about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan DPC <99973273+Dylan-DPC@users.noreply.github.com>2022-08-30 11:26:48 +0530
committerGitHub <noreply@github.com>2022-08-30 11:26:48 +0530
commite63424db1961215f145befa6d362347fefcef9a1 (patch)
treef59210077ab419a3c78d8559552ac5909af3878e
parentc731157395f7a02138d5531041578983a66f6f42 (diff)
parent534426d0f3d12b735b0018bcf268b08a09cc09b8 (diff)
downloadrust-e63424db1961215f145befa6d362347fefcef9a1.tar.gz
rust-e63424db1961215f145befa6d362347fefcef9a1.zip
Rollup merge of #100092 - compiler-errors:issue-100075, r=oli-obk
Fall back when relating two opaques by substs in MIR typeck

This is certainly _one_ way to fix #100075. Not really confident it's the _best_ way to do it, though.

The root cause of this issue is that during MIR type-check, we end up trying to equate an opaque against the same opaque def-id but with different substs. Because of the way that we replace RPITs during (HIR) typeck with an inference variable, we don't end up emitting a type-checking error, so the delayed MIR bug causes an ICE.

See the `src/test/ui/impl-trait/issue-100075-2.rs` test below to make that clear -- in that example, we try to equate `{impl Sized} substs=[T]` and `{impl Sized} substs=[Option<T>]`, which causes an ICE. This new logic will instead cause us to infer `{impl Sized} substs=[Option<T>]` as the hidden type for `{impl Sized} substs=[T]`, which causes a proper error to be emitted later on when we check that an opaque isn't recursive.

I'm open to closing this in favor of something else. Ideally we'd fix this in typeck, but the thing we do to ensure backwards compatibility with weird RPIT cases makes that difficult. Also open to discussing this further.
-rw-r--r--compiler/rustc_infer/src/infer/nll_relate/mod.rs58
-rw-r--r--src/test/ui/impl-trait/issue-100075-2.rs8
-rw-r--r--src/test/ui/impl-trait/issue-100075-2.stderr24
-rw-r--r--src/test/ui/impl-trait/issue-100075.rs21
-rw-r--r--src/test/ui/impl-trait/issue-100075.stderr12
5 files changed, 99 insertions, 24 deletions
diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
index bab4f3e9e36..e7e93116a66 100644
--- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
@@ -396,6 +396,32 @@ where
 
         generalizer.relate(value, value)
     }
+
+    fn relate_opaques(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+        let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) };
+        let mut generalize = |ty, ty_is_expected| {
+            let var = self.infcx.next_ty_var_id_in_universe(
+                TypeVariableOrigin {
+                    kind: TypeVariableOriginKind::MiscVariable,
+                    span: self.delegate.span(),
+                },
+                ty::UniverseIndex::ROOT,
+            );
+            if ty_is_expected {
+                self.relate_ty_var((ty, var))
+            } else {
+                self.relate_ty_var((var, ty))
+            }
+        };
+        let (a, b) = match (a.kind(), b.kind()) {
+            (&ty::Opaque(..), _) => (a, generalize(b, false)?),
+            (_, &ty::Opaque(..)) => (generalize(a, true)?, b),
+            _ => unreachable!(),
+        };
+        self.delegate.register_opaque_type(a, b, true)?;
+        trace!(a = ?a.kind(), b = ?b.kind(), "opaque type instantiated");
+        Ok(a)
+    }
 }
 
 /// When we instantiate an inference variable with a value in
