Add test cases and address review comments
This commit is contained in:
parent
5d2a935e6c
commit
dc53cfea7e
5 changed files with 156 additions and 19 deletions
|
@ -617,14 +617,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
ref prior_arms,
|
ref prior_arms,
|
||||||
last_ty,
|
last_ty,
|
||||||
scrut_hir_id,
|
scrut_hir_id,
|
||||||
suggest_box,
|
opt_suggest_box_span,
|
||||||
arm_span,
|
arm_span,
|
||||||
..
|
..
|
||||||
}) => match source {
|
}) => match source {
|
||||||
hir::MatchSource::IfLetDesugar { .. } => {
|
hir::MatchSource::IfLetDesugar { .. } => {
|
||||||
let msg = "`if let` arms have incompatible types";
|
let msg = "`if let` arms have incompatible types";
|
||||||
err.span_label(cause.span, msg);
|
err.span_label(cause.span, msg);
|
||||||
if let Some(ret_sp) = suggest_box {
|
if let Some(ret_sp) = opt_suggest_box_span {
|
||||||
self.suggest_boxing_for_return_impl_trait(
|
self.suggest_boxing_for_return_impl_trait(
|
||||||
err,
|
err,
|
||||||
ret_sp,
|
ret_sp,
|
||||||
|
@ -684,7 +684,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if let Some(ret_sp) = suggest_box {
|
if let Some(ret_sp) = opt_suggest_box_span {
|
||||||
// Get return type span and point to it.
|
// Get return type span and point to it.
|
||||||
self.suggest_boxing_for_return_impl_trait(
|
self.suggest_boxing_for_return_impl_trait(
|
||||||
err,
|
err,
|
||||||
|
@ -699,7 +699,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
else_sp,
|
else_sp,
|
||||||
outer,
|
outer,
|
||||||
semicolon,
|
semicolon,
|
||||||
suggest_box,
|
opt_suggest_box_span,
|
||||||
}) => {
|
}) => {
|
||||||
err.span_label(then, "expected because of this");
|
err.span_label(then, "expected because of this");
|
||||||
if let Some(sp) = outer {
|
if let Some(sp) = outer {
|
||||||
|
@ -713,7 +713,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if let Some(ret_sp) = suggest_box {
|
if let Some(ret_sp) = opt_suggest_box_span {
|
||||||
self.suggest_boxing_for_return_impl_trait(
|
self.suggest_boxing_for_return_impl_trait(
|
||||||
err,
|
err,
|
||||||
ret_sp,
|
ret_sp,
|
||||||
|
|
|
@ -350,7 +350,7 @@ pub struct MatchExpressionArmCause<'tcx> {
|
||||||
pub prior_arms: Vec<Span>,
|
pub prior_arms: Vec<Span>,
|
||||||
pub last_ty: Ty<'tcx>,
|
pub last_ty: Ty<'tcx>,
|
||||||
pub scrut_hir_id: hir::HirId,
|
pub scrut_hir_id: hir::HirId,
|
||||||
pub suggest_box: Option<Span>,
|
pub opt_suggest_box_span: Option<Span>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
@ -359,7 +359,7 @@ pub struct IfExpressionCause {
|
||||||
pub else_sp: Span,
|
pub else_sp: Span,
|
||||||
pub outer: Option<Span>,
|
pub outer: Option<Span>,
|
||||||
pub semicolon: Option<Span>,
|
pub semicolon: Option<Span>,
|
||||||
pub suggest_box: Option<Span>,
|
pub opt_suggest_box_span: Option<Span>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
|
||||||
|
|
|
@ -119,13 +119,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
// When we have a `match` as a tail expression in a `fn` with a returned `impl Trait`
|
// When we have a `match` as a tail expression in a `fn` with a returned `impl Trait`
|
||||||
// we check if the different arms would work with boxed trait objects instead and
|
// we check if the different arms would work with boxed trait objects instead and
|
||||||
// provide a structured suggestion in that case.
|
// provide a structured suggestion in that case.
|
||||||
let suggest_box = match (
|
let opt_suggest_box_span = match (
|
||||||
orig_expected,
|
orig_expected,
|
||||||
self.body_id
|
self.ret_coercion_impl_trait.map(|ty| (self.body_id.owner, ty)),
|
||||||
.owner
|
|
||||||
.to_def_id()
|
|
||||||
.as_local()
|
|
||||||
.and_then(|id| self.ret_coercion_impl_trait.map(|ty| (id, ty))),
|
|
||||||
) {
|
) {
|
||||||
(Expectation::ExpectHasType(expected), Some((id, ty)))
|
(Expectation::ExpectHasType(expected), Some((id, ty)))
|
||||||
if self.in_tail_expr && self.can_coerce(arm_ty, expected) =>
|
if self.in_tail_expr && self.can_coerce(arm_ty, expected) =>
|
||||||
|
@ -181,7 +177,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
&arm.body,
|
&arm.body,
|
||||||
then_ty,
|
then_ty,
|
||||||
arm_ty,
|
arm_ty,
|
||||||
suggest_box,
|
opt_suggest_box_span,
|
||||||
);
|
);
|
||||||
coercion.coerce(self, &cause, &arm.body, arm_ty);
|
coercion.coerce(self, &cause, &arm.body, arm_ty);
|
||||||
}
|
}
|
||||||
|
@ -205,7 +201,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
prior_arms: other_arms.clone(),
|
prior_arms: other_arms.clone(),
|
||||||
last_ty: prior_arm_ty.unwrap(),
|
last_ty: prior_arm_ty.unwrap(),
|
||||||
scrut_hir_id: scrut.hir_id,
|
scrut_hir_id: scrut.hir_id,
|
||||||
suggest_box,
|
opt_suggest_box_span,
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
@ -330,7 +326,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
else_expr: &'tcx hir::Expr<'tcx>,
|
else_expr: &'tcx hir::Expr<'tcx>,
|
||||||
then_ty: Ty<'tcx>,
|
then_ty: Ty<'tcx>,
|
||||||
else_ty: Ty<'tcx>,
|
else_ty: Ty<'tcx>,
|
||||||
suggest_box: Option<Span>,
|
opt_suggest_box_span: Option<Span>,
|
||||||
) -> ObligationCause<'tcx> {
|
) -> ObligationCause<'tcx> {
|
||||||
let mut outer_sp = if self.tcx.sess.source_map().is_multiline(span) {
|
let mut outer_sp = if self.tcx.sess.source_map().is_multiline(span) {
|
||||||
// The `if`/`else` isn't in one line in the output, include some context to make it
|
// The `if`/`else` isn't in one line in the output, include some context to make it
|
||||||
|
@ -421,7 +417,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
else_sp: error_sp,
|
else_sp: error_sp,
|
||||||
outer: outer_sp,
|
outer: outer_sp,
|
||||||
semicolon: remove_semicolon,
|
semicolon: remove_semicolon,
|
||||||
suggest_box,
|
opt_suggest_box_span,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,4 +63,39 @@ fn dog() -> impl std::fmt::Display {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn hat() -> dyn std::fmt::Display { //~ ERROR return type cannot have an unboxed trait object
|
||||||
|
match 13 {
|
||||||
|
0 => {
|
||||||
|
return 0i32;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
1u32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pug() -> dyn std::fmt::Display { //~ ERROR return type cannot have an unboxed trait object
|
||||||
|
match 13 {
|
||||||
|
0 => 0i32,
|
||||||
|
1 => 1u32, //~ ERROR `match` arms have incompatible types
|
||||||
|
_ => 2u32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn man() -> dyn std::fmt::Display { //~ ERROR return type cannot have an unboxed trait object
|
||||||
|
if false {
|
||||||
|
0i32
|
||||||
|
} else {
|
||||||
|
1u32 //~ ERROR `if` and `else` have incompatible types
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apt() -> impl std::fmt::Display {
|
||||||
|
if let Some(42) = Some(42) {
|
||||||
|
0i32
|
||||||
|
} else {
|
||||||
|
1u32 //~ ERROR `if` and `else` have incompatible types
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -207,6 +207,112 @@ LL | 0 => Box::new(0i32),
|
||||||
LL | 1 => Box::new(1u32),
|
LL | 1 => Box::new(1u32),
|
||||||
|
|
|
|
||||||
|
|
||||||
error: aborting due to 8 previous errors
|
error[E0308]: `if` and `else` have incompatible types
|
||||||
|
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:97:9
|
||||||
|
|
|
||||||
|
LL | / if let Some(42) = Some(42) {
|
||||||
|
LL | | 0i32
|
||||||
|
| | ---- expected because of this
|
||||||
|
LL | | } else {
|
||||||
|
LL | | 1u32
|
||||||
|
| | ^^^^ expected `i32`, found `u32`
|
||||||
|
LL | | }
|
||||||
|
| |_____- `if` and `else` have incompatible types
|
||||||
|
|
|
||||||
|
help: you could change the return type to be a boxed trait object
|
||||||
|
|
|
||||||
|
LL | fn apt() -> Box<dyn std::fmt::Display> {
|
||||||
|
| ^^^^^^^ ^
|
||||||
|
help: if you change the return type to expect trait objects, box the returned expressions
|
||||||
|
|
|
||||||
|
LL | Box::new(0i32)
|
||||||
|
LL | } else {
|
||||||
|
LL | Box::new(1u32)
|
||||||
|
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0308`.
|
error[E0746]: return type cannot have an unboxed trait object
|
||||||
|
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:66:13
|
||||||
|
|
|
||||||
|
LL | fn hat() -> dyn std::fmt::Display {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||||
|
|
|
||||||
|
= note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
|
||||||
|
= note: if all the returned values were of the same type you could use `impl std::fmt::Display` as the return type
|
||||||
|
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
||||||
|
= note: you can create a new `enum` with a variant for each returned type
|
||||||
|
help: return a boxed trait object instead
|
||||||
|
|
|
||||||
|
LL | fn hat() -> Box<dyn std::fmt::Display> {
|
||||||
|
LL | match 13 {
|
||||||
|
LL | 0 => {
|
||||||
|
LL | return Box::new(0i32);
|
||||||
|
LL | }
|
||||||
|
LL | _ => {
|
||||||
|
...
|
||||||
|
|
||||||
|
error[E0308]: `match` arms have incompatible types
|
||||||
|
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:80:14
|
||||||
|
|
|
||||||
|
LL | / match 13 {
|
||||||
|
LL | | 0 => 0i32,
|
||||||
|
| | ---- this is found to be of type `i32`
|
||||||
|
LL | | 1 => 1u32,
|
||||||
|
| | ^^^^ expected `i32`, found `u32`
|
||||||
|
LL | | _ => 2u32,
|
||||||
|
LL | | }
|
||||||
|
| |_____- `match` arms have incompatible types
|
||||||
|
|
||||||
|
error[E0746]: return type cannot have an unboxed trait object
|
||||||
|
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:77:13
|
||||||
|
|
|
||||||
|
LL | fn pug() -> dyn std::fmt::Display {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||||
|
|
|
||||||
|
= note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
|
||||||
|
= note: if all the returned values were of the same type you could use `impl std::fmt::Display` as the return type
|
||||||
|
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
||||||
|
= note: you can create a new `enum` with a variant for each returned type
|
||||||
|
help: return a boxed trait object instead
|
||||||
|
|
|
||||||
|
LL | fn pug() -> Box<dyn std::fmt::Display> {
|
||||||
|
LL | match 13 {
|
||||||
|
LL | 0 => Box::new(0i32),
|
||||||
|
LL | 1 => Box::new(1u32),
|
||||||
|
LL | _ => Box::new(2u32),
|
||||||
|
|
|
||||||
|
|
||||||
|
error[E0308]: `if` and `else` have incompatible types
|
||||||
|
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:89:9
|
||||||
|
|
|
||||||
|
LL | / if false {
|
||||||
|
LL | | 0i32
|
||||||
|
| | ---- expected because of this
|
||||||
|
LL | | } else {
|
||||||
|
LL | | 1u32
|
||||||
|
| | ^^^^ expected `i32`, found `u32`
|
||||||
|
LL | | }
|
||||||
|
| |_____- `if` and `else` have incompatible types
|
||||||
|
|
||||||
|
error[E0746]: return type cannot have an unboxed trait object
|
||||||
|
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:85:13
|
||||||
|
|
|
||||||
|
LL | fn man() -> dyn std::fmt::Display {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||||
|
|
|
||||||
|
= note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
|
||||||
|
= note: if all the returned values were of the same type you could use `impl std::fmt::Display` as the return type
|
||||||
|
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
||||||
|
= note: you can create a new `enum` with a variant for each returned type
|
||||||
|
help: return a boxed trait object instead
|
||||||
|
|
|
||||||
|
LL | fn man() -> Box<dyn std::fmt::Display> {
|
||||||
|
LL | if false {
|
||||||
|
LL | Box::new(0i32)
|
||||||
|
LL | } else {
|
||||||
|
LL | Box::new(1u32)
|
||||||
|
|
|
||||||
|
|
||||||
|
error: aborting due to 14 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0308, E0746.
|
||||||
|
For more information about an error, try `rustc --explain E0308`.
|
||||||
|
|
Loading…
Add table
Reference in a new issue