about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2023-06-03 20:38:12 +0200
committerGitHub <noreply@github.com>2023-06-03 20:38:12 +0200
commit20cbbbb9774f419f17164c4fbbf9ed51d615f993 (patch)
tree4de211bf16412a8f9bd961fa15fa2ae7f78beb96
parentea8b4ff2a6a8a23756ae76643989bd6844e462de (diff)
parent9f70efb31aa9345e07b547b3d4f63a1e08b53c49 (diff)
downloadrust-20cbbbb9774f419f17164c4fbbf9ed51d615f993.tar.gz
rust-20cbbbb9774f419f17164c4fbbf9ed51d615f993.zip
Rollup merge of #112215 - compiler-errors:check-sized-better, r=cjgillot
only suppress coercion error if type is definitely unsized

we previously suppressed coercion errors when the return type was `dyn Trait` because we expect a far more descriptive `Sized` trait error to be emitted instead, however the code that does this suppression does not consider where-clause predicates since it just looked at the HIR. let's do that instead by creating an obligation and checking if it may hold.

fixes #110683
fixes #112208
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs30
-rw-r--r--tests/ui/typeck/return-dyn-type-mismatch-2.rs11
-rw-r--r--tests/ui/typeck/return-dyn-type-mismatch-2.stderr15
-rw-r--r--tests/ui/typeck/return-dyn-type-mismatch.rs21
-rw-r--r--tests/ui/typeck/return-dyn-type-mismatch.stderr15
5 files changed, 81 insertions, 11 deletions
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 905781ec8f5..ba49e0c4161 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -1595,7 +1595,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                             Some(blk_id),
                         );
                         if !fcx.tcx.features().unsized_locals {
-                            unsized_return = self.is_return_ty_unsized(fcx, blk_id);
+                            unsized_return = self.is_return_ty_definitely_unsized(fcx);
                         }
                         if let Some(expression) = expression
                             && let hir::ExprKind::Loop(loop_blk, ..) = expression.kind {
@@ -1614,8 +1614,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                             None,
                         );
                         if !fcx.tcx.features().unsized_locals {
-                            let id = fcx.tcx.hir().parent_id(id);
-                            unsized_return = self.is_return_ty_unsized(fcx, id);
+                            unsized_return = self.is_return_ty_definitely_unsized(fcx);
                         }
                     }
                     _ => {
@@ -1896,15 +1895,24 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
         err.help("you could instead create a new `enum` with a variant for each returned type");
     }
 
-    fn is_return_ty_unsized<'a>(&self, fcx: &FnCtxt<'a, 'tcx>, blk_id: hir::HirId) -> bool {
-        if let Some((_, fn_decl, _)) = fcx.get_fn_decl(blk_id)
-            && let hir::FnRetTy::Return(ty) = fn_decl.output
-            && let ty = fcx.astconv().ast_ty_to_ty( ty)
-            && let ty::Dynamic(..) = ty.kind()
-        {
-            return true;
+    /// Checks whether the return type is unsized via an obligation, which makes
+    /// sure we consider `dyn Trait: Sized` where clauses, which are trivially
+    /// false but technically valid for typeck.
+    fn is_return_ty_definitely_unsized(&self, fcx: &FnCtxt<'_, 'tcx>) -> bool {
+        if let Some(sig) = fcx.body_fn_sig() {
+            !fcx.predicate_may_hold(&Obligation::new(
+                fcx.tcx,
+                ObligationCause::dummy(),
+                fcx.param_env,
+                ty::TraitRef::new(
+                    fcx.tcx,
+                    fcx.tcx.require_lang_item(hir::LangItem::Sized, None),
+                    [sig.output()],
+                ),
+            ))
+        } else {
+            false
         }
-        false
     }
 
     pub fn complete<'a>(self, fcx: &FnCtxt<'a, 'tcx>) -> Ty<'tcx> {
diff --git a/tests/ui/typeck/return-dyn-type-mismatch-2.rs b/tests/ui/typeck/return-dyn-type-mismatch-2.rs
new file mode 100644
index 00000000000..328f154dcbc
--- /dev/null
+++ b/tests/ui/typeck/return-dyn-type-mismatch-2.rs
@@ -0,0 +1,11 @@
+trait Trait<T> {}
+
+fn foo<T>() -> dyn Trait<T>
+where
+    dyn Trait<T>: Sized, // pesky sized predicate
+{
+    42
+    //~^ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/tests/ui/typeck/return-dyn-type-mismatch-2.stderr b/tests/ui/typeck/return-dyn-type-mismatch-2.stderr
new file mode 100644
index 00000000000..9c368e83834
--- /dev/null
+++ b/tests/ui/typeck/return-dyn-type-mismatch-2.stderr
@@ -0,0 +1,15 @@
+error[E0308]: mismatched types
+  --> $DIR/return-dyn-type-mismatch-2.rs:7:5
+   |
+LL | fn foo<T>() -> dyn Trait<T>
+   |                ------------ expected `(dyn Trait<T> + 'static)` because of return type
+...
+LL |     42
+   |     ^^ expected `dyn Trait`, found integer
+   |
+   = note: expected trait object `(dyn Trait<T> + 'static)`
+                      found type `{integer}`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/typeck/return-dyn-type-mismatch.rs b/tests/ui/typeck/return-dyn-type-mismatch.rs
new file mode 100644
index 00000000000..93718f70f41
--- /dev/null
+++ b/tests/ui/typeck/return-dyn-type-mismatch.rs
@@ -0,0 +1,21 @@
+pub trait TestTrait {
+    type MyType;
+
+    fn func() -> Option<Self>
+    where
+        Self: Sized;
+}
+
+impl<T> dyn TestTrait<MyType = T>
+where
+    Self: Sized, // pesky sized predicate
+{
+    fn other_func() -> dyn TestTrait<MyType = T> {
+        match Self::func() {
+            None => None,
+            //~^ ERROR mismatched types
+        }
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/typeck/return-dyn-type-mismatch.stderr b/tests/ui/typeck/return-dyn-type-mismatch.stderr
new file mode 100644
index 00000000000..9d0a609d87f
--- /dev/null
+++ b/tests/ui/typeck/return-dyn-type-mismatch.stderr
@@ -0,0 +1,15 @@
+error[E0308]: mismatched types
+  --> $DIR/return-dyn-type-mismatch.rs:15:21
+   |
+LL |     fn other_func() -> dyn TestTrait<MyType = T> {
+   |                        ------------------------- expected `(dyn TestTrait<MyType = T> + 'static)` because of return type
+LL |         match Self::func() {
+LL |             None => None,
+   |                     ^^^^ expected `dyn TestTrait`, found `Option<_>`
+   |
+   = note: expected trait object `(dyn TestTrait<MyType = T> + 'static)`
+                      found enum `Option<_>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.