Skip to content

Commit a93214e

Browse files
committedSep 12, 2022
Auto merge of #101604 - compiler-errors:issue-101465, r=lcnr
Fix ICE in opt_suggest_box_span We were _totally_ mishandling substs and obligations in `opt_suggest_box_span`, so I reworked that function pretty heavily. Also some drive-by changes, namely removing `ret_type_span`. Fixes #101465
2 parents 56e7678 + 5599a45 commit a93214e

File tree

7 files changed

+120
-50
lines changed

7 files changed

+120
-50
lines changed
 

‎compiler/rustc_infer/src/infer/opaque_types.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
7373
// for opaque types, and then use that kind to fix the spans for type errors
7474
// that we see later on.
7575
let ty_var = self.next_ty_var(TypeVariableOrigin {
76-
kind: TypeVariableOriginKind::TypeInference,
76+
kind: TypeVariableOriginKind::OpaqueTypeInference(def_id),
7777
span,
7878
});
7979
obligations.extend(

‎compiler/rustc_infer/src/infer/type_variable.rs

+1
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ pub enum TypeVariableOriginKind {
122122
MiscVariable,
123123
NormalizeProjectionType,
124124
TypeInference,
125+
OpaqueTypeInference(DefId),
125126
TypeParameterDefinition(Symbol, Option<DefId>),
126127

127128
/// One of the upvars or closure kind parameters in a `ClosureSubsts`

‎compiler/rustc_typeck/src/check/_match.rs

+68-45
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use rustc_errors::{Applicability, MultiSpan};
44
use rustc_hir::{self as hir, ExprKind};
55
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
66
use rustc_infer::traits::Obligation;
7-
use rustc_middle::ty::{self, ToPredicate, Ty};
7+
use rustc_middle::ty::{self, Subst, ToPredicate, Ty};
88
use rustc_span::Span;
99
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
1010
use rustc_trait_selection::traits::{
@@ -137,9 +137,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
137137
Some(&arm.body),
138138
arm_ty,
139139
Some(&mut |err| {
140-
let Some(ret) = self.ret_type_span else {
141-
return;
142-
};
140+
let Some(ret) = self
141+
.tcx
142+
.hir()
143+
.find_by_def_id(self.body_id.owner)
144+
.and_then(|owner| owner.fn_decl())
145+
.map(|decl| decl.output.span())
146+
else { return; };
143147
let Expectation::IsLast(stmt) = orig_expected else {
144148
return
145149
};
@@ -468,58 +472,77 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
468472
}
469473
}
470474

471-
// When we have a `match` as a tail expression in a `fn` with a returned `impl Trait`
472-
// we check if the different arms would work with boxed trait objects instead and
473-
// provide a structured suggestion in that case.
475+
/// When we have a `match` as a tail expression in a `fn` with a returned `impl Trait`
476+
/// we check if the different arms would work with boxed trait objects instead and
477+
/// provide a structured suggestion in that case.
474478
pub(crate) fn opt_suggest_box_span(
475479
&self,
476480
first_ty: Ty<'tcx>,
477481
second_ty: Ty<'tcx>,
478482
orig_expected: Expectation<'tcx>,
479483
) -> Option<Span> {
484+
// FIXME(compiler-errors): This really shouldn't need to be done during the
485+
// "good" path of typeck, but here we are.
480486
match orig_expected {
481-
Expectation::ExpectHasType(expected)
482-
if self.in_tail_expr
483-
&& self.return_type_has_opaque
484-
&& self.can_coerce(first_ty, expected)
485-
&& self.can_coerce(second_ty, expected) =>
486-
{
487-
let obligations = self.fulfillment_cx.borrow().pending_obligations();
488-
let mut suggest_box = !obligations.is_empty();
489-
'outer: for o in obligations {
490-
for outer_ty in &[first_ty, second_ty] {
491-
match o.predicate.kind().skip_binder() {
492-
ty::PredicateKind::Trait(t) => {
493-
let pred = ty::Binder::dummy(ty::PredicateKind::Trait(
494-
ty::TraitPredicate {
495-
trait_ref: ty::TraitRef {
496-
def_id: t.def_id(),
497-
substs: self.tcx.mk_substs_trait(*outer_ty, &[]),
498-
},
499-
constness: t.constness,
500-
polarity: t.polarity,
501-
},
502-
));
503-
let obl = Obligation::new(
504-
o.cause.clone(),
505-
self.param_env,
506-
pred.to_predicate(self.tcx),
507-
);
508-
suggest_box &= self.predicate_must_hold_modulo_regions(&obl);
509-
if !suggest_box {
510-
// We've encountered some obligation that didn't hold, so the
511-
// return expression can't just be boxed. We don't need to
512-
// evaluate the rest of the obligations.
513-
break 'outer;
514-
}
487+
Expectation::ExpectHasType(expected) => {
488+
let TypeVariableOrigin {
489+
span,
490+
kind: TypeVariableOriginKind::OpaqueTypeInference(rpit_def_id),
491+
..
492+
} = self.type_var_origin(expected)? else { return None; };
493+
494+
let sig = *self
495+
.typeck_results
496+
.borrow()
497+
.liberated_fn_sigs()
498+
.get(hir::HirId::make_owner(self.body_id.owner))?;
499+
500+
let substs = sig.output().walk().find_map(|arg| {
501+
if let ty::GenericArgKind::Type(ty) = arg.unpack()
502+
&& let ty::Opaque(def_id, substs) = *ty.kind()
503+
&& def_id == rpit_def_id
504+
{
505+
Some(substs)
506+
} else {
507+
None
508+
}
509+
})?;
510+
let opaque_ty = self.tcx.mk_opaque(rpit_def_id, substs);
511+
512+
if !self.can_coerce(first_ty, expected) || !self.can_coerce(second_ty, expected) {
513+
return None;
514+
}
515+
516+
for ty in [first_ty, second_ty] {
517+
for pred in self.tcx.bound_explicit_item_bounds(rpit_def_id).transpose_iter() {
518+
let pred = pred.map_bound(|(pred, _)| *pred).subst(self.tcx, substs);
519+
let pred = match pred.kind().skip_binder() {
520+
ty::PredicateKind::Trait(mut trait_pred) => {
521+
assert_eq!(trait_pred.trait_ref.self_ty(), opaque_ty);
522+
trait_pred.trait_ref.substs =
523+
self.tcx.mk_substs_trait(ty, &trait_pred.trait_ref.substs[1..]);
524+
pred.kind().rebind(trait_pred).to_predicate(self.tcx)
515525
}
516-
_ => {}
526+
ty::PredicateKind::Projection(mut proj_pred) => {
527+
assert_eq!(proj_pred.projection_ty.self_ty(), opaque_ty);
528+
proj_pred.projection_ty.substs = self
529+
.tcx
530+
.mk_substs_trait(ty, &proj_pred.projection_ty.substs[1..]);
531+
pred.kind().rebind(proj_pred).to_predicate(self.tcx)
532+
}
533+
_ => continue,
534+
};
535+
if !self.predicate_must_hold_modulo_regions(&Obligation::new(
536+
ObligationCause::misc(span, self.body_id),
537+
self.param_env,
538+
pred,
539+
)) {
540+
return None;
517541
}
518542
}
519543
}
520-
// If all the obligations hold (or there are no obligations) the tail expression
521-
// we can suggest to return a boxed trait object instead of an opaque type.
522-
if suggest_box { self.ret_type_span } else { None }
544+
545+
Some(span)
523546
}
524547
_ => None,
525548
}

‎compiler/rustc_typeck/src/check/check.rs

-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,6 @@ pub(super) fn check_fn<'a, 'tcx>(
106106
fcx.return_type_has_opaque = ret_ty != declared_ret_ty;
107107

108108
fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
109-
fcx.ret_type_span = Some(decl.output.span());
110109

111110
let span = body.value.span;
112111

‎compiler/rustc_typeck/src/check/fn_ctxt/mod.rs

-3
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,6 @@ pub struct FnCtxt<'a, 'tcx> {
6868
/// any).
6969
pub(super) ret_coercion: Option<RefCell<DynamicCoerceMany<'tcx>>>,
7070

71-
pub(super) ret_type_span: Option<Span>,
72-
7371
/// Used exclusively to reduce cost of advanced evaluation used for
7472
/// more helpful diagnostics.
7573
pub(super) in_tail_expr: bool,
@@ -142,7 +140,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
142140
param_env,
143141
err_count_on_creation: inh.tcx.sess.err_count(),
144142
ret_coercion: None,
145-
ret_type_span: None,
146143
in_tail_expr: false,
147144
ret_coercion_span: Cell::new(None),
148145
resume_yield_tys: None,
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#![feature(trait_alias)]
2+
3+
struct B;
4+
struct C;
5+
6+
trait Tr {}
7+
8+
impl Tr for B {}
9+
impl Tr for C {}
10+
11+
trait Tr2<S> = Into<S>;
12+
13+
fn foo2<T: Tr2<()>>() {}
14+
15+
fn foo() -> impl Tr {
16+
let x = foo2::<_>();
17+
18+
match true {
19+
true => B,
20+
false => C,
21+
//~^ `match` arms have incompatible types
22+
}
23+
}
24+
25+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
error[E0308]: `match` arms have incompatible types
2+
--> $DIR/issue-101465.rs:20:18
3+
|
4+
LL | / match true {
5+
LL | | true => B,
6+
| | - this is found to be of type `B`
7+
LL | | false => C,
8+
| | ^ expected struct `B`, found struct `C`
9+
LL | |
10+
LL | | }
11+
| |_____- `match` arms have incompatible types
12+
|
13+
help: you could change the return type to be a boxed trait object
14+
|
15+
LL | fn foo() -> Box<dyn Tr> {
16+
| ~~~~~~~ +
17+
help: if you change the return type to expect trait objects, box the returned expressions
18+
|
19+
LL ~ true => Box::new(B),
20+
LL ~ false => Box::new(C),
21+
|
22+
23+
error: aborting due to previous error
24+
25+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)
Please sign in to comment.