Rollup merge of #103008 - aliemjay:opaque-parent-substs, r=oli-obk
replace ReErased with fresh region vars in opaque types See inline comments. Prior art #102943. cc ``@compiler-errors`` ``@oli-obk`` Fixes #100267 Fixes #101940 Fixes #102649 Fixes #102510
This commit is contained in:
commit
059bbf7ea9
4 changed files with 209 additions and 5 deletions
|
@ -732,8 +732,6 @@ fn check_opaque_meets_bounds<'tcx>(
|
||||||
span: Span,
|
span: Span,
|
||||||
origin: &hir::OpaqueTyOrigin,
|
origin: &hir::OpaqueTyOrigin,
|
||||||
) {
|
) {
|
||||||
let hidden_type = tcx.bound_type_of(def_id.to_def_id()).subst(tcx, substs);
|
|
||||||
|
|
||||||
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
||||||
let defining_use_anchor = match *origin {
|
let defining_use_anchor = match *origin {
|
||||||
hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did,
|
hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did,
|
||||||
|
@ -748,14 +746,26 @@ fn check_opaque_meets_bounds<'tcx>(
|
||||||
let ocx = ObligationCtxt::new(&infcx);
|
let ocx = ObligationCtxt::new(&infcx);
|
||||||
let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs);
|
let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs);
|
||||||
|
|
||||||
|
// `ReErased` regions appear in the "parent_substs" of closures/generators.
|
||||||
|
// We're ignoring them here and replacing them with fresh region variables.
|
||||||
|
// See tests in ui/type-alias-impl-trait/closure_{parent_substs,wf_outlives}.rs.
|
||||||
|
//
|
||||||
|
// FIXME: Consider wrapping the hidden type in an existential `Binder` and instantiating it
|
||||||
|
// here rather than using ReErased.
|
||||||
|
let hidden_ty = tcx.bound_type_of(def_id.to_def_id()).subst(tcx, substs);
|
||||||
|
let hidden_ty = tcx.fold_regions(hidden_ty, |re, _dbi| match re.kind() {
|
||||||
|
ty::ReErased => infcx.next_region_var(RegionVariableOrigin::MiscVariable(span)),
|
||||||
|
_ => re,
|
||||||
|
});
|
||||||
|
|
||||||
let misc_cause = traits::ObligationCause::misc(span, hir_id);
|
let misc_cause = traits::ObligationCause::misc(span, hir_id);
|
||||||
|
|
||||||
match infcx.at(&misc_cause, param_env).eq(opaque_ty, hidden_type) {
|
match infcx.at(&misc_cause, param_env).eq(opaque_ty, hidden_ty) {
|
||||||
Ok(infer_ok) => ocx.register_infer_ok_obligations(infer_ok),
|
Ok(infer_ok) => ocx.register_infer_ok_obligations(infer_ok),
|
||||||
Err(ty_err) => {
|
Err(ty_err) => {
|
||||||
tcx.sess.delay_span_bug(
|
tcx.sess.delay_span_bug(
|
||||||
span,
|
span,
|
||||||
&format!("could not unify `{hidden_type}` with revealed type:\n{ty_err}"),
|
&format!("could not unify `{hidden_ty}` with revealed type:\n{ty_err}"),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -764,7 +774,7 @@ fn check_opaque_meets_bounds<'tcx>(
|
||||||
// Defining use functions may have more bounds than the opaque type, which is ok, as long as the
|
// Defining use functions may have more bounds than the opaque type, which is ok, as long as the
|
||||||
// hidden type is well formed even without those bounds.
|
// hidden type is well formed even without those bounds.
|
||||||
let predicate =
|
let predicate =
|
||||||
ty::Binder::dummy(ty::PredicateKind::WellFormed(hidden_type.into())).to_predicate(tcx);
|
ty::Binder::dummy(ty::PredicateKind::WellFormed(hidden_ty.into())).to_predicate(tcx);
|
||||||
ocx.register_obligation(Obligation::new(misc_cause, param_env, predicate));
|
ocx.register_obligation(Obligation::new(misc_cause, param_env, predicate));
|
||||||
|
|
||||||
// Check that all obligations are satisfied by the implementation's
|
// Check that all obligations are satisfied by the implementation's
|
||||||
|
|
65
src/test/ui/type-alias-impl-trait/closure_parent_substs.rs
Normal file
65
src/test/ui/type-alias-impl-trait/closure_parent_substs.rs
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
// When WF checking the hidden type in the ParamEnv of the opaque type,
|
||||||
|
// one complication arises when the hidden type is a closure/generator:
|
||||||
|
// the "parent_substs" of the type may reference lifetime parameters
|
||||||
|
// not present in the opaque type.
|
||||||
|
// These region parameters are not really useful in this check.
|
||||||
|
// So here we ignore them and replace them with fresh region variables.
|
||||||
|
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
// Basic test
|
||||||
|
mod test1 {
|
||||||
|
// Hidden type = Closure['_#0r]
|
||||||
|
type Opaque = impl Sized;
|
||||||
|
|
||||||
|
fn define<'a: 'a>() -> Opaque {
|
||||||
|
|| {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// the region vars cannot both be equal to `'static` or `'empty`
|
||||||
|
mod test2 {
|
||||||
|
trait Trait {}
|
||||||
|
|
||||||
|
// Hidden type = Closure['a, '_#0r, '_#1r]
|
||||||
|
// Constraints = [('_#0r: 'a), ('a: '_#1r)]
|
||||||
|
type Opaque<'a>
|
||||||
|
where
|
||||||
|
&'a (): Trait,
|
||||||
|
= impl Sized + 'a;
|
||||||
|
|
||||||
|
fn define<'a, 'x, 'y>() -> Opaque<'a>
|
||||||
|
where
|
||||||
|
&'a (): Trait,
|
||||||
|
'x: 'a,
|
||||||
|
'a: 'y,
|
||||||
|
{
|
||||||
|
|| {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// the region var cannot be equal to `'a` or `'b`
|
||||||
|
mod test3 {
|
||||||
|
trait Trait {}
|
||||||
|
|
||||||
|
// Hidden type = Closure['a, 'b, '_#0r]
|
||||||
|
// Constraints = [('_#0r: 'a), ('_#0r: 'b)]
|
||||||
|
type Opaque<'a, 'b>
|
||||||
|
where
|
||||||
|
(&'a (), &'b ()): Trait,
|
||||||
|
= impl Sized + 'a + 'b;
|
||||||
|
|
||||||
|
fn define<'a, 'b, 'x>() -> Opaque<'a, 'b>
|
||||||
|
where
|
||||||
|
(&'a (), &'b ()): Trait,
|
||||||
|
'x: 'a,
|
||||||
|
'x: 'b,
|
||||||
|
{
|
||||||
|
|| {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
65
src/test/ui/type-alias-impl-trait/closure_wf_outlives.rs
Normal file
65
src/test/ui/type-alias-impl-trait/closure_wf_outlives.rs
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
// If the hidden type is a closure, we require the "outlives" bounds that appear on the
|
||||||
|
// defining site to also appear on the opaque type.
|
||||||
|
//
|
||||||
|
// It's not clear if this is the desired behavior but at least
|
||||||
|
// it's consistent and has no back-compat risk.
|
||||||
|
|
||||||
|
// check-fail
|
||||||
|
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
// requires `'a: 'b` bound
|
||||||
|
mod test1 {
|
||||||
|
type Opaque<'a, 'b> = impl Sized + 'a + 'b;
|
||||||
|
//~^ ERROR lifetime bound not satisfied
|
||||||
|
|
||||||
|
fn define<'a, 'b>() -> Opaque<'a, 'b>
|
||||||
|
where
|
||||||
|
'a: 'b,
|
||||||
|
{
|
||||||
|
|| {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same as the above but through indirection `'x`
|
||||||
|
mod test2 {
|
||||||
|
type Opaque<'a, 'b> = impl Sized + 'a + 'b;
|
||||||
|
//~^ ERROR cannot infer an appropriate lifetime
|
||||||
|
|
||||||
|
fn define<'a, 'b, 'x>() -> Opaque<'a, 'b>
|
||||||
|
where
|
||||||
|
'a: 'x,
|
||||||
|
'x: 'b,
|
||||||
|
{
|
||||||
|
|| {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fixed version of the above
|
||||||
|
mod test2_fixed {
|
||||||
|
type Opaque<'a: 'b, 'b> = impl Sized + 'a + 'b;
|
||||||
|
|
||||||
|
fn define<'a, 'b, 'x>() -> Opaque<'a, 'b>
|
||||||
|
where
|
||||||
|
'a: 'x,
|
||||||
|
'x: 'b,
|
||||||
|
{
|
||||||
|
|| {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// requires `T: 'static`
|
||||||
|
mod test3 {
|
||||||
|
type Opaque<T> = impl Sized;
|
||||||
|
//~^ ERROR the parameter type `T` may not live long enough
|
||||||
|
|
||||||
|
fn define<T>() -> Opaque<T>
|
||||||
|
where
|
||||||
|
T: 'static,
|
||||||
|
{
|
||||||
|
|| {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
64
src/test/ui/type-alias-impl-trait/closure_wf_outlives.stderr
Normal file
64
src/test/ui/type-alias-impl-trait/closure_wf_outlives.stderr
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
error[E0478]: lifetime bound not satisfied
|
||||||
|
--> $DIR/closure_wf_outlives.rs:14:27
|
||||||
|
|
|
||||||
|
LL | type Opaque<'a, 'b> = impl Sized + 'a + 'b;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: lifetime parameter instantiated with the lifetime `'a` as defined here
|
||||||
|
--> $DIR/closure_wf_outlives.rs:14:17
|
||||||
|
|
|
||||||
|
LL | type Opaque<'a, 'b> = impl Sized + 'a + 'b;
|
||||||
|
| ^^
|
||||||
|
note: but lifetime parameter must outlive the lifetime `'b` as defined here
|
||||||
|
--> $DIR/closure_wf_outlives.rs:14:21
|
||||||
|
|
|
||||||
|
LL | type Opaque<'a, 'b> = impl Sized + 'a + 'b;
|
||||||
|
| ^^
|
||||||
|
|
||||||
|
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
|
||||||
|
--> $DIR/closure_wf_outlives.rs:27:27
|
||||||
|
|
|
||||||
|
LL | type Opaque<'a, 'b> = impl Sized + 'a + 'b;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
|
||||||
|
--> $DIR/closure_wf_outlives.rs:27:17
|
||||||
|
|
|
||||||
|
LL | type Opaque<'a, 'b> = impl Sized + 'a + 'b;
|
||||||
|
| ^^
|
||||||
|
note: ...so that the declared lifetime parameter bounds are satisfied
|
||||||
|
--> $DIR/closure_wf_outlives.rs:27:27
|
||||||
|
|
|
||||||
|
LL | type Opaque<'a, 'b> = impl Sized + 'a + 'b;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
note: but, the lifetime must be valid for the lifetime `'b` as defined here...
|
||||||
|
--> $DIR/closure_wf_outlives.rs:27:21
|
||||||
|
|
|
||||||
|
LL | type Opaque<'a, 'b> = impl Sized + 'a + 'b;
|
||||||
|
| ^^
|
||||||
|
note: ...so that the declared lifetime parameter bounds are satisfied
|
||||||
|
--> $DIR/closure_wf_outlives.rs:27:27
|
||||||
|
|
|
||||||
|
LL | type Opaque<'a, 'b> = impl Sized + 'a + 'b;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0310]: the parameter type `T` may not live long enough
|
||||||
|
--> $DIR/closure_wf_outlives.rs:54:22
|
||||||
|
|
|
||||||
|
LL | type Opaque<T> = impl Sized;
|
||||||
|
| ^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
|
||||||
|
|
|
||||||
|
note: ...that is required by this bound
|
||||||
|
--> $DIR/closure_wf_outlives.rs:59:12
|
||||||
|
|
|
||||||
|
LL | T: 'static,
|
||||||
|
| ^^^^^^^
|
||||||
|
help: consider adding an explicit lifetime bound...
|
||||||
|
|
|
||||||
|
LL | type Opaque<T: 'static> = impl Sized;
|
||||||
|
| +++++++++
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0310, E0478, E0495.
|
||||||
|
For more information about an error, try `rustc --explain E0310`.
|
Loading…
Add table
Add a link
Reference in a new issue