@@ -572,32 +598,16 @@ where
             (&ty::Infer(ty::TyVar(vid)), _) => self.relate_ty_var((vid, b)),
 
             (&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => {
-                self.infcx.super_combine_tys(self, a, b)
+                infcx.commit_if_ok(|_| infcx.super_combine_tys(self, a, b)).or_else(|err| {
+                    self.tcx().sess.delay_span_bug(
+                        self.delegate.span(),
+                        "failure to relate an opaque to itself should result in an error later on",
+                    );
+                    if a_def_id.is_local() { self.relate_opaques(a, b) } else { Err(err) }
+                })
             }
             (&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..)) if did.is_local() => {
-                let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) };
-                let mut generalize = |ty, ty_is_expected| {
-                    let var = infcx.next_ty_var_id_in_universe(
-                        TypeVariableOrigin {
-                            kind: TypeVariableOriginKind::MiscVariable,
-                            span: self.delegate.span(),
-                        },
-                        ty::UniverseIndex::ROOT,
-                    );
-                    if ty_is_expected {
-                        self.relate_ty_var((ty, var))
-                    } else {
-                        self.relate_ty_var((var, ty))
-                    }
-                };
-                let (a, b) = match (a.kind(), b.kind()) {
-                    (&ty::Opaque(..), _) => (a, generalize(b, false)?),
-                    (_, &ty::Opaque(..)) => (generalize(a, true)?, b),
-                    _ => unreachable!(),
-                };
-                self.delegate.register_opaque_type(a, b, true)?;
-                trace!(a = ?a.kind(), b = ?b.kind(), "opaque type instantiated");
-                Ok(a)
+                self.relate_opaques(a, b)
             }
 
             (&ty::Projection(projection_ty), _)
diff --git a/src/test/ui/impl-trait/issue-100075-2.rs b/src/test/ui/impl-trait/issue-100075-2.rs
new file mode 100644
index 00000000000..cf059af1925
--- /dev/null
+++ b/src/test/ui/impl-trait/issue-100075-2.rs
@@ -0,0 +1,8 @@
+fn opaque<T>(t: T) -> impl Sized {
+    //~^ ERROR cannot resolve opaque type
+    //~| WARNING function cannot return without recursing
+    opaque(Some(t))
+}
+
+#[allow(dead_code)]
+fn main() {}
diff --git a/src/test/ui/impl-trait/issue-100075-2.stderr b/src/test/ui/impl-trait/issue-100075-2.stderr
new file mode 100644
index 00000000000..5a1f1a97d04
--- /dev/null
+++ b/src/test/ui/impl-trait/issue-100075-2.stderr
@@ -0,0 +1,24 @@
+warning: function cannot return without recursing
+  --> $DIR/issue-100075-2.rs:1:1
+   |
+LL | fn opaque<T>(t: T) -> impl Sized {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+...
+LL |     opaque(Some(t))
+   |     --------------- recursive call site
+   |
+   = note: `#[warn(unconditional_recursion)]` on by default
+   = help: a `loop` may express intention better if this is on purpose
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/issue-100075-2.rs:1:23
+   |
+LL | fn opaque<T>(t: T) -> impl Sized {
+   |                       ^^^^^^^^^^ recursive opaque type
+...
+LL |     opaque(Some(t))
+   |     --------------- returning here with type `impl Sized`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0720`.
diff --git a/src/test/ui/impl-trait/issue-100075.rs b/src/test/ui/impl-trait/issue-100075.rs
new file mode 100644
index 00000000000..ea30abb4855
--- /dev/null
+++ b/src/test/ui/impl-trait/issue-100075.rs
@@ -0,0 +1,21 @@
+trait Marker {}
+impl<T> Marker for T {}
+
+fn maybe<T>(
+    _t: T,
+) -> Option<
+    //removing the line below makes it compile
+    &'static T,
+> {
+    None
+}
+
+fn _g<T>(t: &'static T) -> &'static impl Marker {
+    //~^ ERROR cannot resolve opaque type
+    if let Some(t) = maybe(t) {
+        return _g(t);
+    }
+    todo!()
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/issue-100075.stderr b/src/test/ui/impl-trait/issue-100075.stderr
new file mode 100644
index 00000000000..267ecfdaed1
--- /dev/null
+++ b/src/test/ui/impl-trait/issue-100075.stderr
@@ -0,0 +1,12 @@
+error[E0720]: cannot resolve opaque type
+  --> $DIR/issue-100075.rs:13:37
+   |
+LL | fn _g<T>(t: &'static T) -> &'static impl Marker {
+   |                                     ^^^^^^^^^^^ recursive opaque type
+...
+LL |         return _g(t);
+   |                ----- returning here with type `&impl Marker`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0720`.