@@ -6,6 +6,7 @@ use crate::hir::def_id::DefId;
6
6
use crate :: hir:: GenericArg ;
7
7
use rustc_hir as hir;
8
8
use rustc_infer:: infer:: { self , InferOk } ;
9
+ use rustc_infer:: traits:: EvaluationResult ;
9
10
use rustc_middle:: traits:: { ObligationCauseCode , UnifyReceiverContext } ;
10
11
use rustc_middle:: ty:: adjustment:: { Adjust , Adjustment , PointerCast } ;
11
12
use rustc_middle:: ty:: adjustment:: { AllowTwoPhase , AutoBorrow , AutoBorrowMutability } ;
@@ -14,7 +15,9 @@ use rustc_middle::ty::subst::{self, Subst, SubstsRef};
14
15
use rustc_middle:: ty:: { self , GenericParamDefKind , Ty } ;
15
16
use rustc_span:: Span ;
16
17
use rustc_trait_selection:: traits;
18
+ use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt ;
17
19
20
+ use std:: collections:: hash_map:: Entry ;
18
21
use std:: ops:: Deref ;
19
22
20
23
struct ConfirmContext < ' a , ' tcx > {
@@ -55,6 +58,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
55
58
let mut confirm_cx = ConfirmContext :: new ( self , span, self_expr, call_expr) ;
56
59
confirm_cx. confirm ( unadjusted_self_ty, pick, segment)
57
60
}
61
+
62
+ fn apply_adjustments_for_sized_bound (
63
+ & self ,
64
+ expr : & hir:: Expr < ' tcx > ,
65
+ adj : Vec < Adjustment < ' tcx > > ,
66
+ ) {
67
+ debug ! ( "apply_adjustments_for_sized_bound(expr={:?}, adj={:?})" , expr, adj) ;
68
+ if adj. is_empty ( ) {
69
+ return ;
70
+ }
71
+
72
+ match self . typeck_results . borrow_mut ( ) . adjustments_mut ( ) . entry ( expr. hir_id ) {
73
+ Entry :: Vacant ( entry) => {
74
+ entry. insert ( adj) ;
75
+ }
76
+ Entry :: Occupied ( mut entry) => {
77
+ * entry. get_mut ( ) = adj;
78
+ }
79
+ }
80
+ }
58
81
}
59
82
60
83
impl < ' a , ' tcx > ConfirmContext < ' a , ' tcx > {
@@ -74,16 +97,12 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
74
97
segment : & hir:: PathSegment < ' _ > ,
75
98
) -> ConfirmResult < ' tcx > {
76
99
// Adjust the self expression the user provided and obtain the adjusted type.
77
- let self_ty = self . adjust_self_ty ( unadjusted_self_ty, & pick) ;
78
-
79
- // Create substitutions for the method's type parameters.
80
- let rcvr_substs = self . fresh_receiver_substs ( self_ty, & pick) ;
81
- let all_substs = self . instantiate_method_substs ( & pick, segment, rcvr_substs) ;
82
-
83
- debug ! ( "all_substs={:?}" , all_substs) ;
100
+ let ( adjusted_self_ty, autoderef_obligations) =
101
+ self . adjust_self_ty ( unadjusted_self_ty, & pick, FnCtxt :: apply_adjustments) ;
84
102
85
103
// Create the final signature for the method, replacing late-bound regions.
86
- let ( method_sig, method_predicates) = self . instantiate_method_sig ( & pick, all_substs) ;
104
+ let ( all_substs, method_sig, method_predicates) =
105
+ self . create_substs_and_instantiate_method_sig ( adjusted_self_ty, & pick, segment) ;
87
106
88
107
// Unify the (adjusted) self type with what the method expects.
89
108
//
@@ -92,15 +111,16 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
92
111
// could alter our Self-type, except for normalizing the receiver from the
93
112
// signature (which is also done during probing).
94
113
let method_sig_rcvr = self . normalize_associated_types_in ( self . span , method_sig. inputs ( ) [ 0 ] ) ;
95
- debug ! (
96
- "confirm: self_ty={:?} method_sig_rcvr={:?} method_sig={:?} method_predicates={:?}" ,
97
- self_ty, method_sig_rcvr, method_sig, method_predicates
98
- ) ;
99
- self . unify_receivers ( self_ty, method_sig_rcvr, & pick, all_substs) ;
114
+ self . unify_receivers ( adjusted_self_ty, method_sig_rcvr, & pick, all_substs) ;
100
115
101
116
let ( method_sig, method_predicates) =
102
117
self . normalize_associated_types_in ( self . span , ( method_sig, method_predicates) ) ;
103
118
119
+ debug ! (
120
+ "confirm: adjusted_self_ty={:?} method_sig_rcvr={:?} method_sig={:?} method_predicates={:?}" ,
121
+ adjusted_self_ty, method_sig_rcvr, method_sig, method_predicates
122
+ ) ;
123
+
104
124
// Make sure nobody calls `drop()` explicitly.
105
125
self . enforce_illegal_method_limitations ( & pick) ;
106
126
@@ -114,12 +134,31 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
114
134
// appropriate hint suggesting to import the trait.
115
135
let illegal_sized_bound = self . predicates_require_illegal_sized_bound ( & method_predicates) ;
116
136
117
- // Add any trait/regions obligations specified on the method's type parameters.
118
- // We won't add these if we encountered an illegal sized bound, so that we can use
119
- // a custom error in that case.
120
- if illegal_sized_bound. is_none ( ) {
121
- let method_ty = self . tcx . mk_fn_ptr ( ty:: Binder :: bind ( method_sig) ) ;
122
- self . add_obligations ( method_ty, all_substs, method_predicates) ;
137
+ match illegal_sized_bound {
138
+ Some ( _) => {
139
+ // try to autoref receiver to fulfill sized bound (see issue #82825 for an example of
140
+ // why this might be necessary)
141
+ if let Some ( sized_confirm_result) = self . try_autoref_for_sized_bound (
142
+ unadjusted_self_ty,
143
+ method_sig_rcvr,
144
+ pick. clone ( ) ,
145
+ & segment,
146
+ ) {
147
+ return sized_confirm_result;
148
+ }
149
+ }
150
+ None => {
151
+ // We only register predicates from adjusting `self_ty` now, since these
152
+ // obligations might violate those found in a successful call of
153
+ // `try_autoref_for_sized_bound
154
+ self . register_predicates ( autoderef_obligations) ;
155
+
156
+ // Add any trait/regions obligations specified on the method's type parameters.
157
+ // We won't add these if we encountered an illegal sized bound, so that we can use
158
+ // a custom error in that case.
159
+ let method_ty = self . tcx . mk_fn_ptr ( ty:: Binder :: bind ( method_sig) ) ;
160
+ self . add_obligations ( method_ty, all_substs, method_predicates) ;
161
+ }
123
162
}
124
163
125
164
// Create the final `MethodCallee`.
@@ -134,17 +173,21 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
134
173
& mut self ,
135
174
unadjusted_self_ty : Ty < ' tcx > ,
136
175
pick : & probe:: Pick < ' tcx > ,
137
- ) -> Ty < ' tcx > {
176
+ apply_adjustments : fn ( & FnCtxt < ' a , ' tcx > , & hir:: Expr < ' tcx > , Vec < Adjustment < ' tcx > > ) -> ( ) ,
177
+ ) -> ( Ty < ' tcx > , Vec < traits:: PredicateObligation < ' tcx > > ) {
138
178
// Commit the autoderefs by calling `autoderef` again, but this
139
179
// time writing the results into the various typeck results.
140
180
let mut autoderef =
141
181
self . autoderef_overloaded_span ( self . span , unadjusted_self_ty, self . call_expr . span ) ;
142
182
let ( _, n) = match autoderef. nth ( pick. autoderefs ) {
143
183
Some ( n) => n,
144
184
None => {
145
- return self . tcx . ty_error_with_message (
146
- rustc_span:: DUMMY_SP ,
147
- & format ! ( "failed autoderef {}" , pick. autoderefs) ,
185
+ return (
186
+ self . tcx . ty_error_with_message (
187
+ rustc_span:: DUMMY_SP ,
188
+ & format ! ( "failed autoderef {}" , pick. autoderefs) ,
189
+ ) ,
190
+ vec ! [ ] ,
148
191
) ;
149
192
}
150
193
} ;
@@ -197,12 +240,12 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
197
240
None => { }
198
241
}
199
242
200
- self . register_predicates ( autoderef. into_obligations ( ) ) ;
243
+ let autoderef_obligations = autoderef. into_obligations ( ) ;
201
244
202
245
// Write out the final adjustments.
203
- self . apply_adjustments ( self . self_expr , adjustments) ;
246
+ apply_adjustments ( self , self . self_expr , adjustments) ;
204
247
205
- target
248
+ ( target, autoderef_obligations )
206
249
}
207
250
208
251
/// Returns a set of substitutions for the method *receiver* where all type and region
@@ -557,4 +600,159 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
557
600
{
558
601
self . fcx . replace_bound_vars_with_fresh_vars ( self . span , infer:: FnCall , value) . 0
559
602
}
603
+
604
+ fn create_substs_and_instantiate_method_sig (
605
+ & mut self ,
606
+ self_ty : Ty < ' tcx > ,
607
+ pick : & probe:: Pick < ' tcx > ,
608
+ segment : & hir:: PathSegment < ' _ > ,
609
+ ) -> ( SubstsRef < ' tcx > , ty:: FnSig < ' tcx > , ty:: InstantiatedPredicates < ' tcx > ) {
610
+ // Create substitutions for the method's type parameters.
611
+ let rcvr_substs = self . fresh_receiver_substs ( self_ty, & pick) ;
612
+ let all_substs = self . instantiate_method_substs ( pick, segment, rcvr_substs) ;
613
+
614
+ debug ! ( "all_substs={:?}" , all_substs) ;
615
+
616
+ // Create the final signature for the method, replacing late-bound regions.
617
+ let ( method_sig, method_predicates) = self . instantiate_method_sig ( pick, all_substs) ;
618
+
619
+ ( all_substs, method_sig, method_predicates)
620
+ }
621
+
622
+ /// In situations in which we have a trait method that takes a reference receiver type,
623
+ /// a Self : Sized bound and a trait implementation for a reference type, the adjustments
624
+ /// that the compiler applies in `ProbeMode::Normal` are insufficient to fulfill the Sized bound.
625
+ /// Example:
626
+ ///
627
+ /// ```
628
+ /// trait Trait {
629
+ /// fn foo(&self) where Self: Sized;
630
+ ///
631
+ /// impl<T: ?Sized + Trait> Trait for &T {
632
+ /// fn foo(&self) where Self: Sized {
633
+ /// ...
634
+ /// }
635
+ ///
636
+ /// fn bar(x: &dyn Trait) {
637
+ /// // The compiler needs to include an additional autoref here, a Deref -> Borrow adjustment
638
+ /// // will not pick the correct trait implementation
639
+ /// x.foo()
640
+ /// ```
641
+ ///
642
+ /// Specifically in `ProbeMode::Normal` we deref to the base type and then autoref once,
643
+ /// which fulfills the reference receiver type, but violates the `Sized` bound on `Self`.
644
+ /// In order to generate the correct predicate (i.e. <&dyn Trait as Trait> we try create a
645
+ /// `&&` receiver type during method probing, try to confirm the probe and see if all obligations hold.
646
+ /// See issue #82825 for further details.
647
+ fn try_autoref_for_sized_bound (
648
+ & mut self ,
649
+ unadjusted_self_ty : Ty < ' tcx > ,
650
+ method_rcvr : Ty < ' tcx > ,
651
+ pick : probe:: Pick < ' tcx > ,
652
+ segment : & hir:: PathSegment < ' _ > ,
653
+ ) -> Option < ConfirmResult < ' tcx > > {
654
+ debug ! (
655
+ "try_autoref_for_sized_bound(unadjusted_self_ty: {:?}, pick: {:?}" ,
656
+ unadjusted_self_ty, pick
657
+ ) ;
658
+
659
+ // methods that move dyn values always violate sized constraint.
660
+ match method_rcvr. kind ( ) {
661
+ ty:: Ref ( _, _, _) => { }
662
+ _ => {
663
+ return None ;
664
+ }
665
+ }
666
+
667
+ let mode = probe:: Mode :: MethodCall ;
668
+ let self_ty = self . resolve_vars_if_possible ( unadjusted_self_ty) ;
669
+
670
+ let mut new_pick = match self . probe_for_name_with_sized_bound (
671
+ self . span ,
672
+ mode,
673
+ segment. ident ,
674
+ probe:: IsSuggestion ( false ) ,
675
+ self_ty,
676
+ self . call_expr . hir_id ,
677
+ probe:: ProbeScope :: TraitsInScope ,
678
+ ) {
679
+ Ok ( new_pick) => new_pick,
680
+ _ => {
681
+ return None ;
682
+ }
683
+ } ;
684
+
685
+ debug ! ( "new_pick: {:?}" , new_pick) ;
686
+
687
+ // Note: The previous, failed `confirm` call already set adjustments in `self.typeck_results`.
688
+ // Since `TyCtxt::apply_adjustments` cannot compose `Borrow` adjustments on top of previous
689
+ // adjustments, which do not contain `Deref` adjustments, we need to use
690
+ // `FnCtxt::apply_adjustments_for_sized_bound` to apply the adjustments generated by
691
+ // `probe_for_name_with_sized_bound`.
692
+ let ( adjusted_self_ty, autoderef_obligations) = self . adjust_self_ty (
693
+ unadjusted_self_ty,
694
+ & mut new_pick,
695
+ FnCtxt :: apply_adjustments_for_sized_bound,
696
+ ) ;
697
+ debug ! (
698
+ "try_autoref_for_sized_bound: self_ty after adjust_self_ty call is {:?}" ,
699
+ adjusted_self_ty
700
+ ) ;
701
+
702
+ // Create the final signature for the method, replacing late-bound regions.
703
+ let ( all_substs, method_sig, method_predicates) =
704
+ self . create_substs_and_instantiate_method_sig ( adjusted_self_ty, & new_pick, segment) ;
705
+
706
+ // Unify the (adjusted) self type with what the method expects.
707
+ //
708
+ // SUBTLE: if we want good error messages, because of "guessing" while matching
709
+ // traits, no trait system method can be called before this point because they
710
+ // could alter our Self-type, except for normalizing the receiver from the
711
+ // signature (which is also done during probing).
712
+ let method_sig_rcvr = self . normalize_associated_types_in ( self . span , method_sig. inputs ( ) [ 0 ] ) ;
713
+ self . unify_receivers ( adjusted_self_ty, method_sig_rcvr, & new_pick, all_substs) ;
714
+
715
+ let ( method_sig, method_predicates) =
716
+ self . normalize_associated_types_in ( self . span , ( method_sig, method_predicates) ) ;
717
+
718
+ debug ! ( "method_sig {:?}, predicates: {:?}" , method_sig, method_predicates) ;
719
+
720
+ let cause = traits:: ObligationCause :: misc ( self . span , self . body_id ) ;
721
+ let obligations_satisfied =
722
+ traits:: predicates_for_generics ( cause, self . param_env , method_predicates. clone ( ) ) . all (
723
+ |o| {
724
+ debug ! ( "obligation: {:?}" , o) ;
725
+ let eval_result = self . infcx . evaluate_obligation ( & o) ;
726
+ debug ! ( "evaluation result: {:?}" , eval_result) ;
727
+ match eval_result {
728
+ Ok ( EvaluationResult :: EvaluatedToOk )
729
+ | Ok ( EvaluationResult :: EvaluatedToOkModuloRegions ) => true ,
730
+ _ => false ,
731
+ }
732
+ } ,
733
+ ) ;
734
+
735
+ if !obligations_satisfied {
736
+ return None ;
737
+ }
738
+
739
+ self . enforce_illegal_method_limitations ( & new_pick) ;
740
+ let illegal_sized_bound = self . predicates_require_illegal_sized_bound ( & method_predicates) ;
741
+
742
+ match illegal_sized_bound {
743
+ Some ( _) => {
744
+ return None ;
745
+ }
746
+ None => {
747
+ self . register_predicates ( autoderef_obligations) ;
748
+ let method_ty = self . tcx . mk_fn_ptr ( ty:: Binder :: bind ( method_sig) ) ;
749
+ self . add_obligations ( method_ty, all_substs, method_predicates) ;
750
+ }
751
+ }
752
+
753
+ // Create the final `MethodCallee`.
754
+ let callee =
755
+ MethodCallee { def_id : new_pick. item . def_id , substs : all_substs, sig : method_sig } ;
756
+ Some ( ConfirmResult { callee, illegal_sized_bound } )
757
+ }
560
758
}
0 commit comments