@@ -352,6 +352,14 @@ pub trait TypeErrCtxtExt<'tcx> {
352352 param_env : ty:: ParamEnv < ' tcx > ,
353353 err : & mut Diagnostic ,
354354 ) ;
355+ fn probe_assoc_types_at_expr (
356+ & self ,
357+ type_diffs : & [ TypeError < ' tcx > ] ,
358+ span : Span ,
359+ prev_ty : Ty < ' tcx > ,
360+ body_id : hir:: HirId ,
361+ param_env : ty:: ParamEnv < ' tcx > ,
362+ ) -> Vec < Option < ( Span , ( DefId , Ty < ' tcx > ) ) > > ;
355363}
356364
357365fn predicate_constraint ( generics : & hir:: Generics < ' _ > , pred : ty:: Predicate < ' _ > ) -> ( Span , String ) {
@@ -3152,23 +3160,37 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
31523160 if let ObligationCauseCode :: ExprBindingObligation ( def_id, _, _, idx) = parent_code. deref ( )
31533161 && let predicates = self . tcx . predicates_of ( def_id) . instantiate_identity ( self . tcx )
31543162 && let Some ( pred) = predicates. predicates . get ( * idx)
3155- && let Ok ( trait_pred) = pred. kind ( ) . try_map_bound ( |pred| match pred {
3156- ty:: PredicateKind :: Clause ( ty:: Clause :: Trait ( trait_pred) ) => Ok ( trait_pred) ,
3157- _ => Err ( ( ) ) ,
3158- } )
31593163 {
3160- let mut c = CollectAllMismatches {
3161- infcx : self . infcx ,
3162- param_env,
3163- errors : vec ! [ ] ,
3164- } ;
3165- if let Ok ( trait_predicate) = predicate. kind ( ) . try_map_bound ( |pred| match pred {
3164+ if let Ok ( trait_pred) = pred. kind ( ) . try_map_bound ( |pred| match pred {
31663165 ty:: PredicateKind :: Clause ( ty:: Clause :: Trait ( trait_pred) ) => Ok ( trait_pred) ,
31673166 _ => Err ( ( ) ) ,
3168- } ) {
3167+ } )
3168+ && let Ok ( trait_predicate) = predicate. kind ( ) . try_map_bound ( |pred| match pred {
3169+ ty:: PredicateKind :: Clause ( ty:: Clause :: Trait ( trait_pred) ) => Ok ( trait_pred) ,
3170+ _ => Err ( ( ) ) ,
3171+ } )
3172+ {
3173+ let mut c = CollectAllMismatches {
3174+ infcx : self . infcx ,
3175+ param_env,
3176+ errors : vec ! [ ] ,
3177+ } ;
31693178 if let Ok ( _) = c. relate ( trait_pred, trait_predicate) {
31703179 type_diffs = c. errors ;
31713180 }
3181+ } else if let ty:: PredicateKind :: Clause (
3182+ ty:: Clause :: Projection ( proj)
3183+ ) = pred. kind ( ) . skip_binder ( )
3184+ && let ty:: PredicateKind :: Clause (
3185+ ty:: Clause :: Projection ( projection)
3186+ ) = predicate. kind ( ) . skip_binder ( )
3187+ {
3188+ type_diffs = vec ! [
3189+ Sorts ( ty:: error:: ExpectedFound {
3190+ expected: self . tcx. mk_ty( ty:: Alias ( ty:: Projection , proj. projection_ty) ) ,
3191+ found: projection. term. ty( ) . unwrap( ) ,
3192+ } ) ,
3193+ ] ;
31723194 }
31733195 }
31743196 if let hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( None , path) ) = expr. kind
@@ -3221,10 +3243,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
32213243
32223244 let tcx = self . tcx ;
32233245
3246+ let mut print_root_expr = true ;
32243247 let mut assocs = vec ! [ ] ;
3225- // We still want to point at the different methods even if there hasn't
3226- // been a change of assoc type.
3227- let mut call_spans = vec ! [ ] ;
32283248 let mut expr = expr;
32293249 let mut prev_ty = self . resolve_vars_if_possible (
32303250 typeck_results. expr_ty_adjusted_opt ( expr) . unwrap_or ( tcx. ty_error ( ) ) ,
@@ -3234,64 +3254,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
32343254 // vec![1, 2, 3].iter().map(mapper).sum<i32>()
32353255 // ^^^^^^ ^^^^^^^^^^^
32363256 expr = rcvr_expr;
3237- let mut assocs_in_this_method = Vec :: with_capacity ( type_diffs. len ( ) ) ;
3238- call_spans. push ( span) ;
3239-
3240- let ocx = ObligationCtxt :: new_in_snapshot ( self . infcx ) ;
3241- for diff in & type_diffs {
3242- let Sorts ( expected_found) = diff else { continue ; } ;
3243- let ty:: Alias ( ty:: Projection , proj) = expected_found. expected . kind ( ) else { continue ; } ;
3244-
3245- let origin =
3246- TypeVariableOrigin { kind : TypeVariableOriginKind :: TypeInference , span } ;
3247- let trait_def_id = proj. trait_def_id ( self . tcx ) ;
3248- // Make `Self` be equivalent to the type of the call chain
3249- // expression we're looking at now, so that we can tell what
3250- // for example `Iterator::Item` is at this point in the chain.
3251- let substs = InternalSubsts :: for_item ( self . tcx , trait_def_id, |param, _| {
3252- match param. kind {
3253- ty:: GenericParamDefKind :: Type { .. } => {
3254- if param. index == 0 {
3255- return prev_ty. into ( ) ;
3256- }
3257- }
3258- ty:: GenericParamDefKind :: Lifetime
3259- | ty:: GenericParamDefKind :: Const { .. } => { }
3260- }
3261- self . var_for_def ( span, param)
3262- } ) ;
3263- // This will hold the resolved type of the associated type, if the
3264- // current expression implements the trait that associated type is
3265- // in. For example, this would be what `Iterator::Item` is here.
3266- let ty_var = self . infcx . next_ty_var ( origin) ;
3267- // This corresponds to `<ExprTy as Iterator>::Item = _`.
3268- let trait_ref = ty:: Binder :: dummy ( ty:: PredicateKind :: Clause (
3269- ty:: Clause :: Projection ( ty:: ProjectionPredicate {
3270- projection_ty : ty:: AliasTy { substs, def_id : proj. def_id } ,
3271- term : ty_var. into ( ) ,
3272- } ) ,
3273- ) ) ;
3274- // Add `<ExprTy as Iterator>::Item = _` obligation.
3275- ocx. register_obligation ( Obligation :: misc (
3276- self . tcx ,
3277- span,
3278- expr. hir_id ,
3279- param_env,
3280- trait_ref,
3281- ) ) ;
3282- if ocx. select_where_possible ( ) . is_empty ( ) {
3283- // `ty_var` now holds the type that `Item` is for `ExprTy`.
3284- let ty_var = self . resolve_vars_if_possible ( ty_var) ;
3285- assocs_in_this_method. push ( Some ( ( span, ( proj. def_id , ty_var) ) ) ) ;
3286- } else {
3287- // `<ExprTy as Iterator>` didn't select, so likely we've
3288- // reached the end of the iterator chain, like the originating
3289- // `Vec<_>`.
3290- // Keep the space consistent for later zipping.
3291- assocs_in_this_method. push ( None ) ;
3292- }
3293- }
3257+ let assocs_in_this_method =
3258+ self . probe_assoc_types_at_expr ( & type_diffs, span, prev_ty, expr. hir_id , param_env) ;
32943259 assocs. push ( assocs_in_this_method) ;
3260+
32953261 prev_ty = self . resolve_vars_if_possible (
32963262 typeck_results. expr_ty_adjusted_opt ( expr) . unwrap_or ( tcx. ty_error ( ) ) ,
32973263 ) ;
@@ -3300,17 +3266,32 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
33003266 && let hir:: Path { res : hir:: def:: Res :: Local ( hir_id) , .. } = path
33013267 && let Some ( hir:: Node :: Pat ( binding) ) = self . tcx . hir ( ) . find ( * hir_id)
33023268 && let parent_hir_id = self . tcx . hir ( ) . get_parent_node ( binding. hir_id )
3303- && let Some ( hir:: Node :: Local ( local) ) = self . tcx . hir ( ) . find ( parent_hir_id)
3304- && let Some ( binding_expr) = local. init
3269+ && let Some ( parent) = self . tcx . hir ( ) . find ( parent_hir_id)
33053270 {
3306- // We've reached the root of the method call chain and it is a
3307- // binding. Get the binding creation and try to continue the chain.
3308- expr = binding_expr;
3271+ // We've reached the root of the method call chain...
3272+ if let hir:: Node :: Local ( local) = parent
3273+ && let Some ( binding_expr) = local. init
3274+ {
3275+ // ...and it is a binding. Get the binding creation and continue the chain.
3276+ expr = binding_expr;
3277+ }
3278+ if let hir:: Node :: Param ( param) = parent {
3279+ // ...and it is a an fn argument.
3280+ let prev_ty = self . resolve_vars_if_possible (
3281+ typeck_results. node_type_opt ( param. hir_id ) . unwrap_or ( tcx. ty_error ( ) ) ,
3282+ ) ;
3283+ let assocs_in_this_method = self . probe_assoc_types_at_expr ( & type_diffs, param. ty_span , prev_ty, param. hir_id , param_env) ;
3284+ if assocs_in_this_method. iter ( ) . any ( |a| a. is_some ( ) ) {
3285+ assocs. push ( assocs_in_this_method) ;
3286+ print_root_expr = false ;
3287+ }
3288+ break ;
3289+ }
33093290 }
33103291 }
33113292 // We want the type before deref coercions, otherwise we talk about `&[_]`
33123293 // instead of `Vec<_>`.
3313- if let Some ( ty) = typeck_results. expr_ty_opt ( expr) {
3294+ if let Some ( ty) = typeck_results. expr_ty_opt ( expr) && print_root_expr {
33143295 let ty = with_forced_trimmed_paths ! ( self . ty_to_string( ty) ) ;
33153296 // Point at the root expression
33163297 // vec![1, 2, 3].iter().map(mapper).sum<i32>()
@@ -3324,7 +3305,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
33243305 let Some ( prev_assoc_in_method) = assocs. peek ( ) else {
33253306 for entry in assocs_in_method {
33263307 let Some ( ( span, ( assoc, ty) ) ) = entry else { continue ; } ;
3327- if type_diffs. iter ( ) . any ( |diff| {
3308+ if primary_spans . is_empty ( ) || type_diffs. iter ( ) . any ( |diff| {
33283309 let Sorts ( expected_found) = diff else { return false ; } ;
33293310 self . can_eq ( param_env, expected_found. found , ty) . is_ok ( )
33303311 } ) {
@@ -3380,27 +3361,77 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
33803361 }
33813362 }
33823363 }
3383- for span in call_spans {
3384- if span_labels. iter ( ) . find ( |( s, _) | * s == span) . is_none ( ) {
3385- // Ensure we are showing the entire chain, even if the assoc types
3386- // haven't changed.
3387- span_labels. push ( ( span, String :: new ( ) ) ) ;
3388- }
3389- }
33903364 if !primary_spans. is_empty ( ) {
33913365 let mut multi_span: MultiSpan = primary_spans. into ( ) ;
33923366 for ( span, label) in span_labels {
33933367 multi_span. push_span_label ( span, label) ;
33943368 }
33953369 err. span_note (
33963370 multi_span,
3397- format ! (
3398- "the method call chain might not have had the expected \
3399- associated types",
3400- ) ,
3371+ format ! ( "the method call chain might not have had the expected associated types" ) ,
34013372 ) ;
34023373 }
34033374 }
3375+
3376+ fn probe_assoc_types_at_expr (
3377+ & self ,
3378+ type_diffs : & [ TypeError < ' tcx > ] ,
3379+ span : Span ,
3380+ prev_ty : Ty < ' tcx > ,
3381+ body_id : hir:: HirId ,
3382+ param_env : ty:: ParamEnv < ' tcx > ,
3383+ ) -> Vec < Option < ( Span , ( DefId , Ty < ' tcx > ) ) > > {
3384+ let ocx = ObligationCtxt :: new_in_snapshot ( self . infcx ) ;
3385+ let mut assocs_in_this_method = Vec :: with_capacity ( type_diffs. len ( ) ) ;
3386+ for diff in type_diffs {
3387+ let Sorts ( expected_found) = diff else { continue ; } ;
3388+ let ty:: Alias ( ty:: Projection , proj) = expected_found. expected . kind ( ) else { continue ; } ;
3389+
3390+ let origin = TypeVariableOrigin { kind : TypeVariableOriginKind :: TypeInference , span } ;
3391+ let trait_def_id = proj. trait_def_id ( self . tcx ) ;
3392+ // Make `Self` be equivalent to the type of the call chain
3393+ // expression we're looking at now, so that we can tell what
3394+ // for example `Iterator::Item` is at this point in the chain.
3395+ let substs = InternalSubsts :: for_item ( self . tcx , trait_def_id, |param, _| {
3396+ match param. kind {
3397+ ty:: GenericParamDefKind :: Type { .. } => {
3398+ if param. index == 0 {
3399+ return prev_ty. into ( ) ;
3400+ }
3401+ }
3402+ ty:: GenericParamDefKind :: Lifetime | ty:: GenericParamDefKind :: Const { .. } => { }
3403+ }
3404+ self . var_for_def ( span, param)
3405+ } ) ;
3406+ // This will hold the resolved type of the associated type, if the
3407+ // current expression implements the trait that associated type is
3408+ // in. For example, this would be what `Iterator::Item` is here.
3409+ let ty_var = self . infcx . next_ty_var ( origin) ;
3410+ // This corresponds to `<ExprTy as Iterator>::Item = _`.
3411+ let trait_ref = ty:: Binder :: dummy ( ty:: PredicateKind :: Clause ( ty:: Clause :: Projection (
3412+ ty:: ProjectionPredicate {
3413+ projection_ty : ty:: AliasTy { substs, def_id : proj. def_id } ,
3414+ term : ty_var. into ( ) ,
3415+ } ,
3416+ ) ) ) ;
3417+ // Add `<ExprTy as Iterator>::Item = _` obligation.
3418+ ocx. register_obligation ( Obligation :: misc (
3419+ self . tcx , span, body_id, param_env, trait_ref,
3420+ ) ) ;
3421+ if ocx. select_where_possible ( ) . is_empty ( ) {
3422+ // `ty_var` now holds the type that `Item` is for `ExprTy`.
3423+ let ty_var = self . resolve_vars_if_possible ( ty_var) ;
3424+ assocs_in_this_method. push ( Some ( ( span, ( proj. def_id , ty_var) ) ) ) ;
3425+ } else {
3426+ // `<ExprTy as Iterator>` didn't select, so likely we've
3427+ // reached the end of the iterator chain, like the originating
3428+ // `Vec<_>`.
3429+ // Keep the space consistent for later zipping.
3430+ assocs_in_this_method. push ( None ) ;
3431+ }
3432+ }
3433+ assocs_in_this_method
3434+ }
34043435}
34053436
34063437/// Add a hint to add a missing borrow or remove an unnecessary one.
0 commit comments