@@ -4,7 +4,7 @@ use rustc_errors::{Applicability, MultiSpan};
4
4
use rustc_hir:: { self as hir, ExprKind } ;
5
5
use rustc_infer:: infer:: type_variable:: { TypeVariableOrigin , TypeVariableOriginKind } ;
6
6
use rustc_infer:: traits:: Obligation ;
7
- use rustc_middle:: ty:: { self , ToPredicate , Ty } ;
7
+ use rustc_middle:: ty:: { self , Subst , ToPredicate , Ty } ;
8
8
use rustc_span:: Span ;
9
9
use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt ;
10
10
use rustc_trait_selection:: traits:: {
@@ -143,7 +143,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
143
143
. find_by_def_id ( self . body_id . owner )
144
144
. and_then ( |owner| owner. fn_decl ( ) )
145
145
. map ( |decl| decl. output . span ( ) )
146
- else { return ; } ;
146
+ else { return ; } ;
147
147
let Expectation :: IsLast ( stmt) = orig_expected else {
148
148
return
149
149
} ;
@@ -472,64 +472,77 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
472
472
}
473
473
}
474
474
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.
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.
478
478
pub ( crate ) fn opt_suggest_box_span (
479
479
& self ,
480
480
first_ty : Ty < ' tcx > ,
481
481
second_ty : Ty < ' tcx > ,
482
482
orig_expected : Expectation < ' tcx > ,
483
483
) -> 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.
484
486
match orig_expected {
485
- Expectation :: ExpectHasType ( expected)
486
- if self . in_tail_expr
487
- && self . return_type_has_opaque
488
- && self . can_coerce ( first_ty, expected)
489
- && self . can_coerce ( second_ty, expected) =>
490
- {
491
- let obligations = self . fulfillment_cx . borrow ( ) . pending_obligations ( ) ;
492
- let mut suggest_box = !obligations. is_empty ( ) ;
493
- ' outer: for o in obligations {
494
- for outer_ty in & [ first_ty, second_ty] {
495
- match o. predicate . kind ( ) . skip_binder ( ) {
496
- ty:: PredicateKind :: Trait ( t) => {
497
- let pred = ty:: Binder :: dummy ( ty:: PredicateKind :: Trait (
498
- ty:: TraitPredicate {
499
- trait_ref : ty:: TraitRef {
500
- def_id : t. def_id ( ) ,
501
- substs : self . tcx . mk_substs_trait ( * outer_ty, & [ ] ) ,
502
- } ,
503
- constness : t. constness ,
504
- polarity : t. polarity ,
505
- } ,
506
- ) ) ;
507
- let obl = Obligation :: new (
508
- o. cause . clone ( ) ,
509
- self . param_env ,
510
- pred. to_predicate ( self . tcx ) ,
511
- ) ;
512
- suggest_box &= self . predicate_must_hold_modulo_regions ( & obl) ;
513
- if !suggest_box {
514
- // We've encountered some obligation that didn't hold, so the
515
- // return expression can't just be boxed. We don't need to
516
- // evaluate the rest of the obligations.
517
- break ' outer;
518
- }
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 )
525
+ }
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 )
519
532
}
520
- _ => { }
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 ;
521
541
}
522
542
}
523
543
}
524
- if suggest_box {
525
- self . tcx
526
- . hir ( )
527
- . find_by_def_id ( self . body_id . owner )
528
- . and_then ( |owner| owner. fn_decl ( ) )
529
- . map ( |decl| decl. output . span ( ) )
530
- } else {
531
- None
532
- }
544
+
545
+ Some ( span)
533
546
}
534
547
_ => None ,
535
548
}
0 commit comments