Skip to content

Commit e457cda

Browse files
authored
Unrolled build for rust-lang#126054
Rollup merge of rust-lang#126054 - veera-sivarajan:bugfix-113073-bound-on-generics-2, r=fee1-dead `E0229`: Suggest Moving Type Constraints to Type Parameter Declaration Fixes rust-lang#113073 This PR suggests `impl<T: Bound> Trait<T> for Foo` when finding `impl Trait<T: Bound> for Foo`. Tangentially, it also improves a handful of other error messages. It accomplishes this in two steps: 1. Check if constrained arguments and parameter names appear in the same order and delay emitting "incorrect number of generic arguments" error because it can be confusing for the programmer to see `0 generic arguments provided` when there are `n` constrained generic arguments. 2. Inside `E0229`, suggest declaring the type parameter right after the `impl` keyword by finding the relevant impl block's span for type parameter declaration. This also handles lifetime declarations correctly. Also, the multi part suggestion doesn't use the fluent error mechanism because translating all the errors to fluent style feels outside the scope of this PR. I will handle it in a separate PR if this gets approved.
2 parents 63491e1 + 5da1b41 commit e457cda

File tree

14 files changed

+263
-101
lines changed

14 files changed

+263
-101
lines changed

compiler/rustc_hir/src/hir.rs

+24
Original file line numberDiff line numberDiff line change
@@ -2471,6 +2471,15 @@ pub enum AssocItemConstraintKind<'hir> {
24712471
Bound { bounds: &'hir [GenericBound<'hir>] },
24722472
}
24732473

2474+
impl<'hir> AssocItemConstraintKind<'hir> {
2475+
pub fn descr(&self) -> &'static str {
2476+
match self {
2477+
AssocItemConstraintKind::Equality { .. } => "binding",
2478+
AssocItemConstraintKind::Bound { .. } => "constraint",
2479+
}
2480+
}
2481+
}
2482+
24742483
#[derive(Debug, Clone, Copy, HashStable_Generic)]
24752484
pub struct Ty<'hir> {
24762485
pub hir_id: HirId,
@@ -3763,6 +3772,21 @@ impl<'hir> Node<'hir> {
37633772
}
37643773
}
37653774

3775+
/// Get a `hir::Impl` if the node is an impl block for the given `trait_def_id`.
3776+
pub fn impl_block_of_trait(self, trait_def_id: DefId) -> Option<&'hir Impl<'hir>> {
3777+
match self {
3778+
Node::Item(Item { kind: ItemKind::Impl(impl_block), .. })
3779+
if impl_block
3780+
.of_trait
3781+
.and_then(|trait_ref| trait_ref.trait_def_id())
3782+
.is_some_and(|trait_id| trait_id == trait_def_id) =>
3783+
{
3784+
Some(impl_block)
3785+
}
3786+
_ => None,
3787+
}
3788+
}
3789+
37663790
pub fn fn_sig(self) -> Option<&'hir FnSig<'hir>> {
37673791
match self {
37683792
Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig, _), .. })

compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs

