about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2022-10-14 00:45:18 +0200
committerGitHub <noreply@github.com>2022-10-14 00:45:18 +0200
commit059bbf7ea945d5c6dc2ca5af5abd3eb5c6677ece (patch)
tree1fed6adec27c7fa5d54a72c2c971542f9eea0bdc
parent9692d98e4f3ed8e6076ad1e741d9ed106f40bc3e (diff)
parentd2d3d9433228adb35cfec0de8f3747879e38751f (diff)
downloadrust-059bbf7ea945d5c6dc2ca5af5abd3eb5c6677ece.tar.gz
rust-059bbf7ea945d5c6dc2ca5af5abd3eb5c6677ece.zip
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
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs20
-rw-r--r--src/test/ui/type-alias-impl-trait/closure_parent_substs.rs65
-rw-r--r--src/test/ui/type-alias-impl-trait/closure_wf_outlives.rs65
-rw-r--r--src/test/ui/type-alias-impl-trait/closure_wf_outlives.stderr64
4 files changed, 209 insertions, 5 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 7cee9779c5f..c3583eeb430 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -732,8 +732,6 @@ fn check_opaque_meets_bounds<'tcx>(
     span: Span,
     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 defining_use_anchor = match *origin {
         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 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);
 
-    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),
         Err(ty_err) => {
             tcx.sess.delay_span_bug(
                 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
     // hidden type is well formed even without those bounds.
     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));
 
     // Check that all obligations are satisfied by the implementation's
diff --git a/src/test/ui/type-alias-impl-trait/closure_parent_substs.rs b/src/test/ui/type-alias-impl-trait/closure_parent_substs.rs
new file mode 100644
index 00000000000..475f4724ff2
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/closure_parent_substs.rs
@@ -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() {}
diff --git a/src/test/ui/type-alias-impl-trait/closure_wf_outlives.rs b/src/test/ui/type-alias-impl-trait/closure_wf_outlives.rs
new file mode 100644
index 00000000000..53974dbb36b
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/closure_wf_outlives.rs
@@ -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() {}
diff --git a/src/test/ui/type-alias-impl-trait/closure_wf_outlives.stderr b/src/test/ui/type-alias-impl-trait/closure_wf_outlives.stderr
new file mode 100644
index 00000000000..ae6462bb62c
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/closure_wf_outlives.stderr
@@ -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`.