mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-26 20:09:19 +00:00
Fix crash for super trait cycles
This commit is contained in:
parent
9db34eec20
commit
8fb3cab76c
4 changed files with 39 additions and 20 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1007,7 +1007,6 @@ dependencies = [
|
||||||
"chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git)",
|
"chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git)",
|
||||||
"ena 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ena 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"insta 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"insta 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"once_cell 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"once_cell 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
|
@ -12,7 +12,6 @@ rustc-hash = "1.0"
|
||||||
parking_lot = "0.9.0"
|
parking_lot = "0.9.0"
|
||||||
ena = "0.13"
|
ena = "0.13"
|
||||||
once_cell = "1.0.1"
|
once_cell = "1.0.1"
|
||||||
itertools = "0.8.0"
|
|
||||||
|
|
||||||
ra_syntax = { path = "../ra_syntax" }
|
ra_syntax = { path = "../ra_syntax" }
|
||||||
ra_arena = { path = "../ra_arena" }
|
ra_arena = { path = "../ra_arena" }
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
pub(crate) mod src;
|
pub(crate) mod src;
|
||||||
pub(crate) mod docs;
|
pub(crate) mod docs;
|
||||||
|
|
||||||
use std::iter;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use itertools::Itertools;
|
|
||||||
|
|
||||||
use ra_db::{CrateId, Edition, FileId, SourceRootId};
|
use ra_db::{CrateId, Edition, FileId, SourceRootId};
|
||||||
use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner};
|
use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner};
|
||||||
|
|
||||||
|
@ -849,20 +846,23 @@ impl Trait {
|
||||||
|
|
||||||
/// Returns an iterator over the whole super trait hierarchy (including the
|
/// Returns an iterator over the whole super trait hierarchy (including the
|
||||||
/// trait itself).
|
/// trait itself).
|
||||||
pub fn all_super_traits<'a>(
|
pub fn all_super_traits(self, db: &impl HirDatabase) -> Vec<Trait> {
|
||||||
self,
|
// we need to take care a bit here to avoid infinite loops in case of cycles
|
||||||
db: &'a impl HirDatabase,
|
// (i.e. if we have `trait A: B; trait B: A;`)
|
||||||
) -> impl Iterator<Item = Trait> + 'a {
|
let mut result = vec![self];
|
||||||
self.all_super_traits_inner(db).unique()
|
let mut i = 0;
|
||||||
}
|
while i < result.len() {
|
||||||
|
let t = result[i];
|
||||||
fn all_super_traits_inner<'a>(
|
// yeah this is quadratic, but trait hierarchies should be flat
|
||||||
self,
|
// enough that this doesn't matter
|
||||||
db: &'a impl HirDatabase,
|
for tt in t.direct_super_traits(db) {
|
||||||
) -> impl Iterator<Item = Trait> + 'a {
|
if !result.contains(&tt) {
|
||||||
iter::once(self).chain(self.direct_super_traits(db).into_iter().flat_map(move |t| {
|
result.push(tt);
|
||||||
iter::once(t).chain(Box::new(t.all_super_traits(db)) as Box<dyn Iterator<Item = Trait>>)
|
}
|
||||||
}))
|
}
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn associated_type_by_name(self, db: &impl DefDatabase, name: &Name) -> Option<TypeAlias> {
|
pub fn associated_type_by_name(self, db: &impl DefDatabase, name: &Name) -> Option<TypeAlias> {
|
||||||
|
@ -882,7 +882,7 @@ impl Trait {
|
||||||
db: &impl HirDatabase,
|
db: &impl HirDatabase,
|
||||||
name: &Name,
|
name: &Name,
|
||||||
) -> Option<TypeAlias> {
|
) -> Option<TypeAlias> {
|
||||||
self.all_super_traits(db).find_map(|t| t.associated_type_by_name(db, name))
|
self.all_super_traits(db).into_iter().find_map(|t| t.associated_type_by_name(db, name))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn trait_data(self, db: &impl DefDatabase) -> Arc<TraitData> {
|
pub(crate) fn trait_data(self, db: &impl DefDatabase) -> Arc<TraitData> {
|
||||||
|
|
|
@ -3694,6 +3694,27 @@ fn test<T: Trait1, U: Trait2>(x: T, y: U) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn super_trait_cycle() {
|
||||||
|
// This just needs to not crash
|
||||||
|
assert_snapshot!(
|
||||||
|
infer(r#"
|
||||||
|
trait A: B {}
|
||||||
|
trait B: A {}
|
||||||
|
|
||||||
|
fn test<T: A>(x: T) {
|
||||||
|
x.foo();
|
||||||
|
}
|
||||||
|
"#),
|
||||||
|
@r###"
|
||||||
|
[44; 45) 'x': T
|
||||||
|
[50; 66) '{ ...o(); }': ()
|
||||||
|
[56; 57) 'x': T
|
||||||
|
[56; 63) 'x.foo()': {unknown}
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn super_trait_assoc_type_bounds() {
|
fn super_trait_assoc_type_bounds() {
|
||||||
assert_snapshot!(
|
assert_snapshot!(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue