mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-03 07:04:49 +00:00
Rework find_super_trait_path to protect against cycles
This commit is contained in:
parent
c200025794
commit
3e106c77ff
5 changed files with 74 additions and 23 deletions
|
@ -814,13 +814,16 @@ pub trait TypeWalk {
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.fold_binders(&mut |ty, binders| match ty {
|
self.fold_binders(
|
||||||
Ty::Bound(idx) if idx as usize >= binders => {
|
&mut |ty, binders| match ty {
|
||||||
assert!(idx as i32 >= -n);
|
Ty::Bound(idx) if idx as usize >= binders => {
|
||||||
Ty::Bound((idx as i32 + n) as u32)
|
assert!(idx as i32 >= -n);
|
||||||
}
|
Ty::Bound((idx as i32 + n) as u32)
|
||||||
ty => ty,
|
}
|
||||||
}, 0)
|
ty => ty,
|
||||||
|
},
|
||||||
|
0,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -241,7 +241,8 @@ impl Ty {
|
||||||
TypeNs::TraitId(trait_) => {
|
TypeNs::TraitId(trait_) => {
|
||||||
// if this is a bare dyn Trait, we'll directly put the required ^0 for the self type in there
|
// if this is a bare dyn Trait, we'll directly put the required ^0 for the self type in there
|
||||||
let self_ty = if remaining_segments.len() == 0 { Some(Ty::Bound(0)) } else { None };
|
let self_ty = if remaining_segments.len() == 0 { Some(Ty::Bound(0)) } else { None };
|
||||||
let trait_ref = TraitRef::from_resolved_path(ctx, trait_, resolved_segment, self_ty);
|
let trait_ref =
|
||||||
|
TraitRef::from_resolved_path(ctx, trait_, resolved_segment, self_ty);
|
||||||
return if remaining_segments.len() == 1 {
|
return if remaining_segments.len() == 1 {
|
||||||
let segment = remaining_segments.first().unwrap();
|
let segment = remaining_segments.first().unwrap();
|
||||||
let associated_ty = associated_type_by_name_including_super_traits(
|
let associated_ty = associated_type_by_name_including_super_traits(
|
||||||
|
|
|
@ -622,6 +622,44 @@ fn test() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn coerce_unsize_super_trait_cycle() {
|
||||||
|
assert_snapshot!(
|
||||||
|
infer_with_mismatches(r#"
|
||||||
|
#[lang = "unsize"]
|
||||||
|
pub trait Unsize<T> {}
|
||||||
|
#[lang = "coerce_unsized"]
|
||||||
|
pub trait CoerceUnsized<T> {}
|
||||||
|
|
||||||
|
impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {}
|
||||||
|
|
||||||
|
trait A {}
|
||||||
|
trait B: C + A {}
|
||||||
|
trait C: B {}
|
||||||
|
trait D: C
|
||||||
|
|
||||||
|
struct S;
|
||||||
|
impl A for S {}
|
||||||
|
impl B for S {}
|
||||||
|
impl C for S {}
|
||||||
|
impl D for S {}
|
||||||
|
|
||||||
|
fn test() {
|
||||||
|
let obj: &dyn D = &S;
|
||||||
|
let obj: &dyn A = obj;
|
||||||
|
}
|
||||||
|
"#, true),
|
||||||
|
@r###"
|
||||||
|
[292; 348) '{ ...obj; }': ()
|
||||||
|
[302; 305) 'obj': &dyn D
|
||||||
|
[316; 318) '&S': &S
|
||||||
|
[317; 318) 'S': S
|
||||||
|
[328; 331) 'obj': &dyn A
|
||||||
|
[342; 345) 'obj': &dyn D
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[ignore]
|
#[ignore]
|
||||||
#[test]
|
#[test]
|
||||||
fn coerce_unsize_generic() {
|
fn coerce_unsize_generic() {
|
||||||
|
|
|
@ -316,12 +316,10 @@ fn super_trait_object_unsize_impl_datum(
|
||||||
let self_bounds = vec![GenericPredicate::Implemented(self_trait_ref.clone())];
|
let self_bounds = vec![GenericPredicate::Implemented(self_trait_ref.clone())];
|
||||||
|
|
||||||
// we need to go from our trait to the super trait, substituting type parameters
|
// we need to go from our trait to the super trait, substituting type parameters
|
||||||
let mut path = crate::utils::find_super_trait_path(db, data.super_trait, data.trait_);
|
let path = crate::utils::find_super_trait_path(db, data.trait_, data.super_trait);
|
||||||
path.pop(); // the last one is our current trait, we don't need that
|
|
||||||
path.reverse(); // we want to go from trait to super trait
|
|
||||||
|
|
||||||
let mut current_trait_ref = self_trait_ref;
|
let mut current_trait_ref = self_trait_ref;
|
||||||
for t in path {
|
for t in path.into_iter().skip(1) {
|
||||||
let bounds = db.generic_predicates(current_trait_ref.trait_.into());
|
let bounds = db.generic_predicates(current_trait_ref.trait_.into());
|
||||||
let super_trait_ref = bounds
|
let super_trait_ref = bounds
|
||||||
.iter()
|
.iter()
|
||||||
|
|
|
@ -62,25 +62,36 @@ pub(super) fn all_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<Tr
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finds a path from a trait to one of its descendant traits. Returns an empty
|
/// Finds a path from a trait to one of its super traits. Returns an empty
|
||||||
/// vector if there is no path.
|
/// vector if there is no path.
|
||||||
pub(super) fn find_super_trait_path(
|
pub(super) fn find_super_trait_path(
|
||||||
db: &impl DefDatabase,
|
db: &impl DefDatabase,
|
||||||
super_trait: TraitId,
|
|
||||||
trait_: TraitId,
|
trait_: TraitId,
|
||||||
|
super_trait: TraitId,
|
||||||
) -> Vec<TraitId> {
|
) -> Vec<TraitId> {
|
||||||
if trait_ == super_trait {
|
let mut result = Vec::with_capacity(2);
|
||||||
return vec![trait_];
|
result.push(trait_);
|
||||||
}
|
return if go(db, super_trait, &mut result) { result } else { Vec::new() };
|
||||||
|
|
||||||
for tt in direct_super_traits(db, trait_) {
|
fn go(db: &impl DefDatabase, super_trait: TraitId, path: &mut Vec<TraitId>) -> bool {
|
||||||
let mut path = find_super_trait_path(db, super_trait, tt);
|
let trait_ = *path.last().unwrap();
|
||||||
if !path.is_empty() {
|
if trait_ == super_trait {
|
||||||
path.push(trait_);
|
return true;
|
||||||
return path;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for tt in direct_super_traits(db, trait_) {
|
||||||
|
if path.contains(&tt) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
path.push(tt);
|
||||||
|
if go(db, super_trait, path) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
path.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
}
|
}
|
||||||
Vec::new()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn associated_type_by_name_including_super_traits(
|
pub(super) fn associated_type_by_name_including_super_traits(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue