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:
commit
632f804797
@ -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()
|
||||
}
|
||||
|
@ -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(
|
||||
|
Loading…
Reference in New Issue
Block a user