about summary refs log tree commit diff
diff options
context:
space:
mode:
authorOli Scherer <git-spam-no-reply9815368754983@oli-obk.de>2022-02-08 16:47:24 +0000
committerOli Scherer <git-spam-no-reply9815368754983@oli-obk.de>2022-02-08 17:01:33 +0000
commit239f1e716dcb1e145b5df5f9439524c817d123b2 (patch)
tree5fb2961a7c36ccbd8abc38877ddef7b36843bce6
parent775e480722c7aba6ff4ff3ccec8c1f4639ae7889 (diff)
downloadrust-239f1e716dcb1e145b5df5f9439524c817d123b2.tar.gz
rust-239f1e716dcb1e145b5df5f9439524c817d123b2.zip
Fix regression from lazy opaque types
-rw-r--r--compiler/rustc_typeck/src/check/closure.rs13
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs27
-rw-r--r--src/test/ui/impl-trait/hidden-type-is-opaque-2.rs34
-rw-r--r--src/test/ui/impl-trait/hidden-type-is-opaque-2.stderr11
-rw-r--r--src/test/ui/impl-trait/hidden-type-is-opaque.rs32
-rw-r--r--src/test/ui/impl-trait/issues/issue-70877.rs2
-rw-r--r--src/test/ui/impl-trait/issues/issue-70877.stderr17
7 files changed, 126 insertions, 10 deletions
diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs
index d4336563b96..c3deab0938d 100644
--- a/compiler/rustc_typeck/src/check/closure.rs
+++ b/compiler/rustc_typeck/src/check/closure.rs
@@ -259,6 +259,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// The `cause_span` should be the span that caused us to
     /// have this expected signature, or `None` if we can't readily
     /// know that.
+    #[instrument(level = "debug", skip(self, cause_span))]
     fn deduce_sig_from_projection(
         &self,
         cause_span: Option<Span>,
@@ -266,15 +267,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ) -> Option<ExpectedSig<'tcx>> {
         let tcx = self.tcx;
 
-        debug!("deduce_sig_from_projection({:?})", projection);
-
         let trait_def_id = projection.trait_def_id(tcx);
 
         let is_fn = tcx.fn_trait_kind_from_lang_item(trait_def_id).is_some();
         let gen_trait = tcx.require_lang_item(LangItem::Generator, cause_span);
         let is_gen = gen_trait == trait_def_id;
         if !is_fn && !is_gen {
-            debug!("deduce_sig_from_projection: not fn or generator");
+            debug!("not fn or generator");
             return None;
         }
 
@@ -283,7 +282,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // associated item and not yield.
             let return_assoc_item = self.tcx.associated_item_def_ids(gen_trait)[1];
             if return_assoc_item != projection.projection_def_id() {
-                debug!("deduce_sig_from_projection: not return assoc item of generator");
+                debug!("not return assoc item of generator");
                 return None;
             }
         }
@@ -291,7 +290,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let input_tys = if is_fn {
             let arg_param_ty = projection.skip_binder().projection_ty.substs.type_at(1);
             let arg_param_ty = self.resolve_vars_if_possible(arg_param_ty);
-            debug!("deduce_sig_from_projection: arg_param_ty={:?}", arg_param_ty);
+            debug!(?arg_param_ty);
 
             match arg_param_ty.kind() {
                 ty::Tuple(tys) => tys.into_iter().map(|k| k.expect_ty()).collect::<Vec<_>>(),
@@ -306,7 +305,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // Since this is a return parameter type it is safe to unwrap.
         let ret_param_ty = projection.skip_binder().term.ty().unwrap();
         let ret_param_ty = self.resolve_vars_if_possible(ret_param_ty);
-        debug!("deduce_sig_from_projection: ret_param_ty={:?}", ret_param_ty);
+        debug!(?ret_param_ty);
 
         let sig = projection.rebind(self.tcx.mk_fn_sig(
             input_tys.iter(),
@@ -315,7 +314,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             hir::Unsafety::Normal,
             Abi::Rust,
         ));
-        debug!("deduce_sig_from_projection: sig={:?}", sig);
+        debug!(?sig);
 
         Some(ExpectedSig { cause_span, sig })
     }
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index e60893a658b..52db15b69a3 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -730,7 +730,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ) -> Vec<Ty<'tcx>> {
         let formal_ret = self.resolve_vars_with_obligations(formal_ret);
         let ret_ty = match expected_ret.only_has_type(self) {
-            Some(ret) => ret,
+            Some(ret) => {
+                // HACK(oli-obk): This is a backwards compatibility hack. Without it, the inference
+                // variable will get instantiated with the opaque type. The inference variable often
+                // has various helpful obligations registered for it that help closures figure out their
+                // signature. If we infer the inference var to the opaque type, the closure won't be able
+                // to find those obligations anymore, and it can't necessarily find them from the opaque
+                // type itself. We could be more powerful with inference if we *combined* the obligations
+                // so that we got both the obligations from the opaque type and the ones from the inference
+                // variable. That will accept more code than we do right now, so we need to carefully consider
+                // the implications.
+                // Note: this check is pessimistic, as the inference type could be matched with something other
+                // than the opaque type, but then we need a new `TypeRelation` just for this specific case and
+                // can't re-use `sup` below.
+                if formal_ret.has_infer_types() {
+                    for ty in ret.walk() {
+                        if let ty::subst::GenericArgKind::Type(ty) = ty.unpack() {
+                            if let ty::Opaque(def_id, _) = *ty.kind() {
+                                if self.infcx.opaque_type_origin(def_id, DUMMY_SP).is_some() {
+                                    return Vec::new();
+                                }
+                            }
+                        }
+                    }
+                }
+                ret
+            }
             None => return Vec::new(),
         };
         let expect_args = self
diff --git a/src/test/ui/impl-trait/hidden-type-is-opaque-2.rs b/src/test/ui/impl-trait/hidden-type-is-opaque-2.rs
new file mode 100644
index 00000000000..1b65685a6c0
--- /dev/null
+++ b/src/test/ui/impl-trait/hidden-type-is-opaque-2.rs
@@ -0,0 +1,34 @@
+// This doesn't work, because we don't flow information from opaque types
+// into function arguments via the function's generic parameters
+// FIXME(oli-obk): make `expected_inputs_for_expected_output` support this
+
+fn reify_as() -> Thunk<impl FnOnce(Continuation) -> Continuation> {
+    Thunk::new(|mut cont| { //~ ERROR type annotations needed
+        cont.reify_as();
+        cont
+    })
+}
+
+#[must_use]
+struct Thunk<F>(F);
+
+impl<F> Thunk<F> {
+    fn new(f: F) -> Self
+    where
+        F: ContFn,
+    {
+        Thunk(f)
+    }
+}
+
+trait ContFn {}
+
+impl<F: FnOnce(Continuation) -> Continuation> ContFn for F {}
+
+struct Continuation;
+
+impl Continuation {
+    fn reify_as(&mut self) {}
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/hidden-type-is-opaque-2.stderr b/src/test/ui/impl-trait/hidden-type-is-opaque-2.stderr
new file mode 100644
index 00000000000..e538aaeb4c5
--- /dev/null
+++ b/src/test/ui/impl-trait/hidden-type-is-opaque-2.stderr
@@ -0,0 +1,11 @@
+error[E0282]: type annotations needed
+  --> $DIR/hidden-type-is-opaque-2.rs:6:17
+   |
+LL |     Thunk::new(|mut cont| {
+   |                 ^^^^^^^^ consider giving this closure parameter a type
+   |
+   = note: type must be known at this point
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/impl-trait/hidden-type-is-opaque.rs b/src/test/ui/impl-trait/hidden-type-is-opaque.rs
new file mode 100644
index 00000000000..b302ae36ef4
--- /dev/null
+++ b/src/test/ui/impl-trait/hidden-type-is-opaque.rs
@@ -0,0 +1,32 @@
+// check-pass
+
+fn reify_as() -> Thunk<impl ContFn> {
+    Thunk::new(|mut cont| {
+        cont.reify_as();
+        cont
+    })
+}
+
+#[must_use]
+struct Thunk<F>(F);
+
+impl<F> Thunk<F> {
+    fn new(f: F) -> Self
+    where
+        F: FnOnce(Continuation) -> Continuation,
+    {
+        Thunk(f)
+    }
+}
+
+trait ContFn {}
+
+impl<F: FnOnce(Continuation) -> Continuation> ContFn for F {}
+
+struct Continuation;
+
+impl Continuation {
+    fn reify_as(&mut self) {}
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/issues/issue-70877.rs b/src/test/ui/impl-trait/issues/issue-70877.rs
index 8169cfafac7..1a86fa00ed1 100644
--- a/src/test/ui/impl-trait/issues/issue-70877.rs
+++ b/src/test/ui/impl-trait/issues/issue-70877.rs
@@ -13,7 +13,7 @@ impl Iterator for Bar {
     type Item = FooItem;
 
     fn next(&mut self) -> Option<Self::Item> {
-        Some(Box::new(quux))
+        Some(Box::new(quux)) //~ ERROR mismatched types
     }
 }
 
diff --git a/src/test/ui/impl-trait/issues/issue-70877.stderr b/src/test/ui/impl-trait/issues/issue-70877.stderr
index 8813bff3c35..7cbd58bdabf 100644
--- a/src/test/ui/impl-trait/issues/issue-70877.stderr
+++ b/src/test/ui/impl-trait/issues/issue-70877.stderr
@@ -1,3 +1,17 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-70877.rs:16:9
+   |
+LL | type FooRet = impl std::fmt::Debug;
+   |               -------------------- the expected opaque type
+...
+LL |     fn next(&mut self) -> Option<Self::Item> {
+   |                           ------------------ expected `Option<Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> FooRet + 'static)>>` because of return type
+LL |         Some(Box::new(quux))
+   |         ^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Fn`, found fn item
+   |
+   = note: expected enum `Option<Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> FooRet + 'static)>>`
+              found enum `Option<Box<for<'r> fn(&'r (dyn ToString + 'r)) -> FooRet {quux}>>`
+
 error: opaque type's hidden type cannot be another opaque type from the same scope
   --> $DIR/issue-70877.rs:31:12
    |
@@ -15,5 +29,6 @@ note: opaque type being used as hidden type
 LL | type FooRet = impl std::fmt::Debug;
    |               ^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0308`.