Skip to content

Commit 00ff515

Browse files
authored
Unrolled build for rust-lang#122591
Rollup merge of rust-lang#122591 - gurry:122162-impl-type-binding-suggestion, r=fmease Suggest using type args directly instead of equality constraint When type arguments are written erroneously using an equality constraint we suggest specifying them directly without the equality constraint. Fixes rust-lang#122162 Changes the diagnostic in the issue from: ```rust error[E0229]: associated type bindings are not allowed here 9 | impl std::cmp::PartialEq<Rhs = T> for S { | ^^^^^^^ associated type not allowed here | ``` to ```rust error[E0229]: associated type bindings are not allowed here 9 | impl std::cmp::PartialEq<Rhs = T> for S { | ^^^^^^^ associated type not allowed here | help: to use `T` as a generic argument specify it directly | | impl std::cmp::PartialEq<T> for S { | ~ ```
2 parents cd90d5c + f7ebad4 commit 00ff515

File tree

17 files changed

+707
-29
lines changed

17 files changed

+707
-29
lines changed

Diff for: compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs

+109-6
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use rustc_hir::def::{DefKind, Res};
1717
use rustc_hir::def_id::{DefId, LocalDefId};
1818
use rustc_infer::traits::FulfillmentError;
1919
use rustc_middle::query::Key;
20+
use rustc_middle::ty::GenericParamDefKind;
2021
use rustc_middle::ty::{self, suggest_constraining_type_param};
2122
use rustc_middle::ty::{AdtDef, Ty, TyCtxt, TypeVisitableExt};
2223
use rustc_middle::ty::{Binder, TraitRef};
@@ -1200,12 +1201,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
12001201
/// Emits an error regarding forbidden type binding associations
12011202
pub fn prohibit_assoc_item_binding(
12021203
tcx: TyCtxt<'_>,
1203-
span: Span,
1204-
segment: Option<(&hir::PathSegment<'_>, Span)>,
1204+
binding: &hir::TypeBinding<'_>,
1205+
segment: Option<(DefId, &hir::PathSegment<'_>, Span)>,
12051206
) -> ErrorGuaranteed {
1206-
tcx.dcx().emit_err(AssocTypeBindingNotAllowed {
1207-
span,
1208-
fn_trait_expansion: if let Some((segment, span)) = segment
1207+
let mut err = tcx.dcx().create_err(AssocTypeBindingNotAllowed {
1208+
span: binding.span,
1209+
fn_trait_expansion: if let Some((_, segment, span)) = segment
12091210
&& segment.args().parenthesized == hir::GenericArgsParentheses::ParenSugar
12101211
{
12111212
Some(ParenthesizedFnTraitExpansion {
@@ -1215,7 +1216,109 @@ pub fn prohibit_assoc_item_binding(
12151216
} else {
12161217
None
12171218
},
1218-
})
1219+
});
1220+
1221+
// Emit a suggestion to turn the assoc item binding into a generic arg
1222+
// if the relevant item has a generic param whose name matches the binding name;
1223+
// otherwise suggest the removal of the binding.
1224+
if let Some((def_id, segment, _)) = segment
1225+
&& segment.args().parenthesized == hir::GenericArgsParentheses::No
1226+
&& let hir::TypeBindingKind::Equality { term } = binding.kind
1227+
{
1228+
// Suggests removal of the offending binding
1229+
let suggest_removal = |e: &mut Diag<'_>| {
1230+
let bindings = segment.args().bindings;
1231+
let args = segment.args().args;
1232+
let binding_span = binding.span;
1233+
1234+
// Compute the span to remove based on the position
1235+
// of the binding. We do that as follows:
1236+
// 1. Find the index of the binding in the list of bindings
1237+
// 2. Locate the spans preceding and following the binding.
1238+
// If it's the first binding the preceding span would be
1239+
// that of the last arg
1240+
// 3. Using this information work out whether the span
1241+
// to remove will start from the end of the preceding span,
1242+
// the start of the next span or will simply be the
1243+
// span encomassing everything within the generics brackets
1244+
1245+
let Some(binding_index) = bindings.iter().position(|b| b.hir_id == binding.hir_id)
1246+
else {
1247+
bug!("a type binding exists but its HIR ID not found in generics");
1248+
};
1249+
1250+
let preceding_span = if binding_index > 0 {
1251+
Some(bindings[binding_index - 1].span)
1252+
} else {
1253+
args.last().map(|a| a.span())
1254+
};
1255+
1256+
let next_span = if binding_index < bindings.len() - 1 {
1257+
Some(bindings[binding_index + 1].span)
1258+
} else {
1259+
None
1260+
};
1261+
1262+
let removal_span = match (preceding_span, next_span) {
1263+
(Some(prec), _) => binding_span.with_lo(prec.hi()),
1264+
(None, Some(next)) => binding_span.with_hi(next.lo()),
1265+
(None, None) => {
1266+
let Some(generics_span) = segment.args().span_ext() else {
1267+
bug!("a type binding exists but generic span is empty");
1268+
};
1269+
1270+
generics_span
1271+
}
1272+
};
1273+
1274+
// Now emit the suggestion
1275+
if let Ok(suggestion) = tcx.sess.source_map().span_to_snippet(removal_span) {
1276+
e.span_suggestion_verbose(
1277+
removal_span,
1278+
"consider removing this type binding",
1279+
suggestion,
1280+
Applicability::MaybeIncorrect,
1281+
);
1282+
}
1283+
};
1284+
1285+
// Suggest replacing the associated item binding with a generic argument.
1286+
// i.e., replacing `<..., T = A, ...>` with `<..., A, ...>`.
1287+
let suggest_direct_use = |e: &mut Diag<'_>, sp: Span| {
1288+
if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(sp) {
1289+
e.span_suggestion_verbose(
1290+
binding.span,
1291+
format!("to use `{snippet}` as a generic argument specify it directly"),
1292+
snippet,
1293+
Applicability::MaybeIncorrect,
1294+
);
1295+
}
1296+
};
1297+
1298+
// Check if the type has a generic param with the
1299+
// same name as the assoc type name in type binding
1300+
let generics = tcx.generics_of(def_id);
1301+
let matching_param =
1302+
generics.params.iter().find(|p| p.name.as_str() == binding.ident.as_str());
1303+
1304+
// Now emit the appropriate suggestion
1305+
if let Some(matching_param) = matching_param {
1306+
match (&matching_param.kind, term) {
1307+
(GenericParamDefKind::Type { .. }, hir::Term::Ty(ty)) => {
1308+
suggest_direct_use(&mut err, ty.span);
1309+
}
1310+
(GenericParamDefKind::Const { .. }, hir::Term::Const(c)) => {
1311+
let span = tcx.hir().span(c.hir_id);
1312+
suggest_direct_use(&mut err, span);
1313+
}
1314+
_ => suggest_removal(&mut err),
1315+
}
1316+
} else {
1317+
suggest_removal(&mut err);
1318+
}
1319+
}
1320+
1321+
err.emit()
12191322
}
12201323

12211324
pub(crate) fn fn_trait_to_string(

Diff for: compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,7 @@ pub(crate) fn check_generic_arg_count(
454454
if gen_pos != GenericArgPosition::Type
455455
&& let Some(b) = gen_args.bindings.first()
456456
{
457-
prohibit_assoc_item_binding(tcx, b.span, None);
457+
prohibit_assoc_item_binding(tcx, b, None);
458458
}
459459

460460
let explicit_late_bound =

Diff for: compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
323323
ty::BoundConstness::NotConst,
324324
);
325325
if let Some(b) = item_segment.args().bindings.first() {
326-
prohibit_assoc_item_binding(self.tcx(), b.span, Some((item_segment, span)));
326+
prohibit_assoc_item_binding(self.tcx(), b, Some((def_id, item_segment, span)));
327327
}
328328
args
329329
}
@@ -620,7 +620,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
620620
ty::BoundConstness::NotConst,
621621
);
622622
if let Some(b) = item_segment.args().bindings.first() {
623-
prohibit_assoc_item_binding(self.tcx(), b.span, Some((item_segment, span)));
623+
prohibit_assoc_item_binding(self.tcx(), b, Some((item_def_id, item_segment, span)));
624624
}
625625
args
626626
}
@@ -765,7 +765,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
765765
constness,
766766
);
767767
if let Some(b) = trait_segment.args().bindings.first() {
768-
prohibit_assoc_item_binding(self.tcx(), b.span, Some((trait_segment, span)));
768+
prohibit_assoc_item_binding(self.tcx(), b, Some((trait_def_id, trait_segment, span)));
769769
}
770770
ty::TraitRef::new(self.tcx(), trait_def_id, generic_args)
771771
}
@@ -1544,7 +1544,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
15441544
for segment in segments {
15451545
// Only emit the first error to avoid overloading the user with error messages.
15461546
if let Some(b) = segment.args().bindings.first() {
1547-
return Err(prohibit_assoc_item_binding(self.tcx(), b.span, None));
1547+
return Err(prohibit_assoc_item_binding(self.tcx(), b, None));
15481548
}
15491549
}
15501550

