@@ -38,6 +38,7 @@ use rustc_infer::infer;
38
38
use rustc_infer:: infer:: type_variable:: { TypeVariableOrigin , TypeVariableOriginKind } ;
39
39
use rustc_infer:: infer:: DefineOpaqueTypes ;
40
40
use rustc_infer:: infer:: InferOk ;
41
+ use rustc_infer:: traits:: query:: NoSolution ;
41
42
use rustc_infer:: traits:: ObligationCause ;
42
43
use rustc_middle:: middle:: stability;
43
44
use rustc_middle:: ty:: adjustment:: { Adjust , Adjustment , AllowTwoPhase } ;
@@ -53,6 +54,8 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
53
54
use rustc_target:: abi:: FieldIdx ;
54
55
use rustc_target:: spec:: abi:: Abi :: RustIntrinsic ;
55
56
use rustc_trait_selection:: infer:: InferCtxtExt ;
57
+ use rustc_trait_selection:: traits:: error_reporting:: TypeErrCtxtExt ;
58
+ use rustc_trait_selection:: traits:: ObligationCtxt ;
56
59
use rustc_trait_selection:: traits:: { self , ObligationCauseCode } ;
57
60
58
61
impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
@@ -2800,6 +2803,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2800
2803
element_ty
2801
2804
}
2802
2805
None => {
2806
+ // Attempt to *shallowly* search for an impl which matches,
2807
+ // but has nested obligations which are unsatisfied.
2808
+ for ( base_t, _) in self . autoderef ( base. span , base_t) . silence_errors ( ) {
2809
+ if let Some ( ( _, index_ty, element_ty) ) =
2810
+ self . find_and_report_unsatisfied_index_impl ( expr. hir_id , base, base_t)
2811
+ {
2812
+ self . demand_coerce ( idx, idx_t, index_ty, None , AllowTwoPhase :: No ) ;
2813
+ return element_ty;
2814
+ }
2815
+ }
2816
+
2803
2817
let mut err = type_error_struct ! (
2804
2818
self . tcx. sess,
2805
2819
expr. span,
@@ -2843,6 +2857,82 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2843
2857
}
2844
2858
}
2845
2859
2860
+ /// Try to match an implementation of `Index` against a self type, and report
2861
+ /// the unsatisfied predicates that result from confirming this impl.
2862
+ ///
2863
+ /// Given an index expression, sometimes the `Self` type shallowly but does not
2864
+ /// deeply satisfy an impl predicate. Instead of simply saying that the type
2865
+ /// does not support being indexed, we want to point out exactly what nested
2866
+ /// predicates cause this to be, so that the user can add them to fix their code.
2867
+ fn find_and_report_unsatisfied_index_impl (
2868
+ & self ,
2869
+ index_expr_hir_id : HirId ,
2870
+ base_expr : & hir:: Expr < ' _ > ,
2871
+ base_ty : Ty < ' tcx > ,
2872
+ ) -> Option < ( ErrorGuaranteed , Ty < ' tcx > , Ty < ' tcx > ) > {
2873
+ let index_trait_def_id = self . tcx . lang_items ( ) . index_trait ( ) ?;
2874
+ let index_trait_output_def_id = self . tcx . get_diagnostic_item ( sym:: IndexOutput ) ?;
2875
+
2876
+ let mut relevant_impls = vec ! [ ] ;
2877
+ self . tcx . for_each_relevant_impl ( index_trait_def_id, base_ty, |impl_def_id| {
2878
+ relevant_impls. push ( impl_def_id) ;
2879
+ } ) ;
2880
+ let [ impl_def_id] = relevant_impls[ ..] else {
2881
+ // Only report unsatisfied impl predicates if there's one impl
2882
+ return None ;
2883
+ } ;
2884
+
2885
+ self . commit_if_ok ( |_| {
2886
+ let ocx = ObligationCtxt :: new_in_snapshot ( self ) ;
2887
+ let impl_substs = self . fresh_substs_for_item ( base_expr. span , impl_def_id) ;
2888
+ let impl_trait_ref =
2889
+ self . tcx . impl_trait_ref ( impl_def_id) . unwrap ( ) . subst ( self . tcx , impl_substs) ;
2890
+ let cause = self . misc ( base_expr. span ) ;
2891
+
2892
+ // Match the impl self type against the base ty. If this fails,
2893
+ // we just skip this impl, since it's not particularly useful.
2894
+ let impl_trait_ref = ocx. normalize ( & cause, self . param_env , impl_trait_ref) ;
2895
+ ocx. eq ( & cause, self . param_env , impl_trait_ref. self_ty ( ) , base_ty) ?;
2896
+
2897
+ // Register the impl's predicates. One of these predicates
2898
+ // must be unsatisfied, or else we wouldn't have gotten here
2899
+ // in the first place.
2900
+ ocx. register_obligations ( traits:: predicates_for_generics (
2901
+ |idx, span| {
2902
+ traits:: ObligationCause :: new (
2903
+ base_expr. span ,
2904
+ self . body_id ,
2905
+ if span. is_dummy ( ) {
2906
+ traits:: ExprItemObligation ( impl_def_id, index_expr_hir_id, idx)
2907
+ } else {
2908
+ traits:: ExprBindingObligation ( impl_def_id, span, index_expr_hir_id, idx)
2909
+ } ,
2910
+ )
2911
+ } ,
2912
+ self . param_env ,
2913
+ self . tcx . predicates_of ( impl_def_id) . instantiate ( self . tcx , impl_substs) ,
2914
+ ) ) ;
2915
+
2916
+ // Normalize the output type, which we can use later on as the
2917
+ // return type of the index expression...
2918
+ let element_ty = ocx. normalize (
2919
+ & cause,
2920
+ self . param_env ,
2921
+ self . tcx . mk_projection ( index_trait_output_def_id, impl_trait_ref. substs ) ,
2922
+ ) ;
2923
+
2924
+ let errors = ocx. select_where_possible ( ) ;
2925
+ // There should be at least one error reported. If not, we
2926
+ // will still delay a span bug in `report_fulfillment_errors`.
2927
+ Ok :: < _ , NoSolution > ( (
2928
+ self . err_ctxt ( ) . report_fulfillment_errors ( & errors) ,
2929
+ impl_trait_ref. substs . type_at ( 1 ) ,
2930
+ element_ty,
2931
+ ) )
2932
+ } )
2933
+ . ok ( )
2934
+ }
2935
+
2846
2936
fn point_at_index_if_possible (
2847
2937
& self ,
2848
2938
errors : & mut Vec < traits:: FulfillmentError < ' tcx > > ,
0 commit comments