@@ -38,6 +38,7 @@ use rustc_infer::infer;
3838use rustc_infer:: infer:: type_variable:: { TypeVariableOrigin , TypeVariableOriginKind } ;
3939use rustc_infer:: infer:: DefineOpaqueTypes ;
4040use rustc_infer:: infer:: InferOk ;
41+ use rustc_infer:: traits:: query:: NoSolution ;
4142use rustc_infer:: traits:: ObligationCause ;
4243use rustc_middle:: middle:: stability;
4344use rustc_middle:: ty:: adjustment:: { Adjust , Adjustment , AllowTwoPhase } ;
@@ -53,6 +54,8 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
5354use rustc_target:: abi:: FieldIdx ;
5455use rustc_target:: spec:: abi:: Abi :: RustIntrinsic ;
5556use rustc_trait_selection:: infer:: InferCtxtExt ;
57+ use rustc_trait_selection:: traits:: error_reporting:: TypeErrCtxtExt ;
58+ use rustc_trait_selection:: traits:: ObligationCtxt ;
5659use rustc_trait_selection:: traits:: { self , ObligationCauseCode } ;
5760
5861impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
@@ -2800,6 +2803,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
28002803 element_ty
28012804 }
28022805 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+
28032817 let mut err = type_error_struct ! (
28042818 self . tcx. sess,
28052819 expr. span,
@@ -2843,6 +2857,82 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
28432857 }
28442858 }
28452859
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+
28462936 fn point_at_index_if_possible (
28472937 & self ,
28482938 errors : & mut Vec < traits:: FulfillmentError < ' tcx > > ,
0 commit comments