Skip to content

Commit 2327196

Browse files
maplemaplethecolor
authored andcommitted
Improve diagnostic when using generic type as type param
1 parent e1a2ec6 commit 2327196

File tree

3 files changed

+57
-0
lines changed

3 files changed

+57
-0
lines changed

compiler/rustc_parse/src/parser/item.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,44 @@ impl<'a> Parser<'a> {
576576
let mut generics = if self.choose_generics_over_qpath(0) {
577577
self.parse_generics()?
578578
} else {
579+
// We might be mistakenly trying to use a generic type as a generic parameter.
580+
// impl<X<T>> Trait for Y<T> { ... }
581+
if self.look_ahead(0, |t| t == &token::Lt)
582+
&& self.look_ahead(1, |t| t.is_ident())
583+
&& self.look_ahead(2, |t| t == &token::Lt)
584+
{
585+
self.bump(); // <
586+
let ident = self.parse_ident()?;
587+
let generics = self.parse_generics()?;
588+
let span = ident.span.to(generics.span);
589+
let snippet = self.span_to_snippet(span).unwrap();
590+
591+
let msg = format!("expected type parameter, found path `{}`", snippet);
592+
let mut err = self.dcx().struct_span_err(span, msg);
593+
err.span_label(span, "expected type parameter, found path");
594+
err.span_suggestion(
595+
span,
596+
"you might have meant to bind a type parameter to a trait",
597+
format!("T: {snippet}"),
598+
Applicability::Unspecified,
599+
);
600+
601+
let mut mapped = String::new();
602+
for i in 0..generics.params.len() {
603+
mapped += &format!("{}: {}", generics.params[i].ident, ident);
604+
if i != (generics.params.len() - 1) {
605+
mapped += ", ";
606+
}
607+
}
608+
err.span_suggestion(span, if generics.params.len() == 1 {
609+
format!("alternatively, you might have meant to bind type parameter `{}` to trait `{}`", generics.params[0].ident.name.as_str(), ident.name.as_str())
610+
} else {
611+
format!("alternatively, you might have meant to bind type parameters to trait `{}`", ident.name.as_str())
612+
}, mapped, Applicability::Unspecified);
613+
614+
return Err(err);
615+
}
616+
579617
let mut generics = Generics::default();
580618
// impl A for B {}
581619
// /\ this is where `generics.span` should point when there are no type params.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
impl<Y<A, B, C>> Z for X<T> {} //~ ERROR: expected type parameter, found path `Y<A, B, C>`
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error: expected type parameter, found path `Y<A, B, C>`
2+
--> $DIR/type-as-type-param.rs:1:6
3+
|
4+
LL | impl<Y<A, B, C>> Z for X<T> {}
5+
| ^^^^^^^^^^ expected type parameter, found path
6+
|
7+
help: you might have meant to bind a type parameter to a trait
8+
|
9+
LL | impl<T: Y<A, B, C>> Z for X<T> {}
10+
| ++
11+
help: alternatively, you might have meant to bind type parameters to trait `Y`
12+
|
13+
LL - impl<Y<A, B, C>> Z for X<T> {}
14+
LL + impl<A: Y, B: Y, C: Y> Z for X<T> {}
15+
|
16+
17+
error: aborting due to 1 previous error
18+

0 commit comments

Comments
 (0)