@@ -352,6 +352,14 @@ pub trait TypeErrCtxtExt<'tcx> {
352
352
param_env : ty:: ParamEnv < ' tcx > ,
353
353
err : & mut Diagnostic ,
354
354
) ;
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 > ) ) > > ;
355
363
}
356
364
357
365
fn predicate_constraint ( generics : & hir:: Generics < ' _ > , pred : ty:: Predicate < ' _ > ) -> ( Span , String ) {
@@ -3152,23 +3160,37 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
3152
3160
if let ObligationCauseCode :: ExprBindingObligation ( def_id, _, _, idx) = parent_code. deref ( )
3153
3161
&& let predicates = self . tcx . predicates_of ( def_id) . instantiate_identity ( self . tcx )
3154
3162
&& 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
- } )
3159
3163
{
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 {
3166
3165
ty:: PredicateKind :: Clause ( ty:: Clause :: Trait ( trait_pred) ) => Ok ( trait_pred) ,
3167
3166
_ => 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
+ } ;
3169
3178
if let Ok ( _) = c. relate ( trait_pred, trait_predicate) {
3170
3179
type_diffs = c. errors ;
3171
3180
}
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
+ ] ;
3172
3194
}
3173
3195
}
3174
3196
if let hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( None , path) ) = expr. kind
@@ -3221,10 +3243,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
3221
3243
3222
3244
let tcx = self . tcx ;
3223
3245
3246
+ let mut print_root_expr = true ;
3224
3247
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 ! [ ] ;
3228
3248
let mut expr = expr;
3229
3249
let mut prev_ty = self . resolve_vars_if_possible (
3230
3250
typeck_results. expr_ty_adjusted_opt ( expr) . unwrap_or ( tcx. ty_error ( ) ) ,
@@ -3234,64 +3254,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
3234
3254
// vec![1, 2, 3].iter().map(mapper).sum<i32>()
3235
3255
// ^^^^^^ ^^^^^^^^^^^
3236
3256
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) ;
3294
3259
assocs. push ( assocs_in_this_method) ;
3260
+
3295
3261
prev_ty = self . resolve_vars_if_possible (
3296
3262
typeck_results. expr_ty_adjusted_opt ( expr) . unwrap_or ( tcx. ty_error ( ) ) ,
3297
3263
) ;
@@ -3300,17 +3266,32 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
3300
3266
&& let hir:: Path { res : hir:: def:: Res :: Local ( hir_id) , .. } = path
3301
3267
&& let Some ( hir:: Node :: Pat ( binding) ) = self . tcx . hir ( ) . find ( * hir_id)
3302
3268
&& 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)
3305
3270
{
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
+ }
3309
3290
}
3310
3291
}
3311
3292
// We want the type before deref coercions, otherwise we talk about `&[_]`
3312
3293
// 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 {
3314
3295
let ty = with_forced_trimmed_paths ! ( self . ty_to_string( ty) ) ;
3315
3296
// Point at the root expression
3316
3297
// vec![1, 2, 3].iter().map(mapper).sum<i32>()
@@ -3324,7 +3305,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
3324
3305
let Some ( prev_assoc_in_method) = assocs. peek ( ) else {
3325
3306
for entry in assocs_in_method {
3326
3307
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| {
3328
3309
let Sorts ( expected_found) = diff else { return false ; } ;
3329
3310
self . can_eq ( param_env, expected_found. found , ty) . is_ok ( )
3330
3311
} ) {
@@ -3380,27 +3361,77 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
3380
3361
}
3381
3362
}
3382
3363
}
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
- }
3390
3364
if !primary_spans. is_empty ( ) {
3391
3365
let mut multi_span: MultiSpan = primary_spans. into ( ) ;
3392
3366
for ( span, label) in span_labels {
3393
3367
multi_span. push_span_label ( span, label) ;
3394
3368
}
3395
3369
err. span_note (
3396
3370
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" ) ,
3401
3372
) ;
3402
3373
}
3403
3374
}
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
+ }
3404
3435
}
3405
3436
3406
3437
/// Add a hint to add a missing borrow or remove an unnecessary one.
0 commit comments