Diff for: tests/rustdoc-ui/invalid_associated_const.stderr

+9
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ error[E0229]: associated type bindings are not allowed here
33
|
44
LL | type A: S<C<X = 0i32> = 34>;
55
| ^^^^^^^^ associated type not allowed here
6+
|
7+
help: consider removing this type binding
8+
|
9+
LL | type A: S<C<X = 0i32> = 34>;
10+
| ~~~~~~~~~~
611

712
error[E0229]: associated type bindings are not allowed here
813
--> $DIR/invalid_associated_const.rs:4:17
@@ -11,6 +16,10 @@ LL | type A: S<C<X = 0i32> = 34>;
1116
| ^^^^^^^^ associated type not allowed here
1217
|
1318
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
19+
help: consider removing this type binding
20+
|
21+
LL | type A: S<C<X = 0i32> = 34>;
22+
| ~~~~~~~~~~
1423

1524
error: aborting due to 2 previous errors
1625

Diff for: tests/rustdoc-ui/issue-102467.stderr

+9
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ error[E0229]: associated type bindings are not allowed here
33
|
44
LL | type A: S<C<X = 0i32> = 34>;
55
| ^^^^^^^^ associated type not allowed here
6+
|
7+
help: consider removing this type binding
8+
|
9+
LL | type A: S<C<X = 0i32> = 34>;
10+
| ~~~~~~~~~~
611

