only suppress coercion error if type is definitely unsized

This commit is contained in:
Michael Goulet 2023-06-02 16:37:51 +00:00
parent 789dd0b2a2
commit 9f70efb31a
5 changed files with 81 additions and 11 deletions

View file

@ -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> {

View file

@ -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() {}

View file

@ -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`.

View file

@ -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() {}

View file

@ -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`.