Auto merge of #75608 - estebank:suggest-boxed-match-exprs, r=lcnr,varkor
More structured suggestions for boxed trait objects instead of impl Trait on non-coerceable tail expressions When encountering a `match` or `if` as a tail expression where the different arms do not have the same type *and* the return type of that `fn` is an `impl Trait`, check whether those arms can implement `Trait` and if so, suggest using boxed trait objects. Use structured suggestion for `impl T` to `Box<dyn T>`. Fix https://github.com/rust-lang/rust/issues/69107
This commit is contained in:
commit
41dc3942eb
@ -70,7 +70,7 @@ use rustc_middle::ty::{
|
|||||||
subst::{Subst, SubstsRef},
|
subst::{Subst, SubstsRef},
|
||||||
Region, Ty, TyCtxt, TypeFoldable,
|
Region, Ty, TyCtxt, TypeFoldable,
|
||||||
};
|
};
|
||||||
use rustc_span::{DesugaringKind, Pos, Span};
|
use rustc_span::{BytePos, DesugaringKind, Pos, Span};
|
||||||
use rustc_target::spec::abi;
|
use rustc_target::spec::abi;
|
||||||
use std::{cmp, fmt};
|
use std::{cmp, fmt};
|
||||||
|
|
||||||
@ -617,11 +617,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
ref prior_arms,
|
ref prior_arms,
|
||||||
last_ty,
|
last_ty,
|
||||||
scrut_hir_id,
|
scrut_hir_id,
|
||||||
|
opt_suggest_box_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) = opt_suggest_box_span {
|
||||||
|
self.suggest_boxing_for_return_impl_trait(
|
||||||
|
err,
|
||||||
|
ret_sp,
|
||||||
|
prior_arms.iter().chain(std::iter::once(&arm_span)).map(|s| *s),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
hir::MatchSource::TryDesugar => {
|
hir::MatchSource::TryDesugar => {
|
||||||
if let Some(ty::error::ExpectedFound { expected, .. }) = exp_found {
|
if let Some(ty::error::ExpectedFound { expected, .. }) = exp_found {
|
||||||
@ -675,9 +684,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if let Some(ret_sp) = opt_suggest_box_span {
|
||||||
|
// Get return type span and point to it.
|
||||||
|
self.suggest_boxing_for_return_impl_trait(
|
||||||
|
err,
|
||||||
|
ret_sp,
|
||||||
|
prior_arms.iter().chain(std::iter::once(&arm_span)).map(|s| *s),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ObligationCauseCode::IfExpression(box IfExpressionCause { then, outer, semicolon }) => {
|
ObligationCauseCode::IfExpression(box IfExpressionCause {
|
||||||
|
then,
|
||||||
|
else_sp,
|
||||||
|
outer,
|
||||||
|
semicolon,
|
||||||
|
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 {
|
||||||
err.span_label(sp, "`if` and `else` have incompatible types");
|
err.span_label(sp, "`if` and `else` have incompatible types");
|
||||||
@ -690,11 +713,48 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if let Some(ret_sp) = opt_suggest_box_span {
|
||||||
|
self.suggest_boxing_for_return_impl_trait(
|
||||||
|
err,
|
||||||
|
ret_sp,
|
||||||
|
vec![then, else_sp].into_iter(),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn suggest_boxing_for_return_impl_trait(
|
||||||
|
&self,
|
||||||
|
err: &mut DiagnosticBuilder<'tcx>,
|
||||||
|
return_sp: Span,
|
||||||
|
arm_spans: impl Iterator<Item = Span>,
|
||||||
|
) {
|
||||||
|
err.multipart_suggestion(
|
||||||
|
"you could change the return type to be a boxed trait object",
|
||||||
|
vec![
|
||||||
|
(return_sp.with_hi(return_sp.lo() + BytePos(4)), "Box<dyn".to_string()),
|
||||||
|
(return_sp.shrink_to_hi(), ">".to_string()),
|
||||||
|
],
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
let sugg = arm_spans
|
||||||
|
.flat_map(|sp| {
|
||||||
|
vec![
|
||||||
|
(sp.shrink_to_lo(), "Box::new(".to_string()),
|
||||||
|
(sp.shrink_to_hi(), ")".to_string()),
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
err.multipart_suggestion(
|
||||||
|
"if you change the return type to expect trait objects, box the returned expressions",
|
||||||
|
sugg,
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// Given that `other_ty` is the same as a type argument for `name` in `sub`, populate `value`
|
/// Given that `other_ty` is the same as a type argument for `name` in `sub`, populate `value`
|
||||||
/// highlighting `name` and every type argument that isn't at `pos` (which is `other_ty`), and
|
/// highlighting `name` and every type argument that isn't at `pos` (which is `other_ty`), and
|
||||||
/// populate `other_value` with `other_ty`.
|
/// populate `other_value` with `other_ty`.
|
||||||
|
@ -348,13 +348,16 @@ 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 opt_suggest_box_span: Option<Span>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct IfExpressionCause {
|
pub struct IfExpressionCause {
|
||||||
pub then: Span,
|
pub then: Span,
|
||||||
|
pub else_sp: Span,
|
||||||
pub outer: Option<Span>,
|
pub outer: Option<Span>,
|
||||||
pub semicolon: Option<Span>,
|
pub semicolon: Option<Span>,
|
||||||
|
pub opt_suggest_box_span: Option<Span>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
use crate::check::coercion::CoerceMany;
|
use crate::check::coercion::CoerceMany;
|
||||||
use crate::check::{Diverges, Expectation, FnCtxt, Needs};
|
use crate::check::{Diverges, Expectation, FnCtxt, Needs};
|
||||||
use rustc_hir as hir;
|
use rustc_hir::{self as hir, ExprKind};
|
||||||
use rustc_hir::ExprKind;
|
|
||||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
use rustc_middle::ty::Ty;
|
use rustc_infer::traits::Obligation;
|
||||||
|
use rustc_middle::ty::{self, ToPredicate, Ty};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_trait_selection::traits::ObligationCauseCode;
|
use rustc_trait_selection::opaque_types::InferCtxtExt as _;
|
||||||
use rustc_trait_selection::traits::{IfExpressionCause, MatchExpressionArmCause, ObligationCause};
|
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
||||||
|
use rustc_trait_selection::traits::{
|
||||||
|
IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
|
||||||
|
};
|
||||||
|
|
||||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
pub fn check_match(
|
pub fn check_match(
|
||||||
@ -14,7 +17,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
expr: &'tcx hir::Expr<'tcx>,
|
expr: &'tcx hir::Expr<'tcx>,
|
||||||
scrut: &'tcx hir::Expr<'tcx>,
|
scrut: &'tcx hir::Expr<'tcx>,
|
||||||
arms: &'tcx [hir::Arm<'tcx>],
|
arms: &'tcx [hir::Arm<'tcx>],
|
||||||
expected: Expectation<'tcx>,
|
orig_expected: Expectation<'tcx>,
|
||||||
match_src: hir::MatchSource,
|
match_src: hir::MatchSource,
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
@ -22,7 +25,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
use hir::MatchSource::*;
|
use hir::MatchSource::*;
|
||||||
let (source_if, if_no_else, force_scrutinee_bool) = match match_src {
|
let (source_if, if_no_else, force_scrutinee_bool) = match match_src {
|
||||||
IfDesugar { contains_else_clause } => (true, !contains_else_clause, true),
|
IfDesugar { contains_else_clause } => (true, !contains_else_clause, true),
|
||||||
IfLetDesugar { contains_else_clause } => (true, !contains_else_clause, false),
|
IfLetDesugar { contains_else_clause, .. } => (true, !contains_else_clause, false),
|
||||||
WhileDesugar => (false, false, true),
|
WhileDesugar => (false, false, true),
|
||||||
_ => (false, false, false),
|
_ => (false, false, false),
|
||||||
};
|
};
|
||||||
@ -69,7 +72,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// type in that case)
|
// type in that case)
|
||||||
let mut all_arms_diverge = Diverges::WarnedAlways;
|
let mut all_arms_diverge = Diverges::WarnedAlways;
|
||||||
|
|
||||||
let expected = expected.adjust_for_branches(self);
|
let expected = orig_expected.adjust_for_branches(self);
|
||||||
|
|
||||||
let mut coercion = {
|
let mut coercion = {
|
||||||
let coerce_first = match expected {
|
let coerce_first = match expected {
|
||||||
@ -112,6 +115,60 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
self.check_expr_with_expectation(&arm.body, expected)
|
self.check_expr_with_expectation(&arm.body, expected)
|
||||||
};
|
};
|
||||||
all_arms_diverge &= self.diverges.get();
|
all_arms_diverge &= self.diverges.get();
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// provide a structured suggestion in that case.
|
||||||
|
let opt_suggest_box_span = match (
|
||||||
|
orig_expected,
|
||||||
|
self.ret_coercion_impl_trait.map(|ty| (self.body_id.owner, ty)),
|
||||||
|
) {
|
||||||
|
(Expectation::ExpectHasType(expected), Some((id, ty)))
|
||||||
|
if self.in_tail_expr && self.can_coerce(arm_ty, expected) =>
|
||||||
|
{
|
||||||
|
let impl_trait_ret_ty = self.infcx.instantiate_opaque_types(
|
||||||
|
id,
|
||||||
|
self.body_id,
|
||||||
|
self.param_env,
|
||||||
|
&ty,
|
||||||
|
arm.body.span,
|
||||||
|
);
|
||||||
|
let mut suggest_box = !impl_trait_ret_ty.obligations.is_empty();
|
||||||
|
for o in impl_trait_ret_ty.obligations {
|
||||||
|
match o.predicate.skip_binders_unchecked() {
|
||||||
|
ty::PredicateAtom::Trait(t, constness) => {
|
||||||
|
let pred = ty::PredicateAtom::Trait(
|
||||||
|
ty::TraitPredicate {
|
||||||
|
trait_ref: ty::TraitRef {
|
||||||
|
def_id: t.def_id(),
|
||||||
|
substs: self.infcx.tcx.mk_substs_trait(arm_ty, &[]),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
constness,
|
||||||
|
);
|
||||||
|
let obl = Obligation::new(
|
||||||
|
o.cause.clone(),
|
||||||
|
self.param_env,
|
||||||
|
pred.to_predicate(self.infcx.tcx),
|
||||||
|
);
|
||||||
|
suggest_box &= self.infcx.predicate_must_hold_modulo_regions(&obl);
|
||||||
|
if !suggest_box {
|
||||||
|
// We've encountered some obligation that didn't hold, so the
|
||||||
|
// return expression can't just be boxed. We don't need to
|
||||||
|
// evaluate the rest of the obligations.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If all the obligations hold (or there are no obligations) the tail expression
|
||||||
|
// we can suggest to return a boxed trait object instead of an opaque type.
|
||||||
|
if suggest_box { self.ret_type_span.clone() } else { None }
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
if source_if {
|
if source_if {
|
||||||
let then_expr = &arms[0].body;
|
let then_expr = &arms[0].body;
|
||||||
match (i, if_no_else) {
|
match (i, if_no_else) {
|
||||||
@ -119,7 +176,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
(_, true) => {} // Handled above to avoid duplicated type errors (#60254).
|
(_, true) => {} // Handled above to avoid duplicated type errors (#60254).
|
||||||
(_, _) => {
|
(_, _) => {
|
||||||
let then_ty = prior_arm_ty.unwrap();
|
let then_ty = prior_arm_ty.unwrap();
|
||||||
let cause = self.if_cause(expr.span, then_expr, &arm.body, then_ty, arm_ty);
|
let cause = self.if_cause(
|
||||||
|
expr.span,
|
||||||
|
then_expr,
|
||||||
|
&arm.body,
|
||||||
|
then_ty,
|
||||||
|
arm_ty,
|
||||||
|
opt_suggest_box_span,
|
||||||
|
);
|
||||||
coercion.coerce(self, &cause, &arm.body, arm_ty);
|
coercion.coerce(self, &cause, &arm.body, arm_ty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -142,6 +206,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,
|
||||||
|
opt_suggest_box_span,
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
@ -266,6 +331,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>,
|
||||||
|
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
|
||||||
@ -353,8 +419,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
error_sp,
|
error_sp,
|
||||||
ObligationCauseCode::IfExpression(box IfExpressionCause {
|
ObligationCauseCode::IfExpression(box IfExpressionCause {
|
||||||
then: then_sp,
|
then: then_sp,
|
||||||
|
else_sp: error_sp,
|
||||||
outer: outer_sp,
|
outer: outer_sp,
|
||||||
semicolon: remove_semicolon,
|
semicolon: remove_semicolon,
|
||||||
|
opt_suggest_box_span,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
|
|
||||||
use crate::astconv::AstConv;
|
use crate::astconv::AstConv;
|
||||||
use crate::check::FnCtxt;
|
use crate::check::FnCtxt;
|
||||||
use rustc_errors::{struct_span_err, DiagnosticBuilder};
|
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
use rustc_infer::infer::{Coercion, InferOk, InferResult};
|
use rustc_infer::infer::{Coercion, InferOk, InferResult};
|
||||||
@ -51,7 +51,7 @@ use rustc_middle::ty::subst::SubstsRef;
|
|||||||
use rustc_middle::ty::{self, Ty, TypeAndMut};
|
use rustc_middle::ty::{self, Ty, TypeAndMut};
|
||||||
use rustc_session::parse::feature_err;
|
use rustc_session::parse::feature_err;
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_span::{self, Span};
|
use rustc_span::{self, BytePos, Span};
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
|
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
|
||||||
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
|
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
|
||||||
@ -1459,7 +1459,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let (Some(sp), Some(fn_output)) = (fcx.ret_coercion_span.borrow().as_ref(), fn_output) {
|
if let (Some(sp), Some(fn_output)) = (fcx.ret_coercion_span.borrow().as_ref(), fn_output) {
|
||||||
self.add_impl_trait_explanation(&mut err, fcx, expected, *sp, fn_output);
|
self.add_impl_trait_explanation(&mut err, cause, fcx, expected, *sp, fn_output);
|
||||||
}
|
}
|
||||||
err
|
err
|
||||||
}
|
}
|
||||||
@ -1467,6 +1467,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||||||
fn add_impl_trait_explanation<'a>(
|
fn add_impl_trait_explanation<'a>(
|
||||||
&self,
|
&self,
|
||||||
err: &mut DiagnosticBuilder<'a>,
|
err: &mut DiagnosticBuilder<'a>,
|
||||||
|
cause: &ObligationCause<'tcx>,
|
||||||
fcx: &FnCtxt<'a, 'tcx>,
|
fcx: &FnCtxt<'a, 'tcx>,
|
||||||
expected: Ty<'tcx>,
|
expected: Ty<'tcx>,
|
||||||
sp: Span,
|
sp: Span,
|
||||||
@ -1523,10 +1524,30 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||||||
};
|
};
|
||||||
if has_impl {
|
if has_impl {
|
||||||
if is_object_safe {
|
if is_object_safe {
|
||||||
err.help(&format!(
|
err.multipart_suggestion(
|
||||||
"you can instead return a boxed trait object using `Box<dyn {}>`",
|
"you could change the return type to be a boxed trait object",
|
||||||
&snippet[5..]
|
vec![
|
||||||
));
|
(return_sp.with_hi(return_sp.lo() + BytePos(4)), "Box<dyn".to_string()),
|
||||||
|
(return_sp.shrink_to_hi(), ">".to_string()),
|
||||||
|
],
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
let sugg = vec![sp, cause.span]
|
||||||
|
.into_iter()
|
||||||
|
.flat_map(|sp| {
|
||||||
|
vec![
|
||||||
|
(sp.shrink_to_lo(), "Box::new(".to_string()),
|
||||||
|
(sp.shrink_to_hi(), ")".to_string()),
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
err.multipart_suggestion(
|
||||||
|
"if you change the return type to expect trait objects, box the returned \
|
||||||
|
expressions",
|
||||||
|
sugg,
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
err.help(&format!(
|
err.help(&format!(
|
||||||
"if the trait `{}` were object safe, you could return a boxed trait object",
|
"if the trait `{}` were object safe, you could return a boxed trait object",
|
||||||
@ -1535,7 +1556,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||||||
}
|
}
|
||||||
err.note(trait_obj_msg);
|
err.note(trait_obj_msg);
|
||||||
}
|
}
|
||||||
err.help("alternatively, create a new `enum` with a variant for each returned type");
|
err.help("you could instead create a new `enum` with a variant for each returned type");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_return_ty_unsized(&self, fcx: &FnCtxt<'a, 'tcx>, blk_id: hir::HirId) -> bool {
|
fn is_return_ty_unsized(&self, fcx: &FnCtxt<'a, 'tcx>, blk_id: hir::HirId) -> bool {
|
||||||
|
@ -570,6 +570,14 @@ pub struct FnCtxt<'a, 'tcx> {
|
|||||||
/// any).
|
/// any).
|
||||||
ret_coercion: Option<RefCell<DynamicCoerceMany<'tcx>>>,
|
ret_coercion: Option<RefCell<DynamicCoerceMany<'tcx>>>,
|
||||||
|
|
||||||
|
ret_coercion_impl_trait: Option<Ty<'tcx>>,
|
||||||
|
|
||||||
|
ret_type_span: Option<Span>,
|
||||||
|
|
||||||
|
/// Used exclusively to reduce cost of advanced evaluation used for
|
||||||
|
/// more helpful diagnostics.
|
||||||
|
in_tail_expr: bool,
|
||||||
|
|
||||||
/// First span of a return site that we find. Used in error messages.
|
/// First span of a return site that we find. Used in error messages.
|
||||||
ret_coercion_span: RefCell<Option<Span>>,
|
ret_coercion_span: RefCell<Option<Span>>,
|
||||||
|
|
||||||
@ -1302,10 +1310,15 @@ fn check_fn<'a, 'tcx>(
|
|||||||
let hir = tcx.hir();
|
let hir = tcx.hir();
|
||||||
|
|
||||||
let declared_ret_ty = fn_sig.output();
|
let declared_ret_ty = fn_sig.output();
|
||||||
|
|
||||||
let revealed_ret_ty =
|
let revealed_ret_ty =
|
||||||
fcx.instantiate_opaque_types_from_value(fn_id, &declared_ret_ty, decl.output.span());
|
fcx.instantiate_opaque_types_from_value(fn_id, &declared_ret_ty, decl.output.span());
|
||||||
debug!("check_fn: declared_ret_ty: {}, revealed_ret_ty: {}", declared_ret_ty, revealed_ret_ty);
|
debug!("check_fn: declared_ret_ty: {}, revealed_ret_ty: {}", declared_ret_ty, revealed_ret_ty);
|
||||||
fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty)));
|
fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty)));
|
||||||
|
fcx.ret_type_span = Some(decl.output.span());
|
||||||
|
if let ty::Opaque(..) = declared_ret_ty.kind() {
|
||||||
|
fcx.ret_coercion_impl_trait = Some(declared_ret_ty);
|
||||||
|
}
|
||||||
fn_sig = tcx.mk_fn_sig(
|
fn_sig = tcx.mk_fn_sig(
|
||||||
fn_sig.inputs().iter().cloned(),
|
fn_sig.inputs().iter().cloned(),
|
||||||
revealed_ret_ty,
|
revealed_ret_ty,
|
||||||
@ -1366,6 +1379,7 @@ fn check_fn<'a, 'tcx>(
|
|||||||
|
|
||||||
inherited.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);
|
inherited.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);
|
||||||
|
|
||||||
|
fcx.in_tail_expr = true;
|
||||||
if let ty::Dynamic(..) = declared_ret_ty.kind() {
|
if let ty::Dynamic(..) = declared_ret_ty.kind() {
|
||||||
// FIXME: We need to verify that the return type is `Sized` after the return expression has
|
// FIXME: We need to verify that the return type is `Sized` after the return expression has
|
||||||
// been evaluated so that we have types available for all the nodes being returned, but that
|
// been evaluated so that we have types available for all the nodes being returned, but that
|
||||||
@ -1385,6 +1399,7 @@ fn check_fn<'a, 'tcx>(
|
|||||||
fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
|
fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
|
||||||
fcx.check_return_expr(&body.value);
|
fcx.check_return_expr(&body.value);
|
||||||
}
|
}
|
||||||
|
fcx.in_tail_expr = false;
|
||||||
|
|
||||||
// We insert the deferred_generator_interiors entry after visiting the body.
|
// We insert the deferred_generator_interiors entry after visiting the body.
|
||||||
// This ensures that all nested generators appear before the entry of this generator.
|
// This ensures that all nested generators appear before the entry of this generator.
|
||||||
@ -3084,6 +3099,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
param_env,
|
param_env,
|
||||||
err_count_on_creation: inh.tcx.sess.err_count(),
|
err_count_on_creation: inh.tcx.sess.err_count(),
|
||||||
ret_coercion: None,
|
ret_coercion: None,
|
||||||
|
ret_coercion_impl_trait: None,
|
||||||
|
ret_type_span: None,
|
||||||
|
in_tail_expr: false,
|
||||||
ret_coercion_span: RefCell::new(None),
|
ret_coercion_span: RefCell::new(None),
|
||||||
resume_yield_tys: None,
|
resume_yield_tys: None,
|
||||||
ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)),
|
ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)),
|
||||||
|
@ -23,7 +23,7 @@ LL | 0_u32
|
|||||||
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
||||||
= help: if the trait `Foo` were object safe, you could return a boxed trait object
|
= help: if the trait `Foo` were object safe, you could return a boxed trait object
|
||||||
= 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: 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>
|
||||||
= help: alternatively, create a new `enum` with a variant for each returned type
|
= help: you could instead create a new `enum` with a variant for each returned type
|
||||||
|
|
||||||
error[E0277]: cannot add `impl Foo` to `u32`
|
error[E0277]: cannot add `impl Foo` to `u32`
|
||||||
--> $DIR/equality.rs:24:11
|
--> $DIR/equality.rs:24:11
|
||||||
|
@ -14,7 +14,7 @@ LL | B
|
|||||||
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
||||||
= help: if the trait `NotObjectSafe` were object safe, you could return a boxed trait object
|
= help: if the trait `NotObjectSafe` were object safe, you could return a boxed trait object
|
||||||
= 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: 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>
|
||||||
= help: alternatively, create a new `enum` with a variant for each returned type
|
= help: you could instead create a new `enum` with a variant for each returned type
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/object-unsafe-trait-in-return-position-impl-trait.rs:43:5
|
--> $DIR/object-unsafe-trait-in-return-position-impl-trait.rs:43:5
|
||||||
@ -30,9 +30,18 @@ LL | B
|
|||||||
|
|
|
|
||||||
= note: to return `impl Trait`, all returned values must be of the same type
|
= note: to return `impl Trait`, all returned values must be of the same type
|
||||||
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
||||||
= help: you can instead return a boxed trait object using `Box<dyn ObjectSafe>`
|
|
||||||
= 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: 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>
|
||||||
= help: alternatively, create a new `enum` with a variant for each returned type
|
= help: you could instead create a new `enum` with a variant for each returned type
|
||||||
|
help: you could change the return type to be a boxed trait object
|
||||||
|
|
|
||||||
|
LL | fn cat() -> Box<dyn ObjectSafe> {
|
||||||
|
| ^^^^^^^ ^
|
||||||
|
help: if you change the return type to expect trait objects, box the returned expressions
|
||||||
|
|
|
||||||
|
LL | return Box::new(A);
|
||||||
|
LL | }
|
||||||
|
LL | Box::new(B)
|
||||||
|
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
@ -2,16 +2,14 @@ fn foo() -> impl std::fmt::Display {
|
|||||||
if false {
|
if false {
|
||||||
return 0i32;
|
return 0i32;
|
||||||
}
|
}
|
||||||
1u32
|
1u32 //~ ERROR mismatched types
|
||||||
//~^ ERROR mismatched types
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bar() -> impl std::fmt::Display {
|
fn bar() -> impl std::fmt::Display {
|
||||||
if false {
|
if false {
|
||||||
return 0i32;
|
return 0i32;
|
||||||
} else {
|
} else {
|
||||||
return 1u32;
|
return 1u32; //~ ERROR mismatched types
|
||||||
//~^ ERROR mismatched types
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -19,8 +17,7 @@ fn baz() -> impl std::fmt::Display {
|
|||||||
if false {
|
if false {
|
||||||
return 0i32;
|
return 0i32;
|
||||||
} else {
|
} else {
|
||||||
1u32
|
1u32 //~ ERROR mismatched types
|
||||||
//~^ ERROR mismatched types
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,22 +25,19 @@ fn qux() -> impl std::fmt::Display {
|
|||||||
if false {
|
if false {
|
||||||
0i32
|
0i32
|
||||||
} else {
|
} else {
|
||||||
1u32
|
1u32 //~ ERROR `if` and `else` have incompatible types
|
||||||
//~^ ERROR `if` and `else` have incompatible types
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bat() -> impl std::fmt::Display {
|
fn bat() -> impl std::fmt::Display {
|
||||||
match 13 {
|
match 13 {
|
||||||
0 => return 0i32,
|
0 => return 0i32,
|
||||||
_ => 1u32,
|
_ => 1u32, //~ ERROR mismatched types
|
||||||
//~^ ERROR mismatched types
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn can() -> impl std::fmt::Display {
|
fn can() -> impl std::fmt::Display {
|
||||||
match 13 {
|
match 13 { //~ ERROR mismatched types
|
||||||
//~^ ERROR mismatched types
|
|
||||||
0 => return 0i32,
|
0 => return 0i32,
|
||||||
1 => 1u32,
|
1 => 1u32,
|
||||||
_ => 2u32,
|
_ => 2u32,
|
||||||
@ -56,10 +50,52 @@ fn cat() -> impl std::fmt::Display {
|
|||||||
return 0i32;
|
return 0i32;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
1u32
|
1u32 //~ ERROR mismatched types
|
||||||
//~^ ERROR mismatched types
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn dog() -> impl std::fmt::Display {
|
||||||
|
match 13 {
|
||||||
|
0 => 0i32,
|
||||||
|
1 => 1u32, //~ ERROR `match` arms have incompatible types
|
||||||
|
_ => 2u32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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() {}
|
||||||
|
@ -12,12 +12,21 @@ LL | 1u32
|
|||||||
|
|
|
|
||||||
= note: to return `impl Trait`, all returned values must be of the same type
|
= note: to return `impl Trait`, all returned values must be of the same type
|
||||||
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
||||||
= help: you can instead return a boxed trait object using `Box<dyn std::fmt::Display>`
|
|
||||||
= 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: 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>
|
||||||
= help: alternatively, create a new `enum` with a variant for each returned type
|
= help: you could instead create a new `enum` with a variant for each returned type
|
||||||
|
help: you could change the return type to be a boxed trait object
|
||||||
|
|
|
||||||
|
LL | fn foo() -> Box<dyn std::fmt::Display> {
|
||||||
|
| ^^^^^^^ ^
|
||||||
|
help: if you change the return type to expect trait objects, box the returned expressions
|
||||||
|
|
|
||||||
|
LL | return Box::new(0i32);
|
||||||
|
LL | }
|
||||||
|
LL | Box::new(1u32)
|
||||||
|
|
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:13:16
|
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:12:16
|
||||||
|
|
|
|
||||||
LL | fn bar() -> impl std::fmt::Display {
|
LL | fn bar() -> impl std::fmt::Display {
|
||||||
| ---------------------- expected because this return type...
|
| ---------------------- expected because this return type...
|
||||||
@ -30,12 +39,21 @@ LL | return 1u32;
|
|||||||
|
|
|
|
||||||
= note: to return `impl Trait`, all returned values must be of the same type
|
= note: to return `impl Trait`, all returned values must be of the same type
|
||||||
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
||||||
= help: you can instead return a boxed trait object using `Box<dyn std::fmt::Display>`
|
|
||||||
= 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: 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>
|
||||||
= help: alternatively, create a new `enum` with a variant for each returned type
|
= help: you could instead create a new `enum` with a variant for each returned type
|
||||||
|
help: you could change the return type to be a boxed trait object
|
||||||
|
|
|
||||||
|
LL | fn bar() -> Box<dyn std::fmt::Display> {
|
||||||
|
| ^^^^^^^ ^
|
||||||
|
help: if you change the return type to expect trait objects, box the returned expressions
|
||||||
|
|
|
||||||
|
LL | return Box::new(0i32);
|
||||||
|
LL | } else {
|
||||||
|
LL | return Box::new(1u32);
|
||||||
|
|
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:22:9
|
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:20:9
|
||||||
|
|
|
|
||||||
LL | fn baz() -> impl std::fmt::Display {
|
LL | fn baz() -> impl std::fmt::Display {
|
||||||
| ---------------------- expected because this return type...
|
| ---------------------- expected because this return type...
|
||||||
@ -48,12 +66,21 @@ LL | 1u32
|
|||||||
|
|
|
|
||||||
= note: to return `impl Trait`, all returned values must be of the same type
|
= note: to return `impl Trait`, all returned values must be of the same type
|
||||||
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
||||||
= help: you can instead return a boxed trait object using `Box<dyn std::fmt::Display>`
|
|
||||||
= 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: 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>
|
||||||
= help: alternatively, create a new `enum` with a variant for each returned type
|
= help: you could instead create a new `enum` with a variant for each returned type
|
||||||
|
help: you could change the return type to be a boxed trait object
|
||||||
|
|
|
||||||
|
LL | fn baz() -> Box<dyn std::fmt::Display> {
|
||||||
|
| ^^^^^^^ ^
|
||||||
|
help: if you change the return type to expect trait objects, box the returned expressions
|
||||||
|
|
|
||||||
|
LL | return Box::new(0i32);
|
||||||
|
LL | } else {
|
||||||
|
LL | Box::new(1u32)
|
||||||
|
|
|
||||||
|
|
||||||
error[E0308]: `if` and `else` have incompatible types
|
error[E0308]: `if` and `else` have incompatible types
|
||||||
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:31:9
|
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:28:9
|
||||||
|
|
|
|
||||||
LL | / if false {
|
LL | / if false {
|
||||||
LL | | 0i32
|
LL | | 0i32
|
||||||
@ -61,12 +88,22 @@ LL | | 0i32
|
|||||||
LL | | } else {
|
LL | | } else {
|
||||||
LL | | 1u32
|
LL | | 1u32
|
||||||
| | ^^^^ expected `i32`, found `u32`
|
| | ^^^^ expected `i32`, found `u32`
|
||||||
LL | |
|
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_____- `if` and `else` have incompatible types
|
| |_____- `if` and `else` have incompatible types
|
||||||
|
|
|
||||||
|
help: you could change the return type to be a boxed trait object
|
||||||
|
|
|
||||||
|
LL | fn qux() -> 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)
|
||||||
|
|
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:39:14
|
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:35:14
|
||||||
|
|
|
|
||||||
LL | fn bat() -> impl std::fmt::Display {
|
LL | fn bat() -> impl std::fmt::Display {
|
||||||
| ---------------------- expected because this return type...
|
| ---------------------- expected because this return type...
|
||||||
@ -78,17 +115,24 @@ LL | _ => 1u32,
|
|||||||
|
|
|
|
||||||
= note: to return `impl Trait`, all returned values must be of the same type
|
= note: to return `impl Trait`, all returned values must be of the same type
|
||||||
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
||||||
= help: you can instead return a boxed trait object using `Box<dyn std::fmt::Display>`
|
|
||||||
= 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: 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>
|
||||||
= help: alternatively, create a new `enum` with a variant for each returned type
|
= help: you could instead create a new `enum` with a variant for each returned type
|
||||||
|
help: you could change the return type to be a boxed trait object
|
||||||
|
|
|
||||||
|
LL | fn bat() -> Box<dyn std::fmt::Display> {
|
||||||
|
| ^^^^^^^ ^
|
||||||
|
help: if you change the return type to expect trait objects, box the returned expressions
|
||||||
|
|
|
||||||
|
LL | 0 => return Box::new(0i32),
|
||||||
|
LL | _ => Box::new(1u32),
|
||||||
|
|
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:45:5
|
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:40:5
|
||||||
|
|
|
|
||||||
LL | fn can() -> impl std::fmt::Display {
|
LL | fn can() -> impl std::fmt::Display {
|
||||||
| ---------------------- expected because this return type...
|
| ---------------------- expected because this return type...
|
||||||
LL | / match 13 {
|
LL | / match 13 {
|
||||||
LL | |
|
|
||||||
LL | | 0 => return 0i32,
|
LL | | 0 => return 0i32,
|
||||||
| | ---- ...is found to be `i32` here
|
| | ---- ...is found to be `i32` here
|
||||||
LL | | 1 => 1u32,
|
LL | | 1 => 1u32,
|
||||||
@ -98,12 +142,23 @@ LL | | }
|
|||||||
|
|
|
|
||||||
= note: to return `impl Trait`, all returned values must be of the same type
|
= note: to return `impl Trait`, all returned values must be of the same type
|
||||||
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
||||||
= help: you can instead return a boxed trait object using `Box<dyn std::fmt::Display>`
|
|
||||||
= 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: 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>
|
||||||
= help: alternatively, create a new `enum` with a variant for each returned type
|
= help: you could instead create a new `enum` with a variant for each returned type
|
||||||
|
help: you could change the return type to be a boxed trait object
|
||||||
|
|
|
||||||
|
LL | fn can() -> Box<dyn std::fmt::Display> {
|
||||||
|
| ^^^^^^^ ^
|
||||||
|
help: if you change the return type to expect trait objects, box the returned expressions
|
||||||
|
|
|
||||||
|
LL | Box::new(match 13 {
|
||||||
|
LL | 0 => return Box::new(0i32),
|
||||||
|
LL | 1 => 1u32,
|
||||||
|
LL | _ => 2u32,
|
||||||
|
LL | })
|
||||||
|
|
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:59:13
|
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:53:13
|
||||||
|
|
|
|
||||||
LL | fn cat() -> impl std::fmt::Display {
|
LL | fn cat() -> impl std::fmt::Display {
|
||||||
| ---------------------- expected because this return type...
|
| ---------------------- expected because this return type...
|
||||||
@ -116,10 +171,148 @@ LL | 1u32
|
|||||||
|
|
|
|
||||||
= note: to return `impl Trait`, all returned values must be of the same type
|
= note: to return `impl Trait`, all returned values must be of the same type
|
||||||
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
|
||||||
= help: you can instead return a boxed trait object using `Box<dyn std::fmt::Display>`
|
|
||||||
= 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: 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>
|
||||||
= help: alternatively, create a new `enum` with a variant for each returned type
|
= help: you could instead create a new `enum` with a variant for each returned type
|
||||||
|
help: you could change the return type to be a boxed trait object
|
||||||
|
|
|
||||||
|
LL | fn cat() -> Box<dyn std::fmt::Display> {
|
||||||
|
| ^^^^^^^ ^
|
||||||
|
help: if you change the return type to expect trait objects, box the returned expressions
|
||||||
|
|
|
||||||
|
LL | return Box::new(0i32);
|
||||||
|
LL | }
|
||||||
|
LL | _ => {
|
||||||
|
LL | Box::new(1u32)
|
||||||
|
|
|
||||||
|
|
||||||
error: aborting due to 7 previous errors
|
error[E0308]: `match` arms have incompatible types
|
||||||
|
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:61: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
|
||||||
|
|
|
||||||
|
help: you could change the return type to be a boxed trait object
|
||||||
|
|
|
||||||
|
LL | fn dog() -> Box<dyn std::fmt::Display> {
|
||||||
|
| ^^^^^^^ ^
|
||||||
|
help: if you change the return type to expect trait objects, box the returned expressions
|
||||||
|
|
|
||||||
|
LL | 0 => Box::new(0i32),
|
||||||
|
LL | 1 => Box::new(1u32),
|
||||||
|
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0308`.
|
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)
|
||||||
|
|
|
||||||
|
|
||||||
|
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…
x
Reference in New Issue
Block a user