712
error[E0229]: associated type bindings are not allowed here
813
--> $DIR/issue-102467.rs:7:17
@@ -11,6 +16,10 @@ LL | type A: S<C<X = 0i32> = 34>;
1116
| ^^^^^^^^ associated type not allowed here
1217
|
1318
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
19+
help: consider removing this type binding
20+
|
21+
LL | type A: S<C<X = 0i32> = 34>;
22+
| ~~~~~~~~~~
1423

1524
error: aborting due to 2 previous errors
1625

Diff for: tests/ui/associated-consts/issue-102335-const.stderr

+9
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ error[E0229]: associated type bindings are not allowed here
33
|
44
LL | type A: S<C<X = 0i32> = 34>;
55
| ^^^^^^^^ associated type not allowed here
6+
|
7+
help: consider removing this type binding
8+
|
9+
LL | type A: S<C<X = 0i32> = 34>;
10+
| ~~~~~~~~~~
611

712
error[E0229]: associated type bindings are not allowed here
813
--> $DIR/issue-102335-const.rs:4:17
@@ -11,6 +16,10 @@ LL | type A: S<C<X = 0i32> = 34>;
1116
| ^^^^^^^^ associated type not allowed here
1217
|
1318
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
19+
help: consider removing this type binding
20+
|
21+
LL | type A: S<C<X = 0i32> = 34>;
22+
| ~~~~~~~~~~
1423

1524
error: aborting due to 2 previous errors
1625

Diff for: tests/ui/associated-type-bounds/issue-102335-ty.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
trait T {
2-
type A: S<C<i32 = u32> = ()>;
2+
type A: S<C<i32 = u32> = ()>; // Just one erroneous equality constraint
3+
//~^ ERROR associated type bindings are not allowed here
4+
//~| ERROR associated type bindings are not allowed here
5+
}
6+
7+
trait T2 {
8+
type A: S<C<i32 = u32, X = i32> = ()>; // More than one erroneous equality constraints
39
//~^ ERROR associated type bindings are not allowed here
410
//~| ERROR associated type bindings are not allowed here
511
}
+35-3
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,49 @@
11
error[E0229]: associated type bindings are not allowed here
22
--> $DIR/issue-102335-ty.rs:2:17
33
|
4-
LL | type A: S<C<i32 = u32> = ()>;
4+
LL | type A: S<C<i32 = u32> = ()>; // Just one erroneous equality constraint
55
| ^^^^^^^^^ associated type not allowed here
6+
|
7+
help: consider removing this type binding
8+
|
9+
LL | type A: S<C<i32 = u32> = ()>; // Just one erroneous equality constraint
10+
| ~~~~~~~~~~~
611

712
error[E0229]: associated type bindings are not allowed here
813
--> $DIR/issue-102335-ty.rs:2:17
914
|
10-
LL | type A: S<C<i32 = u32> = ()>;
15+
LL | type A: S<C<i32 = u32> = ()>; // Just one erroneous equality constraint
16+
| ^^^^^^^^^ associated type not allowed here
17+
|
18+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
19+
help: consider removing this type binding
20+
|
21+
LL | type A: S<C<i32 = u32> = ()>; // Just one erroneous equality constraint
22+
| ~~~~~~~~~~~
23+
24+
error[E0229]: associated type bindings are not allowed here
25+
--> $DIR/issue-102335-ty.rs:8:17
26+
|
27+
LL | type A: S<C<i32 = u32, X = i32> = ()>; // More than one erroneous equality constraints
28+
| ^^^^^^^^^ associated type not allowed here
29+
|
30+
help: consider removing this type binding
31+
|
32+
LL | type A: S<C<i32 = u32, X = i32> = ()>; // More than one erroneous equality constraints
33+
| ~~~~~~~~~~
34+
35+
error[E0229]: associated type bindings are not allowed here
36+
--> $DIR/issue-102335-ty.rs:8:17
37+
|
38+
LL | type A: S<C<i32 = u32, X = i32> = ()>; // More than one erroneous equality constraints
1139
| ^^^^^^^^^ associated type not allowed here
1240
|
1341
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
42+
help: consider removing this type binding
43+
|
44+
LL | type A: S<C<i32 = u32, X = i32> = ()>; // More than one erroneous equality constraints
45+
| ~~~~~~~~~~
1446

15-
error: aborting due to 2 previous errors
47+
error: aborting due to 4 previous errors
1648

1749
For more information about this error, try `rustc --explain E0229`.

0 commit comments

Comments
 (0)