@@ -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:: {
@@ -137,9 +137,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
137
137
Some ( & arm. body ) ,
138
138
arm_ty,
139
139
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 ; } ;
143
147
let Expectation :: IsLast ( stmt) = orig_expected else {
144
148
return
145
149
} ;
@@ -468,58 +472,77 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
468
472
}
469
473
}
470
474
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.
474
478
pub ( crate ) fn opt_suggest_box_span (
475
479
& self ,
476
480
first_ty : Ty < ' tcx > ,
477
481
second_ty : Ty < ' tcx > ,
478
482
orig_expected : Expectation < ' tcx > ,
479
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.
480
486
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 )
515
525
}
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 ;
517
541
}
518
542
}
519
543
}
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)
523
546
}
524
547
_ => None ,
525
548
}
0 commit comments