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