diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index b5b628a3f55bd..534fd0d4816dd 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -2369,6 +2369,34 @@ impl<'a> Parser<'a> { Err(err) } + crate fn maybe_recover_bounds_doubled_colon(&mut self, ty: &Ty) -> PResult<'a, ()> { + let TyKind::Path(qself, path) = &ty.kind else { return Ok(()) }; + let qself_position = qself.as_ref().map(|qself| qself.position); + for (i, segments) in path.segments.windows(2).enumerate() { + if qself_position.map(|pos| i < pos).unwrap_or(false) { + continue; + } + if let [a, b] = segments { + let (a_span, b_span) = (a.span(), b.span()); + let between_span = a_span.shrink_to_hi().to(b_span.shrink_to_lo()); + if self.span_to_snippet(between_span).as_ref().map(|a| &a[..]) == Ok(":: ") { + let mut err = self.struct_span_err( + path.span.shrink_to_hi(), + "expected `:` followed by trait or lifetime", + ); + err.span_suggestion( + between_span, + "use single colon", + ": ".to_owned(), + Applicability::MachineApplicable, + ); + return Err(err); + } + } + } + Ok(()) + } + /// Parse and throw away a parenthesized comma separated /// sequence of patterns until `)` is reached. fn skip_pat_list(&mut self) -> PResult<'a, ()> { diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index d625080dee4fd..29fe2b761018e 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -312,6 +312,7 @@ impl<'a> Parser<'a> { id: ast::DUMMY_NODE_ID, })) } else { + self.maybe_recover_bounds_doubled_colon(&ty)?; self.unexpected() } } diff --git a/src/test/ui/generics/issue-95208-ignore-qself.fixed b/src/test/ui/generics/issue-95208-ignore-qself.fixed new file mode 100644 index 0000000000000..608b4a20fbc86 --- /dev/null +++ b/src/test/ui/generics/issue-95208-ignore-qself.fixed @@ -0,0 +1,11 @@ +// run-rustfix + +#[allow(unused)] +struct Struct(T); + +impl Struct where ::Item: std::fmt::Display { +//~^ ERROR expected `:` followed by trait or lifetime +//~| HELP use single colon +} + +fn main() {} diff --git a/src/test/ui/generics/issue-95208-ignore-qself.rs b/src/test/ui/generics/issue-95208-ignore-qself.rs new file mode 100644 index 0000000000000..da7efd576d1cf --- /dev/null +++ b/src/test/ui/generics/issue-95208-ignore-qself.rs @@ -0,0 +1,11 @@ +// run-rustfix + +#[allow(unused)] +struct Struct(T); + +impl Struct where ::Item:: std::fmt::Display { +//~^ ERROR expected `:` followed by trait or lifetime +//~| HELP use single colon +} + +fn main() {} diff --git a/src/test/ui/generics/issue-95208-ignore-qself.stderr b/src/test/ui/generics/issue-95208-ignore-qself.stderr new file mode 100644 index 0000000000000..acbc1300d00fd --- /dev/null +++ b/src/test/ui/generics/issue-95208-ignore-qself.stderr @@ -0,0 +1,10 @@ +error: expected `:` followed by trait or lifetime + --> $DIR/issue-95208-ignore-qself.rs:6:88 + | +LL | impl Struct where ::Item:: std::fmt::Display { + | --- ^ + | | + | help: use single colon: `:` + +error: aborting due to previous error + diff --git a/src/test/ui/generics/issue-95208.fixed b/src/test/ui/generics/issue-95208.fixed new file mode 100644 index 0000000000000..a0b1e886ca268 --- /dev/null +++ b/src/test/ui/generics/issue-95208.fixed @@ -0,0 +1,11 @@ +// run-rustfix + +#[allow(unused)] +struct Struct(T); + +impl Struct where T: std::fmt::Display { +//~^ ERROR expected `:` followed by trait or lifetime +//~| HELP use single colon +} + +fn main() {} diff --git a/src/test/ui/generics/issue-95208.rs b/src/test/ui/generics/issue-95208.rs new file mode 100644 index 0000000000000..0e3083484ff15 --- /dev/null +++ b/src/test/ui/generics/issue-95208.rs @@ -0,0 +1,11 @@ +// run-rustfix + +#[allow(unused)] +struct Struct(T); + +impl Struct where T:: std::fmt::Display { +//~^ ERROR expected `:` followed by trait or lifetime +//~| HELP use single colon +} + +fn main() {} diff --git a/src/test/ui/generics/issue-95208.stderr b/src/test/ui/generics/issue-95208.stderr new file mode 100644 index 0000000000000..559527663e8a8 --- /dev/null +++ b/src/test/ui/generics/issue-95208.stderr @@ -0,0 +1,10 @@ +error: expected `:` followed by trait or lifetime + --> $DIR/issue-95208.rs:6:46 + | +LL | impl Struct where T:: std::fmt::Display { + | --- ^ + | | + | help: use single colon: `:` + +error: aborting due to previous error +