fix: resolve associated types of bare dyn types

This commit is contained in:
Ryo Yoshida 2022-08-18 01:30:04 +09:00
parent d6412b5866
commit 12abaf8ddd
No known key found for this signature in database
GPG Key ID: E25698A930586171
2 changed files with 54 additions and 35 deletions

View File

@ -238,18 +238,7 @@ pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) {
})
.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 => {
@ -468,29 +457,10 @@ pub(crate) fn lower_partly_resolved_path(
}
}
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)
@ -555,11 +525,20 @@ pub(crate) fn lower_path(&self, path: &Path) -> (Ty, Option<TypeNs>) {
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"),
@ -987,6 +966,18 @@ fn assoc_type_bindings_from_type_bound(
})
}
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>],

View File

@ -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]