@@ -6,6 +6,7 @@ use crate::hir::def_id::DefId;
66use crate :: hir:: GenericArg ;
77use rustc_hir as hir;
88use rustc_infer:: infer:: { self , InferOk } ;
9+ use rustc_infer:: traits:: EvaluationResult ;
910use rustc_middle:: traits:: { ObligationCauseCode , UnifyReceiverContext } ;
1011use rustc_middle:: ty:: adjustment:: { Adjust , Adjustment , PointerCast } ;
1112use rustc_middle:: ty:: adjustment:: { AllowTwoPhase , AutoBorrow , AutoBorrowMutability } ;
@@ -14,7 +15,9 @@ use rustc_middle::ty::subst::{self, Subst, SubstsRef};
1415use rustc_middle:: ty:: { self , GenericParamDefKind , Ty } ;
1516use rustc_span:: Span ;
1617use rustc_trait_selection:: traits;
18+ use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt ;
1719
20+ use std:: collections:: hash_map:: Entry ;
1821use std:: ops:: Deref ;
1922
2023struct ConfirmContext < ' a , ' tcx > {
@@ -55,6 +58,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
5558 let mut confirm_cx = ConfirmContext :: new ( self , span, self_expr, call_expr) ;
5659 confirm_cx. confirm ( unadjusted_self_ty, pick, segment)
5760 }
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+ }
5881}
5982
6083impl < ' a , ' tcx > ConfirmContext < ' a , ' tcx > {
@@ -74,16 +97,12 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
7497 segment : & hir:: PathSegment < ' _ > ,
7598 ) -> ConfirmResult < ' tcx > {
7699 // 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) ;
84102
85103 // 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) ;
87106
88107 // Unify the (adjusted) self type with what the method expects.
89108 //
@@ -92,15 +111,16 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
92111 // could alter our Self-type, except for normalizing the receiver from the
93112 // signature (which is also done during probing).
94113 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) ;
100115
101116 let ( method_sig, method_predicates) =
102117 self . normalize_associated_types_in ( self . span , ( method_sig, method_predicates) ) ;
103118
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+
104124 // Make sure nobody calls `drop()` explicitly.
105125 self . enforce_illegal_method_limitations ( & pick) ;
106126
@@ -114,12 +134,31 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
114134 // appropriate hint suggesting to import the trait.
115135 let illegal_sized_bound = self . predicates_require_illegal_sized_bound ( & method_predicates) ;
116136
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+ }
123162 }
124163
125164 // Create the final `MethodCallee`.
@@ -134,17 +173,21 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
134173 & mut self ,
135174 unadjusted_self_ty : Ty < ' tcx > ,
136175 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 > > ) {
138178 // Commit the autoderefs by calling `autoderef` again, but this
139179 // time writing the results into the various typeck results.
140180 let mut autoderef =
141181 self . autoderef_overloaded_span ( self . span , unadjusted_self_ty, self . call_expr . span ) ;
142182 let ( _, n) = match autoderef. nth ( pick. autoderefs ) {
143183 Some ( n) => n,
144184 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 ! [ ] ,
148191 ) ;
149192 }
150193 } ;
@@ -197,12 +240,12 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
197240 None => { }
198241 }
199242
200- self . register_predicates ( autoderef. into_obligations ( ) ) ;
243+ let autoderef_obligations = autoderef. into_obligations ( ) ;
201244
202245 // Write out the final adjustments.
203- self . apply_adjustments ( self . self_expr , adjustments) ;
246+ apply_adjustments ( self , self . self_expr , adjustments) ;
204247
205- target
248+ ( target, autoderef_obligations )
206249 }
207250
208251 /// Returns a set of substitutions for the method *receiver* where all type and region
@@ -557,4 +600,159 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
557600 {
558601 self . fcx . replace_bound_vars_with_fresh_vars ( self . span , infer:: FnCall , value) . 0
559602 }
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+ }
560758}
0 commit comments