Fix ICE in opt_suggest_box_span
This commit is contained in:
parent
0a605d33cd
commit
5599a45e58
5 changed files with 114 additions and 50 deletions
|
@ -73,7 +73,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
// for opaque types, and then use that kind to fix the spans for type errors
|
// for opaque types, and then use that kind to fix the spans for type errors
|
||||||
// that we see later on.
|
// that we see later on.
|
||||||
let ty_var = self.next_ty_var(TypeVariableOrigin {
|
let ty_var = self.next_ty_var(TypeVariableOrigin {
|
||||||
kind: TypeVariableOriginKind::TypeInference,
|
kind: TypeVariableOriginKind::OpaqueTypeInference(def_id),
|
||||||
span,
|
span,
|
||||||
});
|
});
|
||||||
obligations.extend(
|
obligations.extend(
|
||||||
|
|
|
@ -122,6 +122,7 @@ pub enum TypeVariableOriginKind {
|
||||||
MiscVariable,
|
MiscVariable,
|
||||||
NormalizeProjectionType,
|
NormalizeProjectionType,
|
||||||
TypeInference,
|
TypeInference,
|
||||||
|
OpaqueTypeInference(DefId),
|
||||||
TypeParameterDefinition(Symbol, Option<DefId>),
|
TypeParameterDefinition(Symbol, Option<DefId>),
|
||||||
|
|
||||||
/// One of the upvars or closure kind parameters in a `ClosureSubsts`
|
/// One of the upvars or closure kind parameters in a `ClosureSubsts`
|
||||||
|
|
|
@ -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};
|
use rustc_middle::ty::{self, Subst, 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::{
|
||||||
|
@ -143,7 +143,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
.find_by_def_id(self.body_id.owner)
|
.find_by_def_id(self.body_id.owner)
|
||||||
.and_then(|owner| owner.fn_decl())
|
.and_then(|owner| owner.fn_decl())
|
||||||
.map(|decl| decl.output.span())
|
.map(|decl| decl.output.span())
|
||||||
else { return; };
|
else { return; };
|
||||||
let Expectation::IsLast(stmt) = orig_expected else {
|
let Expectation::IsLast(stmt) = orig_expected else {
|
||||||
return
|
return
|
||||||
};
|
};
|
||||||
|
@ -472,64 +472,77 @@ 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.
|
||||||
pub(crate) fn opt_suggest_box_span(
|
pub(crate) fn opt_suggest_box_span(
|
||||||
&self,
|
&self,
|
||||||
first_ty: Ty<'tcx>,
|
first_ty: Ty<'tcx>,
|
||||||
second_ty: Ty<'tcx>,
|
second_ty: Ty<'tcx>,
|
||||||
orig_expected: Expectation<'tcx>,
|
orig_expected: Expectation<'tcx>,
|
||||||
) -> Option<Span> {
|
) -> Option<Span> {
|
||||||
|
// FIXME(compiler-errors): This really shouldn't need to be done during the
|
||||||
|
// "good" path of typeck, but here we are.
|
||||||
match orig_expected {
|
match orig_expected {
|
||||||
Expectation::ExpectHasType(expected)
|
Expectation::ExpectHasType(expected) => {
|
||||||
if self.in_tail_expr
|
let TypeVariableOrigin {
|
||||||
&& self.return_type_has_opaque
|
span,
|
||||||
&& self.can_coerce(first_ty, expected)
|
kind: TypeVariableOriginKind::OpaqueTypeInference(rpit_def_id),
|
||||||
&& self.can_coerce(second_ty, expected) =>
|
..
|
||||||
{
|
} = self.type_var_origin(expected)? else { return None; };
|
||||||
let obligations = self.fulfillment_cx.borrow().pending_obligations();
|
|
||||||
let mut suggest_box = !obligations.is_empty();
|
let sig = *self
|
||||||
'outer: for o in obligations {
|
.typeck_results
|
||||||
for outer_ty in &[first_ty, second_ty] {
|
.borrow()
|
||||||
match o.predicate.kind().skip_binder() {
|
.liberated_fn_sigs()
|
||||||
ty::PredicateKind::Trait(t) => {
|
.get(hir::HirId::make_owner(self.body_id.owner))?;
|
||||||
let pred = ty::Binder::dummy(ty::PredicateKind::Trait(
|
|
||||||
ty::TraitPredicate {
|
let substs = sig.output().walk().find_map(|arg| {
|
||||||
trait_ref: ty::TraitRef {
|
if let ty::GenericArgKind::Type(ty) = arg.unpack()
|
||||||
def_id: t.def_id(),
|
&& let ty::Opaque(def_id, substs) = *ty.kind()
|
||||||
substs: self.tcx.mk_substs_trait(*outer_ty, &[]),
|
&& def_id == rpit_def_id
|
||||||
},
|
{
|
||||||
constness: t.constness,
|
Some(substs)
|
||||||
polarity: t.polarity,
|
} else {
|
||||||
},
|
None
|
||||||
));
|
}
|
||||||
let obl = Obligation::new(
|
})?;
|
||||||
o.cause.clone(),
|
let opaque_ty = self.tcx.mk_opaque(rpit_def_id, substs);
|
||||||
self.param_env,
|
|
||||||
pred.to_predicate(self.tcx),
|
if !self.can_coerce(first_ty, expected) || !self.can_coerce(second_ty, expected) {
|
||||||
);
|
return None;
|
||||||
suggest_box &= self.predicate_must_hold_modulo_regions(&obl);
|
}
|
||||||
if !suggest_box {
|
|
||||||
// We've encountered some obligation that didn't hold, so the
|
for ty in [first_ty, second_ty] {
|
||||||
// return expression can't just be boxed. We don't need to
|
for pred in self.tcx.bound_explicit_item_bounds(rpit_def_id).transpose_iter() {
|
||||||
// evaluate the rest of the obligations.
|
let pred = pred.map_bound(|(pred, _)| *pred).subst(self.tcx, substs);
|
||||||
break 'outer;
|
let pred = match pred.kind().skip_binder() {
|
||||||
}
|
ty::PredicateKind::Trait(mut trait_pred) => {
|
||||||
|
assert_eq!(trait_pred.trait_ref.self_ty(), opaque_ty);
|
||||||
|
trait_pred.trait_ref.substs =
|
||||||
|
self.tcx.mk_substs_trait(ty, &trait_pred.trait_ref.substs[1..]);
|
||||||
|
pred.kind().rebind(trait_pred).to_predicate(self.tcx)
|
||||||
}
|
}
|
||||||
_ => {}
|
ty::PredicateKind::Projection(mut proj_pred) => {
|
||||||
|
assert_eq!(proj_pred.projection_ty.self_ty(), opaque_ty);
|
||||||
|
proj_pred.projection_ty.substs = self
|
||||||
|
.tcx
|
||||||
|
.mk_substs_trait(ty, &proj_pred.projection_ty.substs[1..]);
|
||||||
|
pred.kind().rebind(proj_pred).to_predicate(self.tcx)
|
||||||
|
}
|
||||||
|
_ => continue,
|
||||||
|
};
|
||||||
|
if !self.predicate_must_hold_modulo_regions(&Obligation::new(
|
||||||
|
ObligationCause::misc(span, self.body_id),
|
||||||
|
self.param_env,
|
||||||
|
pred,
|
||||||
|
)) {
|
||||||
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if suggest_box {
|
|
||||||
self.tcx
|
Some(span)
|
||||||
.hir()
|
|
||||||
.find_by_def_id(self.body_id.owner)
|
|
||||||
.and_then(|owner| owner.fn_decl())
|
|
||||||
.map(|decl| decl.output.span())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
|
25
src/test/ui/suggestions/issue-101465.rs
Normal file
25
src/test/ui/suggestions/issue-101465.rs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#![feature(trait_alias)]
|
||||||
|
|
||||||
|
struct B;
|
||||||
|
struct C;
|
||||||
|
|
||||||
|
trait Tr {}
|
||||||
|
|
||||||
|
impl Tr for B {}
|
||||||
|
impl Tr for C {}
|
||||||
|
|
||||||
|
trait Tr2<S> = Into<S>;
|
||||||
|
|
||||||
|
fn foo2<T: Tr2<()>>() {}
|
||||||
|
|
||||||
|
fn foo() -> impl Tr {
|
||||||
|
let x = foo2::<_>();
|
||||||
|
|
||||||
|
match true {
|
||||||
|
true => B,
|
||||||
|
false => C,
|
||||||
|
//~^ `match` arms have incompatible types
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
25
src/test/ui/suggestions/issue-101465.stderr
Normal file
25
src/test/ui/suggestions/issue-101465.stderr
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
error[E0308]: `match` arms have incompatible types
|
||||||
|
--> $DIR/issue-101465.rs:20:18
|
||||||
|
|
|
||||||
|
LL | / match true {
|
||||||
|
LL | | true => B,
|
||||||
|
| | - this is found to be of type `B`
|
||||||
|
LL | | false => C,
|
||||||
|
| | ^ expected struct `B`, found struct `C`
|
||||||
|
LL | |
|
||||||
|
LL | | }
|
||||||
|
| |_____- `match` arms have incompatible types
|
||||||
|
|
|
||||||
|
help: you could change the return type to be a boxed trait object
|
||||||
|
|
|
||||||
|
LL | fn foo() -> Box<dyn Tr> {
|
||||||
|
| ~~~~~~~ +
|
||||||
|
help: if you change the return type to expect trait objects, box the returned expressions
|
||||||
|
|
|
||||||
|
LL ~ true => Box::new(B),
|
||||||
|
LL ~ false => Box::new(C),
|
||||||
|
|
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
Loading…
Add table
Add a link
Reference in a new issue