11use crate :: coercion:: { AsCoercionSite , CoerceMany } ;
22use crate :: { Diverges , Expectation , FnCtxt , Needs } ;
33use rustc_errors:: { Applicability , Diag } ;
4- use rustc_hir:: {
5- self as hir,
6- def:: { CtorOf , DefKind , Res } ,
7- ExprKind , PatKind ,
8- } ;
4+ use rustc_hir:: def:: { CtorOf , DefKind , Res } ;
5+ use rustc_hir:: def_id:: LocalDefId ;
6+ use rustc_hir:: { self as hir, ExprKind , PatKind } ;
97use rustc_hir_pretty:: ty_to_string;
108use rustc_infer:: infer:: type_variable:: { TypeVariableOrigin , TypeVariableOriginKind } ;
11- use rustc_infer:: traits:: Obligation ;
129use rustc_middle:: ty:: { self , Ty } ;
1310use rustc_span:: Span ;
14- use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt ;
1511use rustc_trait_selection:: traits:: {
1612 IfExpressionCause , MatchExpressionArmCause , ObligationCause , ObligationCauseCode ,
1713} ;
@@ -91,10 +87,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
9187
9288 let arm_ty = self . check_expr_with_expectation ( arm. body , expected) ;
9389 all_arms_diverge &= self . diverges . get ( ) ;
94-
95- let opt_suggest_box_span = prior_arm. and_then ( |( _, prior_arm_ty, _) | {
96- self . opt_suggest_box_span ( prior_arm_ty, arm_ty, orig_expected)
97- } ) ;
90+ let tail_defines_return_position_impl_trait =
91+ self . return_position_impl_trait_from_match_expectation ( orig_expected) ;
9892
9993 let ( arm_block_id, arm_span) = if let hir:: ExprKind :: Block ( blk, _) = arm. body . kind {
10094 ( Some ( blk. hir_id ) , self . find_block_span ( blk) )
@@ -120,7 +114,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
120114 scrut_span : scrut. span ,
121115 source : match_src,
122116 prior_non_diverging_arms : prior_non_diverging_arms. clone ( ) ,
123- opt_suggest_box_span ,
117+ tail_defines_return_position_impl_trait ,
124118 } ) ) ,
125119 ) ,
126120 } ;
@@ -422,7 +416,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
422416 else_expr : & ' tcx hir:: Expr < ' tcx > ,
423417 then_ty : Ty < ' tcx > ,
424418 else_ty : Ty < ' tcx > ,
425- opt_suggest_box_span : Option < Span > ,
419+ tail_defines_return_position_impl_trait : Option < LocalDefId > ,
426420 ) -> ObligationCause < ' tcx > {
427421 let mut outer_span = if self . tcx . sess . source_map ( ) . is_multiline ( span) {
428422 // The `if`/`else` isn't in one line in the output, include some context to make it
@@ -513,7 +507,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
513507 then_ty,
514508 else_ty,
515509 outer_span,
516- opt_suggest_box_span ,
510+ tail_defines_return_position_impl_trait ,
517511 } ) ) ,
518512 )
519513 }
@@ -593,96 +587,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
593587 }
594588 }
595589
596- /// When we have a `match` as a tail expression in a `fn` with a returned `impl Trait`
597- /// we check if the different arms would work with boxed trait objects instead and
598- /// provide a structured suggestion in that case.
599- pub ( crate ) fn opt_suggest_box_span (
590+ // Does the expectation of the match define an RPIT?
591+ // (e.g. we're in the tail of a function body)
592+ //
593+ // Returns the `LocalDefId` of the RPIT, which is always identity-substituted.
594+ pub fn return_position_impl_trait_from_match_expectation (
600595 & self ,
601- first_ty : Ty < ' tcx > ,
602- second_ty : Ty < ' tcx > ,
603- orig_expected : Expectation < ' tcx > ,
604- ) -> Option < Span > {
605- // FIXME(compiler-errors): This really shouldn't need to be done during the
606- // "good" path of typeck, but here we are.
607- match orig_expected {
608- Expectation :: ExpectHasType ( expected) => {
609- let TypeVariableOrigin {
610- span,
611- kind : TypeVariableOriginKind :: OpaqueTypeInference ( rpit_def_id) ,
612- ..
613- } = self . type_var_origin ( expected) ?
614- else {
615- return None ;
616- } ;
617-
618- let Some ( rpit_local_def_id) = rpit_def_id. as_local ( ) else {
619- return None ;
620- } ;
621- if !matches ! (
622- self . tcx. hir( ) . expect_item( rpit_local_def_id) . expect_opaque_ty( ) . origin,
623- hir:: OpaqueTyOrigin :: FnReturn ( ..)
624- ) {
625- return None ;
626- }
627-
628- let sig = self . body_fn_sig ( ) ?;
629-
630- let args = sig. output ( ) . walk ( ) . find_map ( |arg| {
631- if let ty:: GenericArgKind :: Type ( ty) = arg. unpack ( )
632- && let ty:: Alias ( ty:: Opaque , ty:: AliasTy { def_id, args, .. } ) = * ty. kind ( )
633- && def_id == rpit_def_id
634- {
635- Some ( args)
636- } else {
637- None
638- }
639- } ) ?;
640-
641- if !self . can_coerce ( first_ty, expected) || !self . can_coerce ( second_ty, expected) {
642- return None ;
643- }
644-
645- for ty in [ first_ty, second_ty] {
646- for ( clause, _) in self
647- . tcx
648- . explicit_item_super_predicates ( rpit_def_id)
649- . iter_instantiated_copied ( self . tcx , args)
650- {
651- let pred = clause. kind ( ) . rebind ( match clause. kind ( ) . skip_binder ( ) {
652- ty:: ClauseKind :: Trait ( trait_pred) => {
653- assert ! ( matches!(
654- * trait_pred. trait_ref. self_ty( ) . kind( ) ,
655- ty:: Alias ( ty:: Opaque , ty:: AliasTy { def_id, args: alias_args, .. } )
656- if def_id == rpit_def_id && args == alias_args
657- ) ) ;
658- ty:: ClauseKind :: Trait ( trait_pred. with_self_ty ( self . tcx , ty) )
659- }
660- ty:: ClauseKind :: Projection ( mut proj_pred) => {
661- assert ! ( matches!(
662- * proj_pred. projection_ty. self_ty( ) . kind( ) ,
663- ty:: Alias ( ty:: Opaque , ty:: AliasTy { def_id, args: alias_args, .. } )
664- if def_id == rpit_def_id && args == alias_args
665- ) ) ;
666- proj_pred = proj_pred. with_self_ty ( self . tcx , ty) ;
667- ty:: ClauseKind :: Projection ( proj_pred)
668- }
669- _ => continue ,
670- } ) ;
671- if !self . predicate_must_hold_modulo_regions ( & Obligation :: new (
672- self . tcx ,
673- ObligationCause :: misc ( span, self . body_id ) ,
674- self . param_env ,
675- pred,
676- ) ) {
677- return None ;
678- }
679- }
680- }
681-
682- Some ( span)
683- }
684- _ => None ,
596+ expectation : Expectation < ' tcx > ,
597+ ) -> Option < LocalDefId > {
598+ let expected_ty = expectation. to_option ( self ) ?;
599+ let ( def_id, args) = match * expected_ty. kind ( ) {
600+ // FIXME: Could also check that the RPIT is not defined
601+ ty:: Alias ( ty:: Opaque , alias_ty) => ( alias_ty. def_id . as_local ( ) ?, alias_ty. args ) ,
602+ // FIXME(-Znext-solver): Remove this branch once `replace_opaque_types_with_infer` is gone.
603+ ty:: Infer ( ty:: TyVar ( _) ) => self
604+ . inner
605+ . borrow ( )
606+ . iter_opaque_types ( )
607+ . find ( |( _, v) | v. ty == expected_ty)
608+ . map ( |( k, _) | ( k. def_id , k. args ) ) ?,
609+ _ => return None ,
610+ } ;
611+ let hir:: OpaqueTyOrigin :: FnReturn ( parent_def_id) = self . tcx . opaque_type_origin ( def_id)
612+ else {
613+ return None ;
614+ } ;
615+ if & args[ 0 ..self . tcx . generics_of ( parent_def_id) . count ( ) ]
616+ != ty:: GenericArgs :: identity_for_item ( self . tcx , parent_def_id) . as_slice ( )
617+ {
618+ return None ;
685619 }
620+ Some ( def_id)
686621 }
687622}
688623
0 commit comments