Auto merge of #13750 - lowr:fix/rpit-in-projection, r=flodiebold

fix: normalize projection after discarding free `BoundVar`s in RPIT

Fixes #13307

When we lower the return type of a function, it may contain free `BoundVar`s in `OpaqueType`'s substitution, which would cause panic during canonicalization as part of projection normalization. Those `BoundVar`s are irrelevant in this context and will be discarded, and we should defer projection normalization until then.
This commit is contained in:
bors 2022-12-10 11:30:14 +00:00
commit 632f804797
2 changed files with 34 additions and 20 deletions

View File

@ -503,7 +503,7 @@ impl<'a> InferenceContext<'a> {
result: InferenceResult::default(), result: InferenceResult::default(),
table: unify::InferenceTable::new(db, trait_env.clone()), table: unify::InferenceTable::new(db, trait_env.clone()),
trait_env, trait_env,
return_ty: TyKind::Error.intern(Interner), // set in collect_fn_signature return_ty: TyKind::Error.intern(Interner), // set in collect_* calls
resume_yield_tys: None, resume_yield_tys: None,
db, db,
owner, owner,
@ -582,14 +582,17 @@ impl<'a> InferenceContext<'a> {
} else { } else {
&*data.ret_type &*data.ret_type
}; };
let return_ty = self.make_ty_with_mode(return_ty, ImplTraitLoweringMode::Opaque);
self.return_ty = return_ty;
if let Some(rpits) = self.db.return_type_impl_traits(func) { let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver)
.with_impl_trait_mode(ImplTraitLoweringMode::Opaque);
let return_ty = ctx.lower_ty(return_ty);
let return_ty = self.insert_type_vars(return_ty);
let return_ty = if let Some(rpits) = self.db.return_type_impl_traits(func) {
// RPIT opaque types use substitution of their parent function. // RPIT opaque types use substitution of their parent function.
let fn_placeholders = TyBuilder::placeholder_subst(self.db, func); let fn_placeholders = TyBuilder::placeholder_subst(self.db, func);
self.return_ty = fold_tys( fold_tys(
self.return_ty.clone(), return_ty,
|ty, _| { |ty, _| {
let opaque_ty_id = match ty.kind(Interner) { let opaque_ty_id = match ty.kind(Interner) {
TyKind::OpaqueType(opaque_ty_id, _) => *opaque_ty_id, TyKind::OpaqueType(opaque_ty_id, _) => *opaque_ty_id,
@ -610,14 +613,18 @@ impl<'a> InferenceContext<'a> {
let (var_predicate, binders) = predicate let (var_predicate, binders) = predicate
.substitute(Interner, &var_subst) .substitute(Interner, &var_subst)
.into_value_and_skipped_binders(); .into_value_and_skipped_binders();
always!(binders.len(Interner) == 0); // quantified where clauses not yet handled always!(binders.is_empty(Interner)); // quantified where clauses not yet handled
self.push_obligation(var_predicate.cast(Interner)); self.push_obligation(var_predicate.cast(Interner));
} }
var var
}, },
DebruijnIndex::INNERMOST, DebruijnIndex::INNERMOST,
); )
} } else {
return_ty
};
self.return_ty = self.normalize_associated_types_in(return_ty);
} }
fn infer_body(&mut self) { fn infer_body(&mut self) {
@ -652,23 +659,14 @@ impl<'a> InferenceContext<'a> {
self.result.diagnostics.push(diagnostic); self.result.diagnostics.push(diagnostic);
} }
fn make_ty_with_mode( fn make_ty(&mut self, type_ref: &TypeRef) -> Ty {
&mut self,
type_ref: &TypeRef,
impl_trait_mode: ImplTraitLoweringMode,
) -> Ty {
// FIXME use right resolver for block // FIXME use right resolver for block
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver) let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
.with_impl_trait_mode(impl_trait_mode);
let ty = ctx.lower_ty(type_ref); let ty = ctx.lower_ty(type_ref);
let ty = self.insert_type_vars(ty); let ty = self.insert_type_vars(ty);
self.normalize_associated_types_in(ty) self.normalize_associated_types_in(ty)
} }
fn make_ty(&mut self, type_ref: &TypeRef) -> Ty {
self.make_ty_with_mode(type_ref, ImplTraitLoweringMode::Disallowed)
}
fn err_ty(&self) -> Ty { fn err_ty(&self) -> Ty {
self.result.standard_types.unknown.clone() self.result.standard_types.unknown.clone()
} }

View File

@ -1388,6 +1388,22 @@ fn foo<const C: u8, T>() -> (impl FnOnce(&str, T), impl Trait<u8>) {
); );
} }
#[test]
fn return_pos_impl_trait_in_projection() {
// Note that the unused type param `X` is significant; see #13307.
check_no_mismatches(
r#"
//- minicore: sized
trait Future { type Output; }
impl Future for () { type Output = i32; }
type Foo<F> = (<F as Future>::Output, F);
fn foo<X>() -> Foo<impl Future<Output = ()>> {
(0, ())
}
"#,
)
}
#[test] #[test]
fn dyn_trait() { fn dyn_trait() {
check_infer( check_infer(