mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-27 09:14:20 +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_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
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_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
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);
|
||||
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 {
|
||||
(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.
|
||||
pub(crate) fn opt_suggest_box_span(
|
||||
&self,
|
||||
outer_ty: Ty<'tcx>,
|
||||
first_ty: Ty<'tcx>,
|
||||
second_ty: Ty<'tcx>,
|
||||
orig_expected: Expectation<'tcx>,
|
||||
) -> Option<Span> {
|
||||
match orig_expected {
|
||||
Expectation::ExpectHasType(expected)
|
||||
if self.in_tail_expr
|
||||
&& self.ret_coercion.as_ref()?.borrow().merged_ty().has_opaque_types()
|
||||
&& self.can_coerce(outer_ty, expected) =>
|
||||
&& self.return_type_has_opaque
|
||||
&& self.can_coerce(first_ty, expected)
|
||||
&& self.can_coerce(second_ty, expected) =>
|
||||
{
|
||||
let obligations = self.fulfillment_cx.borrow().pending_obligations();
|
||||
let mut suggest_box = !obligations.is_empty();
|
||||
for o in obligations {
|
||||
match o.predicate.kind().skip_binder() {
|
||||
ty::PredicateKind::Trait(t) => {
|
||||
let pred =
|
||||
ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate {
|
||||
trait_ref: ty::TraitRef {
|
||||
def_id: t.def_id(),
|
||||
substs: self.tcx.mk_substs_trait(outer_ty, &[]),
|
||||
'outer: for o in obligations {
|
||||
for outer_ty in &[first_ty, second_ty] {
|
||||
match o.predicate.kind().skip_binder() {
|
||||
ty::PredicateKind::Trait(t) => {
|
||||
let pred = ty::Binder::dummy(ty::PredicateKind::Trait(
|
||||
ty::TraitPredicate {
|
||||
trait_ref: ty::TraitRef {
|
||||
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(),
|
||||
self.param_env,
|
||||
pred.to_predicate(self.tcx),
|
||||
);
|
||||
suggest_box &= self.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;
|
||||
));
|
||||
let obl = Obligation::new(
|
||||
o.cause.clone(),
|
||||
self.param_env,
|
||||
pred.to_predicate(self.tcx),
|
||||
);
|
||||
suggest_box &= self.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 'outer;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
// 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_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(
|
||||
sp,
|
||||
cond_expr.span,
|
||||
|
@ -52,6 +52,16 @@ LL | | 1u32
|
||||
LL | | }
|
||||
| |_____- `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`
|
||||
|
|
||||
LL | 1i32
|
||||
@ -114,6 +124,15 @@ 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),
|
||||
|
|
||||
help: change the type of the numeric literal from `u32` to `i32`
|
||||
|
|
||||
LL | 1 => 1i32,
|
||||
@ -131,6 +150,16 @@ LL | | 1u32
|
||||
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)
|
||||
|
|
||||
help: change the type of the numeric literal from `u32` to `i32`
|
||||
|
|
||||
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