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 @@ pub(crate) fn coerce_inner<'a>( 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 @@ pub(crate) fn coerce_inner<'a>( 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 @@ fn add_impl_trait_explanation<'a>( 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 {} + +fn foo() -> dyn Trait +where + dyn Trait: 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() -> dyn Trait + | ------------ expected `(dyn Trait + 'static)` because of return type +... +LL | 42 + | ^^ expected `dyn Trait`, found integer + | + = note: expected trait object `(dyn Trait + '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 + where + Self: Sized; +} + +impl dyn TestTrait +where + Self: Sized, // pesky sized predicate +{ + fn other_func() -> dyn TestTrait { + 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 { + | ------------------------- expected `(dyn TestTrait + 'static)` because of return type +LL | match Self::func() { +LL | None => None, + | ^^^^ expected `dyn TestTrait`, found `Option<_>` + | + = note: expected trait object `(dyn TestTrait + 'static)` + found enum `Option<_>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`.