Skip to content

Commit

Permalink
Auto merge of rust-lang#13049 - lowr:fix/bare-dyn-assoc-type, r=Veykril
Browse files Browse the repository at this point in the history
fix: resolve associated types of bare dyn types

Fixes rust-lang#13031

We've been dropping the associated type bindings of trait object types that were written without the `dyn` keyword. This patch reuses the lowering logic for `TypeRef::DynTrait` so the associated type bindings are properly lowered.
  • Loading branch information
bors committed Aug 18, 2022
2 parents 82ff740 + 12abaf8 commit ae57b69
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 35 deletions.
61 changes: 26 additions & 35 deletions crates/hir-ty/src/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,18 +238,7 @@ impl<'a> TyLoweringContext<'a> {
})
.intern(Interner)
}
TypeRef::DynTrait(bounds) => {
let self_ty =
TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
QuantifiedWhereClauses::from_iter(
Interner,
bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)),
)
});
let bounds = crate::make_single_type_binders(bounds);
TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner)
}
TypeRef::DynTrait(bounds) => self.lower_dyn_trait(bounds),
TypeRef::ImplTrait(bounds) => {
match self.impl_trait_mode {
ImplTraitLoweringMode::Opaque => {
Expand Down Expand Up @@ -468,29 +457,10 @@ impl<'a> TyLoweringContext<'a> {
}
}
0 => {
let self_ty = Some(
TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
.intern(Interner),
);
let trait_ref = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
ctx.lower_trait_ref_from_resolved_path(
trait_,
resolved_segment,
self_ty,
)
});
let dyn_ty = DynTy {
bounds: crate::make_single_type_binders(
QuantifiedWhereClauses::from_iter(
Interner,
Some(crate::wrap_empty_binders(WhereClause::Implemented(
trait_ref,
))),
),
),
lifetime: static_lifetime(),
};
TyKind::Dyn(dyn_ty).intern(Interner)
// Trait object type without dyn; this should be handled in upstream. See
// `lower_path()`.
stdx::never!("unexpected fully resolved trait path");
TyKind::Error.intern(Interner)
}
_ => {
// FIXME report error (ambiguous associated type)
Expand Down Expand Up @@ -555,11 +525,20 @@ impl<'a> TyLoweringContext<'a> {
let (ty, res) = self.lower_ty_ext(type_ref);
return self.lower_ty_relative_path(ty, res, path.segments());
}

let (resolution, remaining_index) =
match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path.mod_path()) {
Some(it) => it,
None => return (TyKind::Error.intern(Interner), None),
};

if matches!(resolution, TypeNs::TraitId(_)) && remaining_index.is_none() {
// trait object type without dyn
let bound = TypeBound::Path(path.clone(), TraitBoundModifier::None);
let ty = self.lower_dyn_trait(&[Interned::new(bound)]);
return (ty, None);
}

let (resolved_segment, remaining_segments) = match remaining_index {
None => (
path.segments().last().expect("resolved path has at least one element"),
Expand Down Expand Up @@ -987,6 +966,18 @@ impl<'a> TyLoweringContext<'a> {
})
}

fn lower_dyn_trait(&self, bounds: &[Interned<TypeBound>]) -> Ty {
let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
QuantifiedWhereClauses::from_iter(
Interner,
bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)),
)
});
let bounds = crate::make_single_type_binders(bounds);
TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner)
}

fn lower_impl_trait(
&self,
bounds: &[Interned<TypeBound>],
Expand Down
28 changes: 28 additions & 0 deletions crates/hir-ty/src/tests/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1476,6 +1476,34 @@ fn test(x: Trait, y: &Trait) -> u64 {
165..172 'z.foo()': u64
"#]],
);

check_infer_with_mismatches(
r#"
//- minicore: fn, coerce_unsized
struct S;
impl S {
fn foo(&self) {}
}
fn f(_: &Fn(S)) {}
fn main() {
f(&|number| number.foo());
}
"#,
expect![[r#"
31..35 'self': &S
37..39 '{}': ()
47..48 '_': &dyn Fn(S)
58..60 '{}': ()
71..105 '{ ...()); }': ()
77..78 'f': fn f(&dyn Fn(S))
77..102 'f(&|nu...foo())': ()
79..101 '&|numb....foo()': &|S| -> ()
80..101 '|numbe....foo()': |S| -> ()
81..87 'number': S
89..95 'number': S
89..101 'number.foo()': ()
"#]],
)
}

#[test]
Expand Down

0 comments on commit ae57b69

Please sign in to comment.