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 @@ fn new(
result: InferenceResult::default(),
table: unify::InferenceTable::new(db, trait_env.clone()),
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,
db,
owner,
@ -582,14 +582,17 @@ fn collect_fn(&mut self, func: FunctionId) {
} else {
&*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.
let fn_placeholders = TyBuilder::placeholder_subst(self.db, func);
self.return_ty = fold_tys(
self.return_ty.clone(),
fold_tys(
return_ty,
|ty, _| {
let opaque_ty_id = match ty.kind(Interner) {
TyKind::OpaqueType(opaque_ty_id, _) => *opaque_ty_id,
@ -610,14 +613,18 @@ fn collect_fn(&mut self, func: FunctionId) {
let (var_predicate, binders) = predicate
.substitute(Interner, &var_subst)
.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));
}
var
},
DebruijnIndex::INNERMOST,
);
}
)
} else {
return_ty
};
self.return_ty = self.normalize_associated_types_in(return_ty);
}
fn infer_body(&mut self) {
@ -652,23 +659,14 @@ fn push_diagnostic(&mut self, diagnostic: InferenceDiagnostic) {
self.result.diagnostics.push(diagnostic);
}
fn make_ty_with_mode(
&mut self,
type_ref: &TypeRef,
impl_trait_mode: ImplTraitLoweringMode,
) -> Ty {
fn make_ty(&mut self, type_ref: &TypeRef) -> Ty {
// FIXME use right resolver for block
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver)
.with_impl_trait_mode(impl_trait_mode);
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
let ty = ctx.lower_ty(type_ref);
let ty = self.insert_type_vars(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 {
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]
fn dyn_trait() {
check_infer(