mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-30 10:45:18 +00:00
Rollup merge of #100019 - TaKO8Ki:suggest-boxed-trait-objects-instead-of-impl-trait, r=compiler-errors
Revive suggestions for boxed trait objects instead of impl Trait The suggestion implemented in #75608 was not working properly, so I fixed it.
This commit is contained in:
commit
7be359e51b
@ -4,7 +4,7 @@ use rustc_errors::{Applicability, MultiSpan};
|
|||||||
use rustc_hir::{self as hir, ExprKind};
|
use rustc_hir::{self as hir, ExprKind};
|
||||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
use rustc_infer::traits::Obligation;
|
use rustc_infer::traits::Obligation;
|
||||||
use rustc_middle::ty::{self, ToPredicate, Ty, TypeVisitable};
|
use rustc_middle::ty::{self, ToPredicate, Ty};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
||||||
use rustc_trait_selection::traits::{
|
use rustc_trait_selection::traits::{
|
||||||
@ -94,7 +94,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
let arm_ty = self.check_expr_with_expectation(&arm.body, expected);
|
let arm_ty = self.check_expr_with_expectation(&arm.body, expected);
|
||||||
all_arms_diverge &= self.diverges.get();
|
all_arms_diverge &= self.diverges.get();
|
||||||
|
|
||||||
let opt_suggest_box_span = self.opt_suggest_box_span(arm_ty, orig_expected);
|
let opt_suggest_box_span = prior_arm.and_then(|(_, prior_arm_ty, _)| {
|
||||||
|
self.opt_suggest_box_span(prior_arm_ty, arm_ty, orig_expected)
|
||||||
|
});
|
||||||
|
|
||||||
let (arm_block_id, arm_span) = if let hir::ExprKind::Block(blk, _) = arm.body.kind {
|
let (arm_block_id, arm_span) = if let hir::ExprKind::Block(blk, _) = arm.body.kind {
|
||||||
(Some(blk.hir_id), self.find_block_span(blk))
|
(Some(blk.hir_id), self.find_block_span(blk))
|
||||||
@ -473,43 +475,48 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// provide a structured suggestion in that case.
|
// provide a structured suggestion in that case.
|
||||||
pub(crate) fn opt_suggest_box_span(
|
pub(crate) fn opt_suggest_box_span(
|
||||||
&self,
|
&self,
|
||||||
outer_ty: Ty<'tcx>,
|
first_ty: Ty<'tcx>,
|
||||||
|
second_ty: Ty<'tcx>,
|
||||||
orig_expected: Expectation<'tcx>,
|
orig_expected: Expectation<'tcx>,
|
||||||
) -> Option<Span> {
|
) -> Option<Span> {
|
||||||
match orig_expected {
|
match orig_expected {
|
||||||
Expectation::ExpectHasType(expected)
|
Expectation::ExpectHasType(expected)
|
||||||
if self.in_tail_expr
|
if self.in_tail_expr
|
||||||
&& self.ret_coercion.as_ref()?.borrow().merged_ty().has_opaque_types()
|
&& self.return_type_has_opaque
|
||||||
&& self.can_coerce(outer_ty, expected) =>
|
&& self.can_coerce(first_ty, expected)
|
||||||
|
&& self.can_coerce(second_ty, expected) =>
|
||||||
{
|
{
|
||||||
let obligations = self.fulfillment_cx.borrow().pending_obligations();
|
let obligations = self.fulfillment_cx.borrow().pending_obligations();
|
||||||
let mut suggest_box = !obligations.is_empty();
|
let mut suggest_box = !obligations.is_empty();
|
||||||
for o in obligations {
|
'outer: for o in obligations {
|
||||||
match o.predicate.kind().skip_binder() {
|
for outer_ty in &[first_ty, second_ty] {
|
||||||
ty::PredicateKind::Trait(t) => {
|
match o.predicate.kind().skip_binder() {
|
||||||
let pred =
|
ty::PredicateKind::Trait(t) => {
|
||||||
ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate {
|
let pred = ty::Binder::dummy(ty::PredicateKind::Trait(
|
||||||
trait_ref: ty::TraitRef {
|
ty::TraitPredicate {
|
||||||
def_id: t.def_id(),
|
trait_ref: ty::TraitRef {
|
||||||
substs: self.tcx.mk_substs_trait(outer_ty, &[]),
|
def_id: t.def_id(),
|
||||||
|
substs: self.tcx.mk_substs_trait(*outer_ty, &[]),
|
||||||
|
},
|
||||||
|
constness: t.constness,
|
||||||
|
polarity: t.polarity,
|
||||||
},
|
},
|
||||||
constness: t.constness,
|
));
|
||||||
polarity: t.polarity,
|
let obl = Obligation::new(
|
||||||
}));
|
o.cause.clone(),
|
||||||
let obl = Obligation::new(
|
self.param_env,
|
||||||
o.cause.clone(),
|
pred.to_predicate(self.tcx),
|
||||||
self.param_env,
|
);
|
||||||
pred.to_predicate(self.tcx),
|
suggest_box &= self.predicate_must_hold_modulo_regions(&obl);
|
||||||
);
|
if !suggest_box {
|
||||||
suggest_box &= self.predicate_must_hold_modulo_regions(&obl);
|
// We've encountered some obligation that didn't hold, so the
|
||||||
if !suggest_box {
|
// return expression can't just be boxed. We don't need to
|
||||||
// We've encountered some obligation that didn't hold, so the
|
// evaluate the rest of the obligations.
|
||||||
// return expression can't just be boxed. We don't need to
|
break 'outer;
|
||||||
// evaluate the rest of the obligations.
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If all the obligations hold (or there are no obligations) the tail expression
|
// If all the obligations hold (or there are no obligations) the tail expression
|
||||||
|
@ -1002,7 +1002,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
let else_ty = self.check_expr_with_expectation(else_expr, expected);
|
let else_ty = self.check_expr_with_expectation(else_expr, expected);
|
||||||
let else_diverges = self.diverges.get();
|
let else_diverges = self.diverges.get();
|
||||||
|
|
||||||
let opt_suggest_box_span = self.opt_suggest_box_span(else_ty, orig_expected);
|
let opt_suggest_box_span = self.opt_suggest_box_span(then_ty, else_ty, orig_expected);
|
||||||
let if_cause = self.if_cause(
|
let if_cause = self.if_cause(
|
||||||
sp,
|
sp,
|
||||||
cond_expr.span,
|
cond_expr.span,
|
||||||
|
@ -52,6 +52,16 @@ LL | | 1u32
|
|||||||
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)
|
||||||
|
|
|
||||||
help: change the type of the numeric literal from `u32` to `i32`
|
help: change the type of the numeric literal from `u32` to `i32`
|
||||||
|
|
|
|
||||||
LL | 1i32
|
LL | 1i32
|
||||||
@ -114,6 +124,15 @@ LL | | _ => 2u32,
|
|||||||
LL | | }
|
LL | | }
|
||||||
| |_____- `match` arms have incompatible types
|
| |_____- `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),
|
||||||
|
|
|
||||||
help: change the type of the numeric literal from `u32` to `i32`
|
help: change the type of the numeric literal from `u32` to `i32`
|
||||||
|
|
|
|
||||||
LL | 1 => 1i32,
|
LL | 1 => 1i32,
|
||||||
@ -131,6 +150,16 @@ LL | | 1u32
|
|||||||
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 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)
|
||||||
|
|
|
||||||
help: change the type of the numeric literal from `u32` to `i32`
|
help: change the type of the numeric literal from `u32` to `i32`
|
||||||
|
|
|
|
||||||
LL | 1i32
|
LL | 1i32
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
struct S;
|
||||||
|
struct Y;
|
||||||
|
|
||||||
|
trait Trait {}
|
||||||
|
|
||||||
|
impl Trait for Y {}
|
||||||
|
|
||||||
|
fn foo() -> impl Trait {
|
||||||
|
if true {
|
||||||
|
S
|
||||||
|
} else {
|
||||||
|
Y //~ ERROR `if` and `else` have incompatible types
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar() -> impl Trait {
|
||||||
|
match true {
|
||||||
|
true => S,
|
||||||
|
false => Y, //~ ERROR `match` arms have incompatible types
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
@ -0,0 +1,26 @@
|
|||||||
|
error[E0308]: `if` and `else` have incompatible types
|
||||||
|
--> $DIR/do-not-suggest-boxed-trait-objects-instead-of-impl-trait.rs:12:9
|
||||||
|
|
|
||||||
|
LL | / if true {
|
||||||
|
LL | | S
|
||||||
|
| | - expected because of this
|
||||||
|
LL | | } else {
|
||||||
|
LL | | Y
|
||||||
|
| | ^ expected struct `S`, found struct `Y`
|
||||||
|
LL | | }
|
||||||
|
| |_____- `if` and `else` have incompatible types
|
||||||
|
|
||||||
|
error[E0308]: `match` arms have incompatible types
|
||||||
|
--> $DIR/do-not-suggest-boxed-trait-objects-instead-of-impl-trait.rs:19:18
|
||||||
|
|
|
||||||
|
LL | / match true {
|
||||||
|
LL | | true => S,
|
||||||
|
| | - this is found to be of type `S`
|
||||||
|
LL | | false => Y,
|
||||||
|
| | ^ expected struct `S`, found struct `Y`
|
||||||
|
LL | | }
|
||||||
|
| |_____- `match` arms have incompatible types
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
@ -0,0 +1,28 @@
|
|||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
struct S;
|
||||||
|
struct Y;
|
||||||
|
|
||||||
|
trait Trait {}
|
||||||
|
|
||||||
|
impl Trait for S {}
|
||||||
|
impl Trait for Y {}
|
||||||
|
|
||||||
|
fn foo() -> Box<dyn Trait> {
|
||||||
|
if true {
|
||||||
|
Box::new(S)
|
||||||
|
} else {
|
||||||
|
Box::new(Y) //~ ERROR `if` and `else` have incompatible types
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar() -> Box<dyn Trait> {
|
||||||
|
match true {
|
||||||
|
true => Box::new(S),
|
||||||
|
false => Box::new(Y), //~ ERROR `match` arms have incompatible types
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
@ -0,0 +1,28 @@
|
|||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
struct S;
|
||||||
|
struct Y;
|
||||||
|
|
||||||
|
trait Trait {}
|
||||||
|
|
||||||
|
impl Trait for S {}
|
||||||
|
impl Trait for Y {}
|
||||||
|
|
||||||
|
fn foo() -> impl Trait {
|
||||||
|
if true {
|
||||||
|
S
|
||||||
|
} else {
|
||||||
|
Y //~ ERROR `if` and `else` have incompatible types
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar() -> impl Trait {
|
||||||
|
match true {
|
||||||
|
true => S,
|
||||||
|
false => Y, //~ ERROR `match` arms have incompatible types
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
@ -0,0 +1,47 @@
|
|||||||
|
error[E0308]: `if` and `else` have incompatible types
|
||||||
|
--> $DIR/suggest-boxed-trait-objects-instead-of-impl-trait.rs:17:9
|
||||||
|
|
|
||||||
|
LL | / if true {
|
||||||
|
LL | | S
|
||||||
|
| | - expected because of this
|
||||||
|
LL | | } else {
|
||||||
|
LL | | Y
|
||||||
|
| | ^ expected struct `S`, found struct `Y`
|
||||||
|
LL | | }
|
||||||
|
| |_____- `if` and `else` have incompatible types
|
||||||
|
|
|
||||||
|
help: you could change the return type to be a boxed trait object
|
||||||
|
|
|
||||||
|
LL | fn foo() -> Box<dyn Trait> {
|
||||||
|
| ~~~~~~~ +
|
||||||
|
help: if you change the return type to expect trait objects, box the returned expressions
|
||||||
|
|
|
||||||
|
LL ~ Box::new(S)
|
||||||
|
LL | } else {
|
||||||
|
LL ~ Box::new(Y)
|
||||||
|
|
|
||||||
|
|
||||||
|
error[E0308]: `match` arms have incompatible types
|
||||||
|
--> $DIR/suggest-boxed-trait-objects-instead-of-impl-trait.rs:24:18
|
||||||
|
|
|
||||||
|
LL | / match true {
|
||||||
|
LL | | true => S,
|
||||||
|
| | - this is found to be of type `S`
|
||||||
|
LL | | false => Y,
|
||||||
|
| | ^ expected struct `S`, found struct `Y`
|
||||||
|
LL | | }
|
||||||
|
| |_____- `match` arms have incompatible types
|
||||||
|
|
|
||||||
|
help: you could change the return type to be a boxed trait object
|
||||||
|
|
|
||||||
|
LL | fn bar() -> Box<dyn Trait> {
|
||||||
|
| ~~~~~~~ +
|
||||||
|
help: if you change the return type to expect trait objects, box the returned expressions
|
||||||
|
|
|
||||||
|
LL ~ true => Box::new(S),
|
||||||
|
LL ~ false => Box::new(Y),
|
||||||
|
|
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
Loading…
Reference in New Issue
Block a user