Skip to content

Commit f45d2bd

Browse files
authored
Rollup merge of #140228 - fmease:revert-overzealous-colon-recovery, r=jieyouxu
Revert overzealous parse recovery for single colons in paths Basically manually reverts #136808, cc ``@chenyukang`` ``@estebank.`` Reopens #129273. Fixes [after beta backport] #140227.
2 parents 1553cfa + 16da97b commit f45d2bd

9 files changed

+64
-89
lines changed

compiler/rustc_parse/src/parser/item.rs

+11
Original file line numberDiff line numberDiff line change
@@ -2058,6 +2058,17 @@ impl<'a> Parser<'a> {
20582058
}
20592059
self.expect_field_ty_separator()?;
20602060
let ty = self.parse_ty()?;
2061+
if self.token == token::Colon && self.look_ahead(1, |&t| t != token::Colon) {
2062+
self.dcx()
2063+
.struct_span_err(self.token.span, "found single colon in a struct field type path")
2064+
.with_span_suggestion_verbose(
2065+
self.token.span,
2066+
"write a path separator here",
2067+
"::",
2068+
Applicability::MaybeIncorrect,
2069+
)
2070+
.emit();
2071+
}
20612072
let default = if self.token == token::Eq {
20622073
self.bump();
20632074
let const_expr = self.parse_expr_anon_const()?;

compiler/rustc_parse/src/parser/path.rs

+7-13
Original file line numberDiff line numberDiff line change
@@ -248,19 +248,13 @@ impl<'a> Parser<'a> {
248248
segments.push(segment);
249249

250250
if self.is_import_coupler() || !self.eat_path_sep() {
251-
let ok_for_recovery = self.may_recover()
252-
&& match style {
253-
PathStyle::Expr => true,
254-
PathStyle::Type if let Some((ident, _)) = self.prev_token.ident() => {
255-
self.token == token::Colon
256-
&& ident.as_str().chars().all(|c| c.is_lowercase())
257-
&& self.token.span.lo() == self.prev_token.span.hi()
258-
&& self
259-
.look_ahead(1, |token| self.token.span.hi() == token.span.lo())
260-
}
261-
_ => false,
262-
};
263-
if ok_for_recovery
251+
// IMPORTANT: We can *only ever* treat single colons as typo'ed double colons in
252+
// expression contexts (!) since only there paths cannot possibly be followed by
253+
// a colon and still form a syntactically valid construct. In pattern contexts,
254+
// a path may be followed by a type annotation. E.g., `let pat:ty`. In type
255+
// contexts, a path may be followed by a list of bounds. E.g., `where ty:bound`.
256+
if self.may_recover()
257+
&& style == PathStyle::Expr // (!)
264258
&& self.token == token::Colon
265259
&& self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident())
266260
{
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
error: path separator must be a double colon
22
--> $DIR/single-colon-path-not-const-generics.rs:8:18
33
|
4+
LL | pub struct Foo {
5+
| --- while parsing this struct
46
LL | a: Vec<foo::bar:A>,
57
| ^
68
|
79
help: use a double colon instead
810
|
911
LL | a: Vec<foo::bar::A>,
10-
| +
12+
| +
1113

1214
error: aborting due to 1 previous error
1315

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Paths in type contexts may be followed by single colons.
2+
// This means we can't generally assume that the user typo'ed a double colon.
3+
// issue: <https://github.com/rust-lang/rust/issues/140227>
4+
//@ check-pass
5+
#![crate_type = "lib"]
6+
#![expect(non_camel_case_types)]
7+
8+
#[rustfmt::skip]
9+
mod garden {
10+
11+
fn f<path>() where path:to::somewhere {} // OK!
12+
13+
fn g(_: impl Take<path:to::somewhere>) {} // OK!
14+
15+
#[cfg(any())] fn h() where a::path:to::nowhere {} // OK!
16+
17+
fn i(_: impl Take<path::<>:to::somewhere>) {} // OK!
18+
19+
mod to { pub(super) trait somewhere {} }
20+
trait Take { type path; }
21+
22+
}

tests/ui/suggestions/argument-list-from-path-sep-error-129273.fixed

-15
This file was deleted.

tests/ui/suggestions/argument-list-from-path-sep-error-129273.rs

-15
This file was deleted.

tests/ui/suggestions/argument-list-from-path-sep-error-129273.stderr

-13
This file was deleted.

tests/ui/suggestions/struct-field-type-including-single-colon.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ mod foo {
77

88
struct Foo {
99
a: foo:A,
10-
//~^ ERROR path separator must be a double colon
11-
//~| ERROR struct `A` is private
10+
//~^ ERROR found single colon in a struct field type path
11+
//~| ERROR expected `,`, or `}`, found `:`
1212
}
1313

1414
struct Bar {
1515
b: foo::bar:B,
16-
//~^ ERROR path separator must be a double colon
17-
//~| ERROR module `bar` is private
16+
//~^ ERROR found single colon in a struct field type path
17+
//~| ERROR expected `,`, or `}`, found `:`
1818
}
1919

2020
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,40 @@
1-
error: path separator must be a double colon
1+
error: found single colon in a struct field type path
22
--> $DIR/struct-field-type-including-single-colon.rs:9:11
33
|
44
LL | a: foo:A,
55
| ^
66
|
7-
help: use a double colon instead
7+
help: write a path separator here
88
|
99
LL | a: foo::A,
1010
| +
1111

12-
error: path separator must be a double colon
12+
error: expected `,`, or `}`, found `:`
13+
--> $DIR/struct-field-type-including-single-colon.rs:9:11
14+
|
15+
LL | struct Foo {
16+
| --- while parsing this struct
17+
LL | a: foo:A,
18+
| ^
19+
20+
error: found single colon in a struct field type path
1321
--> $DIR/struct-field-type-including-single-colon.rs:15:16
1422
|
1523
LL | b: foo::bar:B,
1624
| ^
1725
|
18-
help: use a double colon instead
26+
help: write a path separator here
1927
|
2028
LL | b: foo::bar::B,
2129
| +
2230

23-
error[E0603]: struct `A` is private
24-
--> $DIR/struct-field-type-including-single-colon.rs:9:12
25-
|
26-
LL | a: foo:A,
27-
| ^ private struct
28-
|
29-
note: the struct `A` is defined here
30-
--> $DIR/struct-field-type-including-single-colon.rs:2:5
31-
|
32-
LL | struct A;
33-
| ^^^^^^^^^
34-
35-
error[E0603]: module `bar` is private
36-
--> $DIR/struct-field-type-including-single-colon.rs:15:13
31+
error: expected `,`, or `}`, found `:`
32+
--> $DIR/struct-field-type-including-single-colon.rs:15:16
3733
|
34+
LL | struct Bar {
35+
| --- while parsing this struct
3836
LL | b: foo::bar:B,
39-
| ^^^ - struct `B` is not publicly re-exported
40-
| |
41-
| private module
42-
|
43-
note: the module `bar` is defined here
44-
--> $DIR/struct-field-type-including-single-colon.rs:3:5
45-
|
46-
LL | mod bar {
47-
| ^^^^^^^
37+
| ^
4838

4939
error: aborting due to 4 previous errors
5040

51-
For more information about this error, try `rustc --explain E0603`.

0 commit comments

Comments
 (0)