@@ -4,7 +4,7 @@ use rustc_errors::{Applicability, MultiSpan};
44use rustc_hir:: { self as hir, ExprKind } ;
55use rustc_infer:: infer:: type_variable:: { TypeVariableOrigin , TypeVariableOriginKind } ;
66use rustc_infer:: traits:: Obligation ;
7- use rustc_middle:: ty:: { self , ToPredicate , Ty } ;
7+ use rustc_middle:: ty:: { self , Subst , ToPredicate , Ty } ;
88use rustc_span:: Span ;
99use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt ;
1010use 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 }
0 commit comments