+62-9
Original file line numberDiff line numberDiff line change
@@ -1217,7 +1217,6 @@ pub fn prohibit_assoc_item_constraint(
12171217
// otherwise suggest the removal of the binding.
12181218
if let Some((def_id, segment, _)) = segment
12191219
&& segment.args().parenthesized == hir::GenericArgsParentheses::No
1220-
&& let hir::AssocItemConstraintKind::Equality { term } = constraint.kind
12211220
{
12221221
// Suggests removal of the offending binding
12231222
let suggest_removal = |e: &mut Diag<'_>| {
@@ -1263,7 +1262,7 @@ pub fn prohibit_assoc_item_constraint(
12631262
if let Ok(suggestion) = tcx.sess.source_map().span_to_snippet(removal_span) {
12641263
e.span_suggestion_verbose(
12651264
removal_span,
1266-
"consider removing this associated item binding",
1265+
format!("consider removing this associated item {}", constraint.kind.descr()),
12671266
suggestion,
12681267
Applicability::MaybeIncorrect,
12691268
);
@@ -1286,19 +1285,73 @@ pub fn prohibit_assoc_item_constraint(
12861285
// Check if the type has a generic param with the same name
12871286
// as the assoc type name in the associated item binding.
12881287
let generics = tcx.generics_of(def_id);
1289-
let matching_param =
1290-
generics.own_params.iter().find(|p| p.name.as_str() == constraint.ident.as_str());
1288+
let matching_param = generics.own_params.iter().find(|p| p.name == constraint.ident.name);
12911289

12921290
// Now emit the appropriate suggestion
12931291
if let Some(matching_param) = matching_param {
1294-
match (&matching_param.kind, term) {
1295-
(GenericParamDefKind::Type { .. }, hir::Term::Ty(ty)) => {
1296-
suggest_direct_use(&mut err, ty.span);
1297-
}
1298-
(GenericParamDefKind::Const { .. }, hir::Term::Const(c)) => {
1292+
match (constraint.kind, &matching_param.kind) {
1293+
(
1294+
hir::AssocItemConstraintKind::Equality { term: hir::Term::Ty(ty) },
1295+
GenericParamDefKind::Type { .. },
1296+
) => suggest_direct_use(&mut err, ty.span),
1297+
(
1298+
hir::AssocItemConstraintKind::Equality { term: hir::Term::Const(c) },
1299+
GenericParamDefKind::Const { .. },
1300+
) => {
12991301
let span = tcx.hir().span(c.hir_id);
13001302
suggest_direct_use(&mut err, span);
13011303
}
1304+
(hir::AssocItemConstraintKind::Bound { bounds }, _) => {
1305+
// Suggest `impl<T: Bound> Trait<T> for Foo` when finding
1306+
// `impl Trait<T: Bound> for Foo`
1307+
1308+
// Get the parent impl block based on the binding we have
1309+
// and the trait DefId
1310+
let impl_block = tcx
1311+
.hir()
1312+
.parent_iter(constraint.hir_id)
1313+
.find_map(|(_, node)| node.impl_block_of_trait(def_id));
1314+
1315+
let type_with_constraints =
1316+
tcx.sess.source_map().span_to_snippet(constraint.span);
1317+
1318+
if let Some(impl_block) = impl_block
1319+
&& let Ok(type_with_constraints) = type_with_constraints
1320+
{
1321+
// Filter out the lifetime parameters because
1322+
// they should be declared before the type parameter
1323+
let lifetimes: String = bounds
1324+
.iter()
1325+
.filter_map(|bound| {
1326+
if let hir::GenericBound::Outlives(lifetime) = bound {
1327+
Some(format!("{lifetime}, "))
1328+
} else {
1329+
None
1330+
}
1331+
})
1332+
.collect();
1333+
// Figure out a span and suggestion string based on
1334+
// whether there are any existing parameters
1335+
let param_decl = if let Some(param_span) =
1336+
impl_block.generics.span_for_param_suggestion()
1337+
{
1338+
(param_span, format!(", {lifetimes}{type_with_constraints}"))
1339+
} else {
1340+
(
1341+
impl_block.generics.span.shrink_to_lo(),
1342+
format!("<{lifetimes}{type_with_constraints}>"),
1343+
)
1344+
};
1345+
let suggestions =
1346+
vec![param_decl, (constraint.span, format!("{}", matching_param.name))];
1347+
1348+
err.multipart_suggestion_verbose(
1349+
format!("declare the type parameter right after the `impl` keyword"),
1350+
suggestions,
1351+
Applicability::MaybeIncorrect,
1352+
);
1353+
}
1354+
}
13021355
_ => suggest_removal(&mut err),
13031356
}
13041357
} else {

compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,7 @@ pub(crate) fn check_generic_arg_count(
531531

532532
let num_default_params = expected_max - expected_min;
533533

534+
let mut all_params_are_binded = false;
534535
let gen_args_info = if provided > expected_max {
535536
invalid_args.extend((expected_max..provided).map(|i| i + args_offset));
536537
let num_redundant_args = provided - expected_max;
@@ -547,6 +548,20 @@ pub(crate) fn check_generic_arg_count(
547548
} else {
548549
let num_missing_args = expected_max - provided;
549550

551+
let constraint_names: Vec<_> =
552+
gen_args.constraints.iter().map(|b| b.ident.name).collect();
553+
let param_names: Vec<_> = gen_params
554+
.own_params
555+
.iter()
556+
.filter(|param| !has_self || param.index != 0) // Assumes `Self` will always be the first parameter
557+
.map(|param| param.name)
558+
.collect();
559+
if constraint_names == param_names {
560+
// We set this to true and delay emitting `WrongNumberOfGenericArgs`
561+
// to provide a succinct error for cases like issue #113073
562+
all_params_are_binded = true;
563+
};
564+
550565
GenericArgsInfo::MissingTypesOrConsts {
551566
num_missing_args,
552567
num_default_params,
@@ -567,7 +582,7 @@ pub(crate) fn check_generic_arg_count(
567582
def_id,
568583
)
569584
.diagnostic()
570-
.emit()
585+
.emit_unless(all_params_are_binded)
571586
});
572587

573588
Err(reported)

tests/ui/associated-type-bounds/no-gat-position.rs

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ pub trait Iter {
55

66
fn next<'a>(&'a mut self) -> Option<Self::Item<'a, As1: Copy>>;
77
//~^ ERROR associated item constraints are not allowed here
8+
//~| HELP consider removing this associated item constraint
89
}
910

1011
impl Iter for () {

tests/ui/associated-type-bounds/no-gat-position.stderr

+5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ error[E0229]: associated item constraints are not allowed here
33
|
44
LL | fn next<'a>(&'a mut self) -> Option<Self::Item<'a, As1: Copy>>;
55
| ^^^^^^^^^ associated item constraint not allowed here
6+
|
7+
help: consider removing this associated item constraint
8+
|
9+
LL | fn next<'a>(&'a mut self) -> Option<Self::Item<'a, As1: Copy>>;
10+
| ~~~~~~~~~~~
611

712
error: aborting due to 1 previous error
813

tests/ui/associated-types/associated-types-eq-2.rs

-2
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ trait Tr3<const N: i32, T2, T3> {
7676
impl Tr3<N
7777
//~^ ERROR associated item constraints are not allowed here
7878
//~| ERROR associated const equality is incomplete
79-
//~| ERROR trait takes 3 generic arguments but 0 generic arguments were supplied
8079
= 42, T2 = Qux, T3 = usize> for Bar {
8180
}
8281

@@ -92,7 +91,6 @@ impl Tr3<n = 42, T2 = Qux, T3 = usize> for Qux {
9291
// matches the const param ident but the constraint is a type arg
9392
impl Tr3<N = u32, T2 = Qux, T3 = usize> for Bar {
9493
//~^ ERROR associated item constraints are not allowed here
95-
//~| ERROR trait takes 3 generic arguments but 0 generic arguments were supplied
9694
}
9795

9896
// Test for when equality constraint's ident

tests/ui/associated-types/associated-types-eq-2.stderr

+14-48
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ LL | impl Tr3<N
55
| __________^
66
LL | |
77
LL | |
8-
LL | |
98
LL | | = 42, T2 = Qux, T3 = usize> for Bar {
109
| |____^
1110
|
@@ -14,7 +13,7 @@ LL | | = 42, T2 = Qux, T3 = usize> for Bar {
1413
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
1514

1615
error[E0658]: associated const equality is incomplete
17-
--> $DIR/associated-types-eq-2.rs:85:10
16+
--> $DIR/associated-types-eq-2.rs:84:10
1817
|
1918
LL | impl Tr3<n = 42, T2 = Qux, T3 = usize> for Qux {
2019
| ^^^^^^
@@ -24,7 +23,7 @@ LL | impl Tr3<n = 42, T2 = Qux, T3 = usize> for Qux {
2423
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
2524

2625
error[E0658]: associated const equality is incomplete
27-
--> $DIR/associated-types-eq-2.rs:100:14
26+
--> $DIR/associated-types-eq-2.rs:98:14
2827
|
2928
LL | impl Tr3<42, T2 = 42, T3 = usize> for Bar {
3029
| ^^^^^^^
@@ -34,7 +33,7 @@ LL | impl Tr3<42, T2 = 42, T3 = usize> for Bar {
3433
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
3534

3635
error[E0658]: associated const equality is incomplete
37-
--> $DIR/associated-types-eq-2.rs:108:10
36+
--> $DIR/associated-types-eq-2.rs:106:10
3837
|
3938
LL | impl Tr3<X = 42, Y = Qux, Z = usize> for Bar {
4039
| ^^^^^^
@@ -190,30 +189,13 @@ help: to use `GenericTerm<i32>` as a generic argument specify it directly
190189
LL | impl Tr2<i32, Qux, GenericTerm<i32>> for Bar {
191190
| ~~~~~~~~~~~~~~~~
192191

193-
error[E0107]: trait takes 3 generic arguments but 0 generic arguments were supplied
194-
--> $DIR/associated-types-eq-2.rs:76:6
195-
|
196-
LL | impl Tr3<N
197-
| ^^^ expected 3 generic arguments
198-
|
199-
note: trait defined here, with 3 generic parameters: `N`, `T2`, `T3`
200-
--> $DIR/associated-types-eq-2.rs:69:7
201-
|
202-
LL | trait Tr3<const N: i32, T2, T3> {
203-
| ^^^ ------------ -- --
204-
help: add missing generic arguments
205-
|
206-
LL | impl Tr3<N, T2, T3, N
207-
| ++++++++++
208-
209192
error[E0229]: associated item constraints are not allowed here
210193
--> $DIR/associated-types-eq-2.rs:76:10
211194
|
212195
LL | impl Tr3<N
213196
| __________^
214197
LL | |
215198
LL | |
216-
LL | |
217199
LL | | = 42, T2 = Qux, T3 = usize> for Bar {
218200
| |____^ associated item constraint not allowed here
219201
|
@@ -223,7 +205,7 @@ LL | impl Tr3<42, T2 = Qux, T3 = usize> for Bar {
223205
| ~~
224206

225207
error[E0107]: trait takes 3 generic arguments but 0 generic arguments were supplied
226-
--> $DIR/associated-types-eq-2.rs:85:6
208+
--> $DIR/associated-types-eq-2.rs:84:6
227209
|
228210
LL | impl Tr3<n = 42, T2 = Qux, T3 = usize> for Qux {
229211
| ^^^ expected 3 generic arguments
@@ -239,7 +221,7 @@ LL | impl Tr3<N, T2, T3, n = 42, T2 = Qux, T3 = usize> for Qux {
239221
| ++++++++++
240222

241223
error[E0229]: associated item constraints are not allowed here
242-
--> $DIR/associated-types-eq-2.rs:85:10
224+
--> $DIR/associated-types-eq-2.rs:84:10
243225
|
244226
LL | impl Tr3<n = 42, T2 = Qux, T3 = usize> for Qux {
245227
| ^^^^^^ associated item constraint not allowed here
@@ -249,24 +231,8 @@ help: consider removing this associated item binding
249231
LL | impl Tr3<n = 42, T2 = Qux, T3 = usize> for Qux {
250232
| ~~~~~~~
251233

252-
error[E0107]: trait takes 3 generic arguments but 0 generic arguments were supplied
253-
--> $DIR/associated-types-eq-2.rs:93:6
254-
|
255-
LL | impl Tr3<N = u32, T2 = Qux, T3 = usize> for Bar {
256-
| ^^^ expected 3 generic arguments
257-
|
258-
note: trait defined here, with 3 generic parameters: `N`, `T2`, `T3`
259-
--> $DIR/associated-types-eq-2.rs:69:7
260-
|
261-
LL | trait Tr3<const N: i32, T2, T3> {
262-
| ^^^ ------------ -- --
263-
help: add missing generic arguments
264-
|
265-
LL | impl Tr3<N, T2, T3, N = u32, T2 = Qux, T3 = usize> for Bar {
266-
| ++++++++++
267-
268234
error[E0229]: associated item constraints are not allowed here
269-
--> $DIR/associated-types-eq-2.rs:93:10
235+
--> $DIR/associated-types-eq-2.rs:92:10
270236
|
271237
LL | impl Tr3<N = u32, T2 = Qux, T3 = usize> for Bar {
272238
| ^^^^^^^ associated item constraint not allowed here
@@ -277,7 +243,7 @@ LL | impl Tr3<N = u32, T2 = Qux, T3 = usize> for Bar {
277243
| ~~~~~~~~
278244

279245
error[E0107]: trait takes 3 generic arguments but 1 generic argument was supplied
280-
--> $DIR/associated-types-eq-2.rs:100:6
246+
--> $DIR/associated-types-eq-2.rs:98:6
281247
|
282248
LL | impl Tr3<42, T2 = 42, T3 = usize> for Bar {
283249
| ^^^ -- supplied 1 generic argument
@@ -295,7 +261,7 @@ LL | impl Tr3<42, T2, T3, T2 = 42, T3 = usize> for Bar {
295261
| ++++++++
296262

297263
error[E0229]: associated item constraints are not allowed here
298-
--> $DIR/associated-types-eq-2.rs:100:14
264+
--> $DIR/associated-types-eq-2.rs:98:14
299265
|
300266
LL | impl Tr3<42, T2 = 42, T3 = usize> for Bar {
301267
| ^^^^^^^ associated item constraint not allowed here
@@ -306,7 +272,7 @@ LL | impl Tr3<42, T2 = 42, T3 = usize> for Bar {
306272
| ~~~~~~~~~
307273

308274
error[E0107]: trait takes 3 generic arguments but 0 generic arguments were supplied
309-
--> $DIR/associated-types-eq-2.rs:108:6
275+
--> $DIR/associated-types-eq-2.rs:106:6
310276
|
311277
LL | impl Tr3<X = 42, Y = Qux, Z = usize> for Bar {
312278
| ^^^ expected 3 generic arguments
@@ -322,7 +288,7 @@ LL | impl Tr3<N, T2, T3, X = 42, Y = Qux, Z = usize> for Bar {
322288
| ++++++++++
323289

324290
error[E0229]: associated item constraints are not allowed here
325-
--> $DIR/associated-types-eq-2.rs:108:10
291+
--> $DIR/associated-types-eq-2.rs:106:10
326292
|
327293
LL | impl Tr3<X = 42, Y = Qux, Z = usize> for Bar {
328294
| ^^^^^^ associated item constraint not allowed here
@@ -333,13 +299,13 @@ LL | impl Tr3<X = 42, Y = Qux, Z = usize> for Bar {
333299
| ~~~~~~~
334300

335301
error[E0107]: struct takes 1 generic argument but 0 generic arguments were supplied
336-
--> $DIR/associated-types-eq-2.rs:119:13
302+
--> $DIR/associated-types-eq-2.rs:117:13
337303
|
338304
LL | impl<'a, T> St<'a , T = Qux> {
339305
| ^^ expected 1 generic argument
340306
|
341307
note: struct defined here, with 1 generic parameter: `T`
342-
--> $DIR/associated-types-eq-2.rs:117:8
308+
--> $DIR/associated-types-eq-2.rs:115:8
343309
|
344310
LL | struct St<'a, T> { v: &'a T }
345311
| ^^ -
@@ -349,7 +315,7 @@ LL | impl<'a, T> St<'a, T , T = Qux> {
349315
| +++
350316

351317
error[E0229]: associated item constraints are not allowed here
352-
--> $DIR/associated-types-eq-2.rs:119:21
318+
--> $DIR/associated-types-eq-2.rs:117:21
353319
|
354320
LL | impl<'a, T> St<'a , T = Qux> {
355321
| ^^^^^^^ associated item constraint not allowed here
@@ -359,7 +325,7 @@ help: to use `Qux` as a generic argument specify it directly
359325
LL | impl<'a, T> St<'a , Qux> {
360326
| ~~~
361327

362-
error: aborting due to 27 previous errors
328+
error: aborting due to 25 previous errors
363329

364330
Some errors have detailed explanations: E0046, E0107, E0229, E0658.
365331
For more information about an error, try `rustc --explain E0046`.

0 commit comments

Comments
 (0)