1
1
use crate :: coercion:: { AsCoercionSite , CoerceMany } ;
2
2
use crate :: { Diverges , Expectation , FnCtxt , Needs } ;
3
3
use 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 } ;
9
7
use rustc_hir_pretty:: ty_to_string;
10
8
use rustc_infer:: infer:: type_variable:: { TypeVariableOrigin , TypeVariableOriginKind } ;
11
- use rustc_infer:: traits:: Obligation ;
12
9
use rustc_middle:: ty:: { self , Ty } ;
13
10
use rustc_span:: Span ;
14
- use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt ;
15
11
use rustc_trait_selection:: traits:: {
16
12
IfExpressionCause , MatchExpressionArmCause , ObligationCause , ObligationCauseCode ,
17
13
} ;
@@ -91,10 +87,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
91
87
92
88
let arm_ty = self . check_expr_with_expectation ( arm. body , expected) ;
93
89
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) ;
98
92
99
93
let ( arm_block_id, arm_span) = if let hir:: ExprKind :: Block ( blk, _) = arm. body . kind {
100
94
( Some ( blk. hir_id ) , self . find_block_span ( blk) )
@@ -120,7 +114,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
120
114
scrut_span : scrut. span ,
121
115
source : match_src,
122
116
prior_non_diverging_arms : prior_non_diverging_arms. clone ( ) ,
123
- opt_suggest_box_span ,
117
+ tail_defines_return_position_impl_trait ,
124
118
} ) ) ,
125
119
) ,
126
120
} ;
@@ -422,7 +416,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
422
416
else_expr : & ' tcx hir:: Expr < ' tcx > ,
423
417
then_ty : Ty < ' tcx > ,
424
418
else_ty : Ty < ' tcx > ,
425
- opt_suggest_box_span : Option < Span > ,
419
+ tail_defines_return_position_impl_trait : Option < LocalDefId > ,
426
420
) -> ObligationCause < ' tcx > {
427
421
let mut outer_span = if self . tcx . sess . source_map ( ) . is_multiline ( span) {
428
422
// 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> {
513
507
then_ty,
514
508
else_ty,
515
509
outer_span,
516
- opt_suggest_box_span ,
510
+ tail_defines_return_position_impl_trait ,
517
511
} ) ) ,
518
512
)
519
513
}
@@ -593,96 +587,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
593
587
}
594
588
}
595
589
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 (
600
595
& 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 ;
685
619
}
620
+ Some ( def_id)
686
621
}
687
622
}
688
623
0 commit comments