@@ -43,6 +43,37 @@ pub(super) enum RecoverQPath {
4343 No ,
4444}
4545
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+
4677// Is `...` (`CVarArgs`) legal at this level of type parsing?
4778#[ derive( PartialEq ) ]
4879enum AllowCVariadic {
@@ -62,14 +93,24 @@ fn can_continue_type_after_non_fn_ident(t: &Token) -> bool {
6293impl < ' a > Parser < ' a > {
6394 /// Parses a type.
6495 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+ )
66102 }
67103
68104 /// Parse a type suitable for a function or function pointer parameter.
69105 /// The difference from `parse_ty` is that this version allows `...`
70106 /// (`CVarArgs`) at the top level of the type.
71107 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+ )
73114 }
74115
75116 /// Parses a type in restricted contexts where `+` is not permitted.
@@ -79,18 +120,58 @@ impl<'a> Parser<'a> {
79120 /// Example 2: `value1 as TYPE + value2`
80121 /// `+` is prohibited to avoid interactions with expression grammar.
81122 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+ )
83139 }
84140
85141 /// Parses an optional return type `[ -> TY ]` in a function declaration.
86142 pub ( super ) fn parse_ret_ty (
87143 & mut self ,
88144 allow_plus : AllowPlus ,
89145 recover_qpath : RecoverQPath ,
146+ recover_return_sign : RecoverReturnSign ,
90147 ) -> PResult < ' a , FnRetTy > {
91148 Ok ( if self . eat ( & token:: RArrow ) {
92149 // 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+ ) ?;
94175 FnRetTy :: Ty ( ty)
95176 } else {
96177 FnRetTy :: Default ( self . token . span . shrink_to_lo ( ) )
@@ -100,8 +181,9 @@ impl<'a> Parser<'a> {
100181 fn parse_ty_common (
101182 & mut self ,
102183 allow_plus : AllowPlus ,
103- recover_qpath : RecoverQPath ,
104184 allow_c_variadic : AllowCVariadic ,
185+ recover_qpath : RecoverQPath ,
186+ recover_return_sign : RecoverReturnSign ,
105187 ) -> PResult < ' a , P < Ty > > {
106188 let allow_qpath_recovery = recover_qpath == RecoverQPath :: Yes ;
107189 maybe_recover_from_interpolated_ty_qpath ! ( self , allow_qpath_recovery) ;
@@ -129,14 +211,14 @@ impl<'a> Parser<'a> {
129211 TyKind :: Infer
130212 } else if self . check_fn_front_matter ( ) {
131213 // Function pointer type
132- self . parse_ty_bare_fn ( lo, Vec :: new ( ) ) ?
214+ self . parse_ty_bare_fn ( lo, Vec :: new ( ) , recover_return_sign ) ?
133215 } else if self . check_keyword ( kw:: For ) {
134216 // Function pointer type or bound list (trait object type) starting with a poly-trait.
135217 // `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T`
136218 // `for<'lt> Trait1<'lt> + Trait2 + 'a`
137219 let lifetime_defs = self . parse_late_bound_lifetime_defs ( ) ?;
138220 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 ) ?
140222 } else {
141223 let path = self . parse_path ( PathStyle :: Type ) ?;
142224 let parse_plus = allow_plus == AllowPlus :: Yes && self . check_plus ( ) ;
@@ -338,9 +420,14 @@ impl<'a> Parser<'a> {
338420 /// Function Style ABI Parameter types
339421 /// ```
340422 /// 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 > {
342429 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 ) ?;
344431 let whole_span = lo. to ( self . prev_token . span ) ;
345432 if let ast:: Const :: Yes ( span) = constness {
346433 self . error_fn_ptr_bad_qualifier ( whole_span, span, "const" ) ;
0 commit comments