@@ -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,63 +3254,8 @@ 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 projection = ty:: Binder :: dummy ( ty:: PredicateKind :: Clause (
3269
- ty:: Clause :: Projection ( ty:: ProjectionPredicate {
3270
- projection_ty : tcx. mk_alias_ty ( proj. def_id , substs) ,
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
- projection,
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) ;
3295
3260
prev_ty = self . resolve_vars_if_possible (
3296
3261
typeck_results. expr_ty_adjusted_opt ( expr) . unwrap_or ( tcx. ty_error ( ) ) ,
@@ -3300,17 +3265,32 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
3300
3265
&& let hir:: Path { res : hir:: def:: Res :: Local ( hir_id) , .. } = path
3301
3266
&& let Some ( hir:: Node :: Pat ( binding) ) = self . tcx . hir ( ) . find ( * hir_id)
3302
3267
&& 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
3268
+ && let Some ( parent) = self . tcx . hir ( ) . find ( parent_hir_id)
3305
3269
{
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;
3270
+ // We've reached the root of the method call chain...
3271
+ if let hir:: Node :: Local ( local) = parent
3272
+ && let Some ( binding_expr) = local. init
3273
+ {
3274
+ // ...and it is a binding. Get the binding creation and continue the chain.
3275
+ expr = binding_expr;
3276
+ }
3277
+ if let hir:: Node :: Param ( param) = parent {
3278
+ // ...and it is a an fn argument.
3279
+ let prev_ty = self . resolve_vars_if_possible (
3280
+ typeck_results. node_type_opt ( param. hir_id ) . unwrap_or ( tcx. ty_error ( ) ) ,
3281
+ ) ;
3282
+ let assocs_in_this_method = self . probe_assoc_types_at_expr ( & type_diffs, param. ty_span , prev_ty, param. hir_id , param_env) ;
3283
+ if assocs_in_this_method. iter ( ) . any ( |a| a. is_some ( ) ) {
3284
+ assocs. push ( assocs_in_this_method) ;
3285
+ print_root_expr = false ;
3286
+ }
3287
+ break ;
3288
+ }
3309
3289
}
3310
3290
}
3311
3291
// We want the type before deref coercions, otherwise we talk about `&[_]`
3312
3292
// instead of `Vec<_>`.
3313
- if let Some ( ty) = typeck_results. expr_ty_opt ( expr) {
3293
+ if let Some ( ty) = typeck_results. expr_ty_opt ( expr) && print_root_expr {
3314
3294
let ty = with_forced_trimmed_paths ! ( self . ty_to_string( ty) ) ;
3315
3295
// Point at the root expression
3316
3296
// vec![1, 2, 3].iter().map(mapper).sum<i32>()
@@ -3324,7 +3304,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
3324
3304
let Some ( prev_assoc_in_method) = assocs. peek ( ) else {
3325
3305
for entry in assocs_in_method {
3326
3306
let Some ( ( span, ( assoc, ty) ) ) = entry else { continue ; } ;
3327
- if type_diffs. iter ( ) . any ( |diff| {
3307
+ if primary_spans . is_empty ( ) || type_diffs. iter ( ) . any ( |diff| {
3328
3308
let Sorts ( expected_found) = diff else { return false ; } ;
3329
3309
self . can_eq ( param_env, expected_found. found , ty) . is_ok ( )
3330
3310
} ) {
@@ -3380,27 +3360,77 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
3380
3360
}
3381
3361
}
3382
3362
}
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
3363
if !primary_spans. is_empty ( ) {
3391
3364
let mut multi_span: MultiSpan = primary_spans. into ( ) ;
3392
3365
for ( span, label) in span_labels {
3393
3366
multi_span. push_span_label ( span, label) ;
3394
3367
}
3395
3368
err. span_note (
3396
3369
multi_span,
3397
- format ! (
3398
- "the method call chain might not have had the expected \
3399
- associated types",
3400
- ) ,
3370
+ format ! ( "the method call chain might not have had the expected associated types" ) ,
3401
3371
) ;
3402
3372
}
3403
3373
}
3374
+
3375
+ fn probe_assoc_types_at_expr (
3376
+ & self ,
3377
+ type_diffs : & [ TypeError < ' tcx > ] ,
3378
+ span : Span ,
3379
+ prev_ty : Ty < ' tcx > ,
3380
+ body_id : hir:: HirId ,
3381
+ param_env : ty:: ParamEnv < ' tcx > ,
3382
+ ) -> Vec < Option < ( Span , ( DefId , Ty < ' tcx > ) ) > > {
3383
+ let ocx = ObligationCtxt :: new_in_snapshot ( self . infcx ) ;
3384
+ let mut assocs_in_this_method = Vec :: with_capacity ( type_diffs. len ( ) ) ;
3385
+ for diff in type_diffs {
3386
+ let Sorts ( expected_found) = diff else { continue ; } ;
3387
+ let ty:: Alias ( ty:: Projection , proj) = expected_found. expected . kind ( ) else { continue ; } ;
3388
+
3389
+ let origin = TypeVariableOrigin { kind : TypeVariableOriginKind :: TypeInference , span } ;
3390
+ let trait_def_id = proj. trait_def_id ( self . tcx ) ;
3391
+ // Make `Self` be equivalent to the type of the call chain
3392
+ // expression we're looking at now, so that we can tell what
3393
+ // for example `Iterator::Item` is at this point in the chain.
3394
+ let substs = InternalSubsts :: for_item ( self . tcx , trait_def_id, |param, _| {
3395
+ match param. kind {
3396
+ ty:: GenericParamDefKind :: Type { .. } => {
3397
+ if param. index == 0 {
3398
+ return prev_ty. into ( ) ;
3399
+ }
3400
+ }
3401
+ ty:: GenericParamDefKind :: Lifetime | ty:: GenericParamDefKind :: Const { .. } => { }
3402
+ }
3403
+ self . var_for_def ( span, param)
3404
+ } ) ;
3405
+ // This will hold the resolved type of the associated type, if the
3406
+ // current expression implements the trait that associated type is
3407
+ // in. For example, this would be what `Iterator::Item` is here.
3408
+ let ty_var = self . infcx . next_ty_var ( origin) ;
3409
+ // This corresponds to `<ExprTy as Iterator>::Item = _`.
3410
+ let projection = ty:: Binder :: dummy ( ty:: PredicateKind :: Clause ( ty:: Clause :: Projection (
3411
+ ty:: ProjectionPredicate {
3412
+ projection_ty : self . tcx . mk_alias_ty ( proj. def_id , substs) ,
3413
+ term : ty_var. into ( ) ,
3414
+ } ,
3415
+ ) ) ) ;
3416
+ // Add `<ExprTy as Iterator>::Item = _` obligation.
3417
+ ocx. register_obligation ( Obligation :: misc (
3418
+ self . tcx , span, body_id, param_env, projection,
3419
+ ) ) ;
3420
+ if ocx. select_where_possible ( ) . is_empty ( ) {
3421
+ // `ty_var` now holds the type that `Item` is for `ExprTy`.
3422
+ let ty_var = self . resolve_vars_if_possible ( ty_var) ;
3423
+ assocs_in_this_method. push ( Some ( ( span, ( proj. def_id , ty_var) ) ) ) ;
3424
+ } else {
3425
+ // `<ExprTy as Iterator>` didn't select, so likely we've
3426
+ // reached the end of the iterator chain, like the originating
3427
+ // `Vec<_>`.
3428
+ // Keep the space consistent for later zipping.
3429
+ assocs_in_this_method. push ( None ) ;
3430
+ }
3431
+ }
3432
+ assocs_in_this_method
3433
+ }
3404
3434
}
3405
3435
3406
3436
/// Add a hint to add a missing borrow or remove an unnecessary one.
0 commit comments