@@ -43,6 +43,37 @@ pub(super) enum RecoverQPath {
43
43
No ,
44
44
}
45
45
46
+ /// Signals whether parsing a type should recover `->`.
47
+ ///
48
+ /// More specifically, when parsing a function like:
49
+ /// ```rust
50
+ /// fn foo() => u8 { 0 }
51
+ /// fn bar(): u8 { 0 }
52
+ /// ```
53
+ /// The compiler will try to recover interpreting `foo() => u8` as `foo() -> u8` when calling
54
+ /// `parse_ty` with anything except `RecoverReturnSign::No`, and it will try to recover `bar(): u8`
55
+ /// as `bar() -> u8` when passing `RecoverReturnSign::Yes` to `parse_ty`
56
+ #[ derive( Copy , Clone , PartialEq ) ]
57
+ pub ( super ) enum RecoverReturnSign {
58
+ Yes ,
59
+ OnlyFatArrow ,
60
+ No ,
61
+ }
62
+
63
+ impl RecoverReturnSign {
64
+ /// [RecoverReturnSign::Yes] allows for recovering `fn foo() => u8` and `fn foo(): u8`,
65
+ /// [RecoverReturnSign::OnlyFatArrow] allows for recovering only `fn foo() => u8` (recovering
66
+ /// colons can cause problems when parsing where clauses), and
67
+ /// [RecoverReturnSign::No] doesn't allow for any recovery of the return type arrow
68
+ fn can_recover ( self , token : & TokenKind ) -> bool {
69
+ match self {
70
+ Self :: Yes => matches ! ( token, token:: FatArrow | token:: Colon ) ,
71
+ Self :: OnlyFatArrow => matches ! ( token, token:: FatArrow ) ,
72
+ Self :: No => false ,
73
+ }
74
+ }
75
+ }
76
+
46
77
// Is `...` (`CVarArgs`) legal at this level of type parsing?
47
78
#[ derive( PartialEq ) ]
48
79
enum AllowCVariadic {
@@ -62,14 +93,24 @@ fn can_continue_type_after_non_fn_ident(t: &Token) -> bool {
62
93
impl < ' a > Parser < ' a > {
63
94
/// Parses a type.
64
95
pub fn parse_ty ( & mut self ) -> PResult < ' a , P < Ty > > {
65
- self . parse_ty_common ( AllowPlus :: Yes , RecoverQPath :: Yes , AllowCVariadic :: No )
96
+ self . parse_ty_common (
97
+ AllowPlus :: Yes ,
98
+ AllowCVariadic :: No ,
99
+ RecoverQPath :: Yes ,
100
+ RecoverReturnSign :: Yes ,
101
+ )
66
102
}
67
103
68
104
/// Parse a type suitable for a function or function pointer parameter.
69
105
/// The difference from `parse_ty` is that this version allows `...`
70
106
/// (`CVarArgs`) at the top level of the type.
71
107
pub ( super ) fn parse_ty_for_param ( & mut self ) -> PResult < ' a , P < Ty > > {
72
- self . parse_ty_common ( AllowPlus :: Yes , RecoverQPath :: Yes , AllowCVariadic :: Yes )
108
+ self . parse_ty_common (
109
+ AllowPlus :: Yes ,
110
+ AllowCVariadic :: Yes ,
111
+ RecoverQPath :: Yes ,
112
+ RecoverReturnSign :: Yes ,
113
+ )
73
114
}
74
115
75
116
/// Parses a type in restricted contexts where `+` is not permitted.
@@ -79,18 +120,58 @@ impl<'a> Parser<'a> {
79
120
/// Example 2: `value1 as TYPE + value2`
80
121
/// `+` is prohibited to avoid interactions with expression grammar.
81
122
pub ( super ) fn parse_ty_no_plus ( & mut self ) -> PResult < ' a , P < Ty > > {
82
- self . parse_ty_common ( AllowPlus :: No , RecoverQPath :: Yes , AllowCVariadic :: No )
123
+ self . parse_ty_common (
124
+ AllowPlus :: No ,
125
+ AllowCVariadic :: No ,
126
+ RecoverQPath :: Yes ,
127
+ RecoverReturnSign :: Yes ,
128
+ )
129
+ }
130
+
131
+ /// Parse a type without recovering `:` as `->` to avoid breaking code such as `where fn() : for<'a>`
132
+ pub ( super ) fn parse_ty_for_where_clause ( & mut self ) -> PResult < ' a , P < Ty > > {
133
+ self . parse_ty_common (
134
+ AllowPlus :: Yes ,
135
+ AllowCVariadic :: Yes ,
136
+ RecoverQPath :: Yes ,
137
+ RecoverReturnSign :: OnlyFatArrow ,
138
+ )
83
139
}
84
140
85
141
/// Parses an optional return type `[ -> TY ]` in a function declaration.
86
142
pub ( super ) fn parse_ret_ty (
87
143
& mut self ,
88
144
allow_plus : AllowPlus ,
89
145
recover_qpath : RecoverQPath ,
146
+ recover_return_sign : RecoverReturnSign ,
90
147
) -> PResult < ' a , FnRetTy > {
91
148
Ok ( if self . eat ( & token:: RArrow ) {
92
149
// FIXME(Centril): Can we unconditionally `allow_plus`?
93
- let ty = self . parse_ty_common ( allow_plus, recover_qpath, AllowCVariadic :: No ) ?;
150
+ let ty = self . parse_ty_common (
151
+ allow_plus,
152
+ AllowCVariadic :: No ,
153
+ recover_qpath,
154
+ recover_return_sign,
155
+ ) ?;
156
+ FnRetTy :: Ty ( ty)
157
+ } else if recover_return_sign. can_recover ( & self . token . kind ) {
158
+ // Don't `eat` to prevent `=>` from being added as an expected token which isn't
159
+ // actually expected and could only confuse users
160
+ self . bump ( ) ;
161
+ self . struct_span_err ( self . prev_token . span , "return types are denoted using `->`" )
162
+ . span_suggestion_short (
163
+ self . prev_token . span ,
164
+ "use `->` instead" ,
165
+ "->" . to_string ( ) ,
166
+ Applicability :: MachineApplicable ,
167
+ )
168
+ . emit ( ) ;
169
+ let ty = self . parse_ty_common (
170
+ allow_plus,
171
+ AllowCVariadic :: No ,
172
+ recover_qpath,
173
+ recover_return_sign,
174
+ ) ?;
94
175
FnRetTy :: Ty ( ty)
95
176
} else {
96
177
FnRetTy :: Default ( self . token . span . shrink_to_lo ( ) )
@@ -100,8 +181,9 @@ impl<'a> Parser<'a> {
100
181
fn parse_ty_common (
101
182
& mut self ,
102
183
allow_plus : AllowPlus ,
103
- recover_qpath : RecoverQPath ,
104
184
allow_c_variadic : AllowCVariadic ,
185
+ recover_qpath : RecoverQPath ,
186
+ recover_return_sign : RecoverReturnSign ,
105
187
) -> PResult < ' a , P < Ty > > {
106
188
let allow_qpath_recovery = recover_qpath == RecoverQPath :: Yes ;
107
189
maybe_recover_from_interpolated_ty_qpath ! ( self , allow_qpath_recovery) ;
@@ -129,14 +211,14 @@ impl<'a> Parser<'a> {
129
211
TyKind :: Infer
130
212
} else if self . check_fn_front_matter ( ) {
131
213
// Function pointer type
132
- self . parse_ty_bare_fn ( lo, Vec :: new ( ) ) ?
214
+ self . parse_ty_bare_fn ( lo, Vec :: new ( ) , recover_return_sign ) ?
133
215
} else if self . check_keyword ( kw:: For ) {
134
216
// Function pointer type or bound list (trait object type) starting with a poly-trait.
135
217
// `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T`
136
218
// `for<'lt> Trait1<'lt> + Trait2 + 'a`
137
219
let lifetime_defs = self . parse_late_bound_lifetime_defs ( ) ?;
138
220
if self . check_fn_front_matter ( ) {
139
- self . parse_ty_bare_fn ( lo, lifetime_defs) ?
221
+ self . parse_ty_bare_fn ( lo, lifetime_defs, recover_return_sign ) ?
140
222
} else {
141
223
let path = self . parse_path ( PathStyle :: Type ) ?;
142
224
let parse_plus = allow_plus == AllowPlus :: Yes && self . check_plus ( ) ;
@@ -338,9 +420,14 @@ impl<'a> Parser<'a> {
338
420
/// Function Style ABI Parameter types
339
421
/// ```
340
422
/// We actually parse `FnHeader FnDecl`, but we error on `const` and `async` qualifiers.
341
- fn parse_ty_bare_fn ( & mut self , lo : Span , params : Vec < GenericParam > ) -> PResult < ' a , TyKind > {
423
+ fn parse_ty_bare_fn (
424
+ & mut self ,
425
+ lo : Span ,
426
+ params : Vec < GenericParam > ,
427
+ recover_return_sign : RecoverReturnSign ,
428
+ ) -> PResult < ' a , TyKind > {
342
429
let ast:: FnHeader { ext, unsafety, constness, asyncness } = self . parse_fn_front_matter ( ) ?;
343
- let decl = self . parse_fn_decl ( |_| false , AllowPlus :: No ) ?;
430
+ let decl = self . parse_fn_decl ( |_| false , AllowPlus :: No , recover_return_sign ) ?;
344
431
let whole_span = lo. to ( self . prev_token . span ) ;
345
432
if let ast:: Const :: Yes ( span) = constness {
346
433
self . error_fn_ptr_bad_qualifier ( whole_span, span, "const" ) ;
0 commit comments