@@ -10,14 +10,15 @@ use rustc_hir::HirId;
10
10
use rustc_hir:: def:: DefKind ;
11
11
use rustc_hir_analysis:: autoderef:: { self , Autoderef } ;
12
12
use rustc_infer:: infer:: canonical:: { Canonical , OriginalQueryValues , QueryResponse } ;
13
- use rustc_infer:: infer:: { self , DefineOpaqueTypes , InferOk , TyCtxtInferExt } ;
14
- use rustc_infer:: traits:: ObligationCauseCode ;
13
+ use rustc_infer:: infer:: { self , DefineOpaqueTypes , InferCtxt , InferOk , TyCtxtInferExt } ;
14
+ use rustc_infer:: traits:: solve:: Goal ;
15
+ use rustc_infer:: traits:: { ObligationCauseCode , PredicateObligation } ;
15
16
use rustc_middle:: middle:: stability;
16
17
use rustc_middle:: query:: Providers ;
17
18
use rustc_middle:: ty:: fast_reject:: { TreatParams , simplify_type} ;
18
19
use rustc_middle:: ty:: {
19
20
self , AssocItem , AssocItemContainer , GenericArgs , GenericArgsRef , GenericParamDefKind ,
20
- ParamEnvAnd , Ty , TyCtxt , TypeVisitableExt , Upcast ,
21
+ ParamEnvAnd , PredicateKind , Ty , TyCtxt , TypeVisitableExt , Upcast ,
21
22
} ;
22
23
use rustc_middle:: { bug, span_bug} ;
23
24
use rustc_session:: lint;
@@ -28,6 +29,9 @@ use rustc_span::edit_distance::{
28
29
use rustc_span:: { DUMMY_SP , Ident , Span , Symbol , sym} ;
29
30
use rustc_trait_selection:: error_reporting:: infer:: need_type_info:: TypeAnnotationNeeded ;
30
31
use rustc_trait_selection:: infer:: InferCtxtExt as _;
32
+ use rustc_trait_selection:: solve:: inspect:: {
33
+ InspectConfig , InspectGoal , ProofTreeInferCtxtExt , ProofTreeVisitor ,
34
+ } ;
31
35
use rustc_trait_selection:: traits:: query:: CanonicalTyGoal ;
32
36
use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt ;
33
37
use rustc_trait_selection:: traits:: query:: method_autoderef:: {
@@ -438,7 +442,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
438
442
// If we encountered an `_` type or an error type during autoderef, this is
439
443
// ambiguous.
440
444
if let Some ( bad_ty) = & steps. opt_bad_ty {
441
- if is_suggestion. 0 {
445
+ // Ended up encountering a type variable when doing autoderef,
446
+ // but it may not be a type variable after processing obligations
447
+ // in our local `FnCtxt`, so don't call `structurally_resolve_type`.
448
+ let ty = & bad_ty. ty ;
449
+ let ty = self
450
+ . probe_instantiate_query_response ( span, & orig_values, ty)
451
+ . unwrap_or_else ( |_| span_bug ! ( span, "instantiating {:?} failed?" , ty) ) ;
452
+ if bad_ty. is_opaque_type
453
+ || final_ty_is_opaque (
454
+ & self . infcx ,
455
+ & self . fulfillment_cx . borrow ( ) . pending_obligations ( ) ,
456
+ ty. value ,
457
+ )
458
+ {
459
+ // FIXME(-Znext-solver): This isn't really what we want :<
460
+ assert ! ( self . tcx. next_trait_solver_globally( ) ) ;
461
+ } else if is_suggestion. 0 {
442
462
// Ambiguity was encountered during a suggestion. There's really
443
463
// not much use in suggesting methods in this case.
444
464
return Err ( MethodError :: NoMatch ( NoMatchData {
@@ -464,13 +484,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
464
484
} ,
465
485
) ;
466
486
} else {
467
- // Ended up encountering a type variable when doing autoderef,
468
- // but it may not be a type variable after processing obligations
469
- // in our local `FnCtxt`, so don't call `structurally_resolve_type`.
470
- let ty = & bad_ty. ty ;
471
- let ty = self
472
- . probe_instantiate_query_response ( span, & orig_values, ty)
473
- . unwrap_or_else ( |_| span_bug ! ( span, "instantiating {:?} failed?" , ty) ) ;
474
487
let ty = self . resolve_vars_if_possible ( ty. value ) ;
475
488
let guar = match * ty. kind ( ) {
476
489
ty:: Infer ( ty:: TyVar ( _) ) => {
@@ -578,60 +591,78 @@ fn method_autoderef_steps<'tcx>(
578
591
let mut reached_raw_pointer = false ;
579
592
let arbitrary_self_types_enabled =
580
593
tcx. features ( ) . arbitrary_self_types ( ) || tcx. features ( ) . arbitrary_self_types_pointers ( ) ;
581
- let ( mut steps, reached_recursion_limit) : ( Vec < _ > , bool ) = if arbitrary_self_types_enabled {
582
- let reachable_via_deref =
583
- autoderef_via_deref. by_ref ( ) . map ( |_| true ) . chain ( std:: iter:: repeat ( false ) ) ;
584
-
585
- let mut autoderef_via_receiver =
586
- Autoderef :: new ( infcx, param_env, hir:: def_id:: CRATE_DEF_ID , DUMMY_SP , self_ty)
587
- . include_raw_pointers ( )
588
- . use_receiver_trait ( )
589
- . silence_errors ( ) ;
590
- let steps = autoderef_via_receiver
591
- . by_ref ( )
592
- . zip ( reachable_via_deref)
593
- . map ( |( ( ty, d) , reachable_via_deref) | {
594
- let step = CandidateStep {
595
- self_ty : infcx
596
- . make_query_response_ignoring_pending_obligations ( inference_vars, ty) ,
597
- autoderefs : d,
598
- from_unsafe_deref : reached_raw_pointer,
599
- unsize : false ,
600
- reachable_via_deref,
601
- } ;
602
- if ty. is_unsafe_ptr ( ) {
603
- // all the subsequent steps will be from_unsafe_deref
604
- reached_raw_pointer = true ;
605
- }
606
- step
607
- } )
608
- . collect ( ) ;
609
- ( steps, autoderef_via_receiver. reached_recursion_limit ( ) )
610
- } else {
611
- let steps = autoderef_via_deref
612
- . by_ref ( )
613
- . map ( |( ty, d) | {
614
- let step = CandidateStep {
615
- self_ty : infcx
616
- . make_query_response_ignoring_pending_obligations ( inference_vars, ty) ,
617
- autoderefs : d,
618
- from_unsafe_deref : reached_raw_pointer,
619
- unsize : false ,
620
- reachable_via_deref : true ,
621
- } ;
622
- if ty. is_unsafe_ptr ( ) {
623
- // all the subsequent steps will be from_unsafe_deref
624
- reached_raw_pointer = true ;
625
- }
626
- step
627
- } )
628
- . collect ( ) ;
629
- ( steps, autoderef_via_deref. reached_recursion_limit ( ) )
630
- } ;
631
- let final_ty = autoderef_via_deref. final_ty ( true ) ;
594
+ let ( mut steps, final_ty, reached_recursion_limit, obligations) =
595
+ if arbitrary_self_types_enabled {
596
+ let reachable_via_deref =
597
+ autoderef_via_deref. by_ref ( ) . map ( |_| true ) . chain ( std:: iter:: repeat ( false ) ) ;
598
+
599
+ let mut autoderef_via_receiver =
600
+ Autoderef :: new ( infcx, param_env, hir:: def_id:: CRATE_DEF_ID , DUMMY_SP , self_ty)
601
+ . include_raw_pointers ( )
602
+ . use_receiver_trait ( )
603
+ . silence_errors ( ) ;
604
+ let steps: Vec < _ > = autoderef_via_receiver
605
+ . by_ref ( )
606
+ . zip ( reachable_via_deref)
607
+ . map ( |( ( ty, d) , reachable_via_deref) | {
608
+ let step = CandidateStep {
609
+ self_ty : infcx
610
+ . make_query_response_ignoring_pending_obligations ( inference_vars, ty) ,
611
+ autoderefs : d,
612
+ from_unsafe_deref : reached_raw_pointer,
613
+ unsize : false ,
614
+ reachable_via_deref,
615
+ } ;
616
+ if ty. is_unsafe_ptr ( ) {
617
+ // all the subsequent steps will be from_unsafe_deref
618
+ reached_raw_pointer = true ;
619
+ }
620
+ step
621
+ } )
622
+ . collect ( ) ;
623
+ (
624
+ steps,
625
+ // FIXME(arbitrary_self_types): Why do we look at the final type of
626
+ // the `deref` chain here?
627
+ autoderef_via_deref. final_ty ( true ) ,
628
+ autoderef_via_receiver. reached_recursion_limit ( ) ,
629
+ autoderef_via_receiver. into_obligations ( ) ,
630
+ )
631
+ } else {
632
+ let steps = autoderef_via_deref
633
+ . by_ref ( )
634
+ . map ( |( ty, d) | {
635
+ let step = CandidateStep {
636
+ self_ty : infcx
637
+ . make_query_response_ignoring_pending_obligations ( inference_vars, ty) ,
638
+ autoderefs : d,
639
+ from_unsafe_deref : reached_raw_pointer,
640
+ unsize : false ,
641
+ reachable_via_deref : true ,
642
+ } ;
643
+ if ty. is_unsafe_ptr ( ) {
644
+ // all the subsequent steps will be from_unsafe_deref
645
+ reached_raw_pointer = true ;
646
+ }
647
+ step
648
+ } )
649
+ . collect ( ) ;
650
+ (
651
+ steps,
652
+ autoderef_via_deref. final_ty ( true ) ,
653
+ autoderef_via_deref. reached_recursion_limit ( ) ,
654
+ autoderef_via_deref. into_obligations ( ) ,
655
+ )
656
+ } ;
632
657
let opt_bad_ty = match final_ty. kind ( ) {
633
- ty:: Infer ( ty:: TyVar ( _) ) | ty :: Error ( _ ) => Some ( MethodAutoderefBadTy {
658
+ ty:: Infer ( ty:: TyVar ( _) ) => Some ( MethodAutoderefBadTy {
634
659
reached_raw_pointer,
660
+ is_opaque_type : final_ty_is_opaque ( infcx, & obligations, final_ty) ,
661
+ ty : infcx. make_query_response_ignoring_pending_obligations ( inference_vars, final_ty) ,
662
+ } ) ,
663
+ ty:: Error ( _) => Some ( MethodAutoderefBadTy {
664
+ reached_raw_pointer,
665
+ is_opaque_type : false ,
635
666
ty : infcx. make_query_response_ignoring_pending_obligations ( inference_vars, final_ty) ,
636
667
} ) ,
637
668
ty:: Array ( elem_ty, _) => {
@@ -664,6 +695,71 @@ fn method_autoderef_steps<'tcx>(
664
695
}
665
696
}
666
697
698
+ /// Returns `true` in case the final type is the hidden type of an opaque.
699
+ #[ instrument( level = "debug" , skip( infcx) , ret) ]
700
+ fn final_ty_is_opaque < ' tcx > (
701
+ infcx : & InferCtxt < ' tcx > ,
702
+ obligations : & [ PredicateObligation < ' tcx > ] ,
703
+ final_ty : Ty < ' tcx > ,
704
+ ) -> bool {
705
+ // nyaaaa~
706
+ if infcx. next_trait_solver ( ) {
707
+ for obligation in obligations {
708
+ let mut visitor = FinalTyIsOpaque { final_ty, is_opaque_ty : false } ;
709
+ let goal = Goal :: new ( infcx. tcx , obligation. param_env , obligation. predicate ) ;
710
+ infcx. visit_proof_tree ( goal, & mut visitor) ;
711
+ if visitor. is_opaque_ty {
712
+ return true ;
713
+ }
714
+ }
715
+
716
+ let opaque_types = infcx. clone_opaque_types ( ) ;
717
+ for ( key, hidden_ty) in & opaque_types {
718
+ if infcx. shallow_resolve ( hidden_ty. ty ) == final_ty {
719
+ return true ;
720
+ }
721
+ }
722
+ }
723
+
724
+ false
725
+ }
726
+
727
+ struct FinalTyIsOpaque < ' tcx > {
728
+ final_ty : Ty < ' tcx > ,
729
+ is_opaque_ty : bool ,
730
+ }
731
+
732
+ impl < ' tcx > ProofTreeVisitor < ' tcx > for FinalTyIsOpaque < ' tcx > {
733
+ fn span ( & self ) -> Span {
734
+ DUMMY_SP
735
+ }
736
+
737
+ fn config ( & self ) -> InspectConfig {
738
+ // Using an intentionally low depth to avoid potential hangs
739
+ // due to exponentially growing proof trees.
740
+ InspectConfig { max_depth : 5 }
741
+ }
742
+
743
+ fn visit_goal ( & mut self , inspect_goal : & InspectGoal < ' _ , ' tcx > ) {
744
+ let infcx = inspect_goal. infcx ( ) ;
745
+ let goal = inspect_goal. goal ( ) ;
746
+ if let PredicateKind :: NormalizesTo ( ty:: NormalizesTo { alias, term } ) =
747
+ goal. predicate . kind ( ) . skip_binder ( )
748
+ {
749
+ debug ! ( ?alias, ?term, "visiting normalizes-to goal" ) ;
750
+ if term. as_type ( ) . is_some_and ( |ty| ty == self . final_ty )
751
+ && alias. kind ( infcx. tcx ) == ty:: AliasTermKind :: OpaqueTy
752
+ {
753
+ self . is_opaque_ty = true ;
754
+ }
755
+ }
756
+
757
+ if let Some ( candidate) = inspect_goal. unique_applicable_candidate ( ) {
758
+ candidate. visit_nested_in_probe ( self )
759
+ }
760
+ }
761
+ }
762
+
667
763
impl < ' a , ' tcx > ProbeContext < ' a , ' tcx > {
668
764
fn new (
669
765
fcx : & ' a FnCtxt < ' a , ' tcx > ,
@@ -1879,31 +1975,39 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1879
1975
( xform_self_ty, xform_ret_ty) =
1880
1976
self . xform_self_ty ( probe. item , trait_ref. self_ty ( ) , trait_ref. args ) ;
1881
1977
xform_self_ty = ocx. normalize ( cause, self . param_env , xform_self_ty) ;
1882
- match self_ty. kind ( ) {
1883
- // HACK: opaque types will match anything for which their bounds hold.
1884
- // Thus we need to prevent them from trying to match the `&_` autoref
1885
- // candidates that get created for `&self` trait methods.
1886
- ty:: Alias ( ty:: Opaque , alias_ty)
1887
- if !self . next_trait_solver ( )
1888
- && self . infcx . can_define_opaque_ty ( alias_ty. def_id )
1889
- && !xform_self_ty. is_ty_var ( ) =>
1890
- {
1891
- return ProbeResult :: NoMatch ;
1892
- }
1893
- _ => match ocx. relate (
1894
- cause,
1895
- self . param_env ,
1896
- self . variance ( ) ,
1897
- self_ty,
1898
- xform_self_ty,
1899
- ) {
1900
- Ok ( ( ) ) => { }
1901
- Err ( err) => {
1902
- debug ! ( "--> cannot relate self-types {:?}" , err) ;
1978
+
1979
+ // HACK: opaque types will match anything for which their bounds hold.
1980
+ // Thus we need to prevent them from trying to match the `&_` autoref
1981
+ // candidates that get created for `&self` trait methods.
1982
+ if self . mode == Mode :: MethodCall {
1983
+ match self_ty. kind ( ) {
1984
+ ty:: Infer ( ty:: TyVar ( _) ) => {
1985
+ assert ! ( self . infcx. next_trait_solver( ) ) ;
1986
+ if !xform_self_ty. is_ty_var ( ) {
1987
+ return ProbeResult :: NoMatch ;
1988
+ }
1989
+ }
1990
+ ty:: Alias ( ty:: Opaque , alias_ty)
1991
+ if !self . infcx . next_trait_solver ( )
1992
+ && self . infcx . can_define_opaque_ty ( alias_ty. def_id )
1993
+ && !xform_self_ty. is_ty_var ( ) =>
1994
+ {
1995
+ assert ! ( !self . infcx. next_trait_solver( ) ) ;
1903
1996
return ProbeResult :: NoMatch ;
1904
1997
}
1905
- } ,
1998
+ _ => { }
1999
+ }
2000
+ }
2001
+
2002
+ match ocx. relate ( cause, self . param_env , self . variance ( ) , self_ty, xform_self_ty)
2003
+ {
2004
+ Ok ( ( ) ) => { }
2005
+ Err ( err) => {
2006
+ debug ! ( "--> cannot relate self-types {:?}" , err) ;
2007
+ return ProbeResult :: NoMatch ;
2008
+ }
1906
2009
}
2010
+
1907
2011
let obligation = traits:: Obligation :: new (
1908
2012
self . tcx ,
1909
2013
cause. clone ( ) ,
0 commit comments