4950: Use correct substs for super trait assoc types r=matklad a=flodiebold

When referring to an associated type of a super trait, we used the substs of the
subtrait. That led to the #4931 crash if the subtrait had less parameters, but
it could also lead to other incorrectness if just the order was different.

Fixes #4931.

Co-authored-by: Florian Diebold <florian.diebold@freiheit.com>
This commit is contained in:
bors[bot] 2020-06-19 19:47:30 +00:00 committed by GitHub
commit 1d4388f6bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 47 additions and 17 deletions

View File

@ -337,17 +337,17 @@ impl Ty {
TraitRef::from_resolved_path(ctx, trait_, resolved_segment, self_ty); TraitRef::from_resolved_path(ctx, trait_, resolved_segment, self_ty);
let ty = if remaining_segments.len() == 1 { let ty = 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 found = associated_type_by_name_including_super_traits(
ctx.db.upcast(), ctx.db,
trait_ref.trait_, trait_ref.clone(),
&segment.name, &segment.name,
); );
match associated_ty { match found {
Some(associated_ty) => { Some((super_trait_ref, associated_ty)) => {
// FIXME handle type parameters on the segment // FIXME handle type parameters on the segment
Ty::Projection(ProjectionTy { Ty::Projection(ProjectionTy {
associated_ty, associated_ty,
parameters: trait_ref.substs, parameters: super_trait_ref.substs,
}) })
} }
None => { None => {
@ -706,17 +706,17 @@ fn assoc_type_bindings_from_type_bound<'a>(
.flat_map(|segment| segment.args_and_bindings.into_iter()) .flat_map(|segment| segment.args_and_bindings.into_iter())
.flat_map(|args_and_bindings| args_and_bindings.bindings.iter()) .flat_map(|args_and_bindings| args_and_bindings.bindings.iter())
.flat_map(move |binding| { .flat_map(move |binding| {
let associated_ty = associated_type_by_name_including_super_traits( let found = associated_type_by_name_including_super_traits(
ctx.db.upcast(), ctx.db,
trait_ref.trait_, trait_ref.clone(),
&binding.name, &binding.name,
); );
let associated_ty = match associated_ty { let (super_trait_ref, associated_ty) = match found {
None => return SmallVec::<[GenericPredicate; 1]>::new(), None => return SmallVec::<[GenericPredicate; 1]>::new(),
Some(t) => t, Some(t) => t,
}; };
let projection_ty = let projection_ty =
ProjectionTy { associated_ty, parameters: trait_ref.substs.clone() }; ProjectionTy { associated_ty, parameters: super_trait_ref.substs.clone() };
let mut preds = SmallVec::with_capacity( let mut preds = SmallVec::with_capacity(
binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(), binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
); );

View File

@ -665,3 +665,31 @@ impl Foo<i64> {
"### "###
); );
} }
#[test]
fn issue_4931() {
assert_snapshot!(
infer(r#"
trait Div<T> {
type Output;
}
trait CheckedDiv: Div<()> {}
trait PrimInt: CheckedDiv<Output = ()> {
fn pow(self);
}
fn check<T: PrimInt>(i: T) {
i.pow();
}
"#),
@r###"
118..122 'self': Self
149..150 'i': T
155..171 '{ ...w(); }': ()
161..162 'i': T
161..168 'i.pow()': ()
"###
);
}

View File

@ -143,13 +143,14 @@ pub(super) fn find_super_trait_path(
} }
pub(super) fn associated_type_by_name_including_super_traits( pub(super) fn associated_type_by_name_including_super_traits(
db: &dyn DefDatabase, db: &dyn HirDatabase,
trait_: TraitId, trait_ref: TraitRef,
name: &Name, name: &Name,
) -> Option<TypeAliasId> { ) -> Option<(TraitRef, TypeAliasId)> {
all_super_traits(db, trait_) all_super_trait_refs(db, trait_ref).into_iter().find_map(|t| {
.into_iter() let assoc_type = db.trait_data(t.trait_).associated_type_by_name(name)?;
.find_map(|t| db.trait_data(t).associated_type_by_name(name)) Some((t, assoc_type))
})
} }
pub(super) fn variant_data(db: &dyn DefDatabase, var: VariantId) -> Arc<VariantData> { pub(super) fn variant_data(db: &dyn DefDatabase, var: VariantId) -> Arc<VariantData> {
@ -176,6 +177,7 @@ pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics {
Generics { def, params: db.generic_params(def), parent_generics } Generics { def, params: db.generic_params(def), parent_generics }
} }
#[derive(Debug)]
pub(crate) struct Generics { pub(crate) struct Generics {
def: GenericDefId, def: GenericDefId,
pub(crate) params: Arc<GenericParams>, pub(crate) params: Arc<GenericParams>,