]>
Commit | Line | Data |
---|---|---|
1a4d82fc | 1 | // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT |
223e47cc LB |
2 | // file at the top-level directory of this distribution and at |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
83c7162d | 11 | use rustc_target::spec::abi::{self, Abi}; |
8faf50e0 XL |
12 | use ast::{AngleBracketedArgs, ParenthesisedArgs, AttrStyle, BareFnTy}; |
13 | use ast::{GenericBound, TraitBoundModifier}; | |
7453a54e | 14 | use ast::Unsafety; |
b7449926 | 15 | use ast::{Mod, AnonConst, Arg, Arm, Guard, Attribute, BindingMode, TraitItemKind}; |
7453a54e | 16 | use ast::Block; |
2c00a5a8 | 17 | use ast::{BlockCheckMode, CaptureBy, Movability}; |
c30ab7b3 | 18 | use ast::{Constness, Crate}; |
3157f602 XL |
19 | use ast::Defaultness; |
20 | use ast::EnumDef; | |
54a0048b | 21 | use ast::{Expr, ExprKind, RangeLimits}; |
8faf50e0 | 22 | use ast::{Field, FnDecl, FnHeader}; |
7453a54e | 23 | use ast::{ForeignItem, ForeignItemKind, FunctionRetTy}; |
8faf50e0 XL |
24 | use ast::{GenericParam, GenericParamKind}; |
25 | use ast::GenericArg; | |
26 | use ast::{Ident, ImplItem, IsAsync, IsAuto, Item, ItemKind}; | |
27 | use ast::{Label, Lifetime, Lit, LitKind}; | |
7453a54e SL |
28 | use ast::Local; |
29 | use ast::MacStmtStyle; | |
94b46f34 | 30 | use ast::{Mac, Mac_, MacDelimiter}; |
7453a54e | 31 | use ast::{MutTy, Mutability}; |
8bb4bdeb | 32 | use ast::{Pat, PatKind, PathSegment}; |
c34b1796 | 33 | use ast::{PolyTraitRef, QSelf}; |
7453a54e SL |
34 | use ast::{Stmt, StmtKind}; |
35 | use ast::{VariantData, StructField}; | |
36 | use ast::StrStyle; | |
37 | use ast::SelfKind; | |
abe05a73 | 38 | use ast::{TraitItem, TraitRef, TraitObjectSyntax}; |
8faf50e0 | 39 | use ast::{Ty, TyKind, TypeBinding, GenericBounds}; |
0531ce1d | 40 | use ast::{Visibility, VisibilityKind, WhereClause, CrateSugar}; |
ff7c6d11 | 41 | use ast::{UseTree, UseTreeKind}; |
7453a54e | 42 | use ast::{BinOpKind, UnOp}; |
ea8adc8c | 43 | use ast::{RangeEnd, RangeSyntax}; |
476ff2be | 44 | use {ast, attr}; |
b7449926 | 45 | use source_map::{self, SourceMap, Spanned, respan}; |
8faf50e0 | 46 | use syntax_pos::{self, Span, MultiSpan, BytePos, FileName, edition::Edition}; |
b7449926 | 47 | use errors::{self, Applicability, DiagnosticBuilder, DiagnosticId}; |
94b46f34 | 48 | use parse::{self, SeqSep, classify, token}; |
32a655c1 | 49 | use parse::lexer::TokenAndSpan; |
8bb4bdeb | 50 | use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; |
476ff2be | 51 | use parse::{new_sub_parser_from_file, ParseSess, Directory, DirectoryOwnership}; |
92a42be0 | 52 | use util::parser::{AssocOp, Fixity}; |
1a4d82fc JJ |
53 | use print::pprust; |
54 | use ptr::P; | |
9346a6ac | 55 | use parse::PResult; |
b7449926 XL |
56 | use ThinVec; |
57 | use tokenstream::{self, Delimited, DelimSpan, ThinTokenStream, TokenTree, TokenStream}; | |
476ff2be | 58 | use symbol::{Symbol, keywords}; |
1a4d82fc | 59 | |
94b46f34 | 60 | use std::borrow::Cow; |
7cac9316 | 61 | use std::cmp; |
7cac9316 | 62 | use std::mem; |
cc61c64b | 63 | use std::path::{self, Path, PathBuf}; |
7cac9316 | 64 | use std::slice; |
32a655c1 | 65 | |
8faf50e0 XL |
66 | #[derive(Debug)] |
67 | /// Whether the type alias or associated type is a concrete type or an existential type | |
68 | pub enum AliasKind { | |
69 | /// Just a new name for the same type | |
70 | Weak(P<Ty>), | |
71 | /// Only trait impls of the type will be usable, not the actual type itself | |
72 | Existential(GenericBounds), | |
73 | } | |
74 | ||
1a4d82fc | 75 | bitflags! { |
94b46f34 | 76 | struct Restrictions: u8 { |
ea8adc8c XL |
77 | const STMT_EXPR = 1 << 0; |
78 | const NO_STRUCT_LITERAL = 1 << 1; | |
1a4d82fc | 79 | } |
223e47cc LB |
80 | } |
81 | ||
2c00a5a8 | 82 | type ItemInfo = (Ident, ItemKind, Option<Vec<Attribute>>); |
1a4d82fc | 83 | |
3b2f2976 | 84 | /// How to parse a path. |
c34b1796 | 85 | #[derive(Copy, Clone, PartialEq)] |
a7813a04 | 86 | pub enum PathStyle { |
3b2f2976 XL |
87 | /// In some contexts, notably in expressions, paths with generic arguments are ambiguous |
88 | /// with something else. For example, in expressions `segment < ....` can be interpreted | |
89 | /// as a comparison and `segment ( ....` can be interpreted as a function call. | |
90 | /// In all such contexts the non-path interpretation is preferred by default for practical | |
91 | /// reasons, but the path interpretation can be forced by the disambiguator `::`, e.g. | |
92 | /// `x<y>` - comparisons, `x::<y>` - unambiguously a path. | |
a7813a04 | 93 | Expr, |
3b2f2976 XL |
94 | /// In other contexts, notably in types, no ambiguity exists and paths can be written |
95 | /// without the disambiguator, e.g. `x<y>` - unambiguously a path. | |
96 | /// Paths with disambiguators are still accepted, `x::<Y>` - unambiguously a path too. | |
97 | Type, | |
98 | /// A path with generic arguments disallowed, e.g. `foo::bar::Baz`, used in imports, | |
99 | /// visibilities or attributes. | |
100 | /// Technically, this variant is unnecessary and e.g. `Expr` can be used instead | |
101 | /// (paths in "mod" contexts have to be checked later for absence of generic arguments | |
102 | /// anyway, due to macros), but it is used to avoid weird suggestions about expected | |
103 | /// tokens when something goes wrong. | |
104 | Mod, | |
1a4d82fc JJ |
105 | } |
106 | ||
8faf50e0 | 107 | #[derive(Clone, Copy, PartialEq, Debug)] |
94b46f34 | 108 | enum SemiColonMode { |
7453a54e SL |
109 | Break, |
110 | Ignore, | |
111 | } | |
112 | ||
8faf50e0 | 113 | #[derive(Clone, Copy, PartialEq, Debug)] |
94b46f34 | 114 | enum BlockMode { |
cc61c64b XL |
115 | Break, |
116 | Ignore, | |
117 | } | |
118 | ||
1a4d82fc JJ |
119 | /// Possibly accept an `token::Interpolated` expression (a pre-parsed expression |
120 | /// dropped into the token stream, which happens while parsing the result of | |
121 | /// macro expansion). Placement of these is not as complex as I feared it would | |
122 | /// be. The important thing is to make sure that lookahead doesn't balk at | |
123 | /// `token::Interpolated` tokens. | |
124 | macro_rules! maybe_whole_expr { | |
c30ab7b3 SL |
125 | ($p:expr) => { |
126 | if let token::Interpolated(nt) = $p.token.clone() { | |
041b39d2 | 127 | match nt.0 { |
94b46f34 | 128 | token::NtExpr(ref e) | token::NtLiteral(ref e) => { |
c30ab7b3 SL |
129 | $p.bump(); |
130 | return Ok((*e).clone()); | |
1a4d82fc | 131 | } |
c30ab7b3 SL |
132 | token::NtPath(ref path) => { |
133 | $p.bump(); | |
1a4d82fc | 134 | let span = $p.span; |
c30ab7b3 | 135 | let kind = ExprKind::Path(None, (*path).clone()); |
cc61c64b | 136 | return Ok($p.mk_expr(span, kind, ThinVec::new())); |
1a4d82fc | 137 | } |
c30ab7b3 SL |
138 | token::NtBlock(ref block) => { |
139 | $p.bump(); | |
1a4d82fc | 140 | let span = $p.span; |
94b46f34 | 141 | let kind = ExprKind::Block((*block).clone(), None); |
cc61c64b | 142 | return Ok($p.mk_expr(span, kind, ThinVec::new())); |
1a4d82fc | 143 | } |
c30ab7b3 | 144 | _ => {}, |
1a4d82fc | 145 | }; |
223e47cc | 146 | } |
c30ab7b3 | 147 | } |
1a4d82fc | 148 | } |
223e47cc | 149 | |
1a4d82fc JJ |
150 | /// As maybe_whole_expr, but for things other than expressions |
151 | macro_rules! maybe_whole { | |
c30ab7b3 SL |
152 | ($p:expr, $constructor:ident, |$x:ident| $e:expr) => { |
153 | if let token::Interpolated(nt) = $p.token.clone() { | |
041b39d2 | 154 | if let token::$constructor($x) = nt.0.clone() { |
c30ab7b3 SL |
155 | $p.bump(); |
156 | return Ok($e); | |
223e47cc | 157 | } |
1a4d82fc | 158 | } |
c30ab7b3 | 159 | }; |
1a4d82fc | 160 | } |
223e47cc | 161 | |
2c00a5a8 XL |
162 | fn maybe_append(mut lhs: Vec<Attribute>, mut rhs: Option<Vec<Attribute>>) -> Vec<Attribute> { |
163 | if let Some(ref mut rhs) = rhs { | |
164 | lhs.append(rhs); | |
223e47cc | 165 | } |
1a4d82fc | 166 | lhs |
223e47cc LB |
167 | } |
168 | ||
3b2f2976 | 169 | #[derive(Debug, Clone, Copy, PartialEq)] |
c30ab7b3 | 170 | enum PrevTokenKind { |
9e0c209e SL |
171 | DocComment, |
172 | Comma, | |
cc61c64b | 173 | Plus, |
9e0c209e SL |
174 | Interpolated, |
175 | Eof, | |
041b39d2 | 176 | Ident, |
9e0c209e SL |
177 | Other, |
178 | } | |
179 | ||
ff7c6d11 XL |
180 | trait RecoverQPath: Sized { |
181 | const PATH_STYLE: PathStyle = PathStyle::Expr; | |
182 | fn to_ty(&self) -> Option<P<Ty>>; | |
183 | fn to_recovered(&self, qself: Option<QSelf>, path: ast::Path) -> Self; | |
184 | fn to_string(&self) -> String; | |
185 | } | |
186 | ||
187 | impl RecoverQPath for Ty { | |
188 | const PATH_STYLE: PathStyle = PathStyle::Type; | |
189 | fn to_ty(&self) -> Option<P<Ty>> { | |
190 | Some(P(self.clone())) | |
191 | } | |
192 | fn to_recovered(&self, qself: Option<QSelf>, path: ast::Path) -> Self { | |
193 | Self { span: path.span, node: TyKind::Path(qself, path), id: self.id } | |
194 | } | |
195 | fn to_string(&self) -> String { | |
196 | pprust::ty_to_string(self) | |
197 | } | |
198 | } | |
199 | ||
200 | impl RecoverQPath for Pat { | |
201 | fn to_ty(&self) -> Option<P<Ty>> { | |
202 | self.to_ty() | |
203 | } | |
204 | fn to_recovered(&self, qself: Option<QSelf>, path: ast::Path) -> Self { | |
205 | Self { span: path.span, node: PatKind::Path(qself, path), id: self.id } | |
206 | } | |
207 | fn to_string(&self) -> String { | |
208 | pprust::pat_to_string(self) | |
209 | } | |
210 | } | |
211 | ||
212 | impl RecoverQPath for Expr { | |
213 | fn to_ty(&self) -> Option<P<Ty>> { | |
214 | self.to_ty() | |
215 | } | |
216 | fn to_recovered(&self, qself: Option<QSelf>, path: ast::Path) -> Self { | |
217 | Self { span: path.span, node: ExprKind::Path(qself, path), | |
218 | id: self.id, attrs: self.attrs.clone() } | |
219 | } | |
220 | fn to_string(&self) -> String { | |
221 | pprust::expr_to_string(self) | |
222 | } | |
223 | } | |
224 | ||
223e47cc LB |
225 | /* ident is handled by common.rs */ |
226 | ||
041b39d2 | 227 | #[derive(Clone)] |
1a4d82fc JJ |
228 | pub struct Parser<'a> { |
229 | pub sess: &'a ParseSess, | |
230 | /// the current token: | |
231 | pub token: token::Token, | |
232 | /// the span of the current token: | |
233 | pub span: Span, | |
c30ab7b3 | 234 | /// the span of the previous token: |
94b46f34 | 235 | meta_var_span: Option<Span>, |
c30ab7b3 | 236 | pub prev_span: Span, |
9e0c209e | 237 | /// the previous token kind |
c30ab7b3 | 238 | prev_token_kind: PrevTokenKind, |
94b46f34 | 239 | restrictions: Restrictions, |
223e47cc | 240 | /// Used to determine the path to externally loaded source files |
94b46f34 | 241 | crate directory: Directory<'a>, |
7cac9316 XL |
242 | /// Whether to parse sub-modules in other files. |
243 | pub recurse_into_file_modules: bool, | |
1a4d82fc JJ |
244 | /// Name of the root module this parser originated from. If `None`, then the |
245 | /// name is not known. This does not change while the parser is descending | |
246 | /// into modules, and sub-parsers have new values for this name. | |
247 | pub root_module_name: Option<String>, | |
94b46f34 | 248 | crate expected_tokens: Vec<TokenType>, |
8bb4bdeb | 249 | token_cursor: TokenCursor, |
94b46f34 | 250 | desugar_doc_comments: bool, |
32a655c1 SL |
251 | /// Whether we should configure out of line modules as we parse. |
252 | pub cfg_mods: bool, | |
1a4d82fc JJ |
253 | } |
254 | ||
7cac9316 | 255 | |
041b39d2 | 256 | #[derive(Clone)] |
8bb4bdeb XL |
257 | struct TokenCursor { |
258 | frame: TokenCursorFrame, | |
259 | stack: Vec<TokenCursorFrame>, | |
260 | } | |
261 | ||
041b39d2 | 262 | #[derive(Clone)] |
8bb4bdeb XL |
263 | struct TokenCursorFrame { |
264 | delim: token::DelimToken, | |
b7449926 | 265 | span: DelimSpan, |
8bb4bdeb XL |
266 | open_delim: bool, |
267 | tree_cursor: tokenstream::Cursor, | |
268 | close_delim: bool, | |
3b2f2976 XL |
269 | last_token: LastToken, |
270 | } | |
271 | ||
272 | /// This is used in `TokenCursorFrame` above to track tokens that are consumed | |
273 | /// by the parser, and then that's transitively used to record the tokens that | |
274 | /// each parse AST item is created with. | |
275 | /// | |
276 | /// Right now this has two states, either collecting tokens or not collecting | |
277 | /// tokens. If we're collecting tokens we just save everything off into a local | |
278 | /// `Vec`. This should eventually though likely save tokens from the original | |
279 | /// token stream and just use slicing of token streams to avoid creation of a | |
280 | /// whole new vector. | |
281 | /// | |
282 | /// The second state is where we're passively not recording tokens, but the last | |
283 | /// token is still tracked for when we want to start recording tokens. This | |
284 | /// "last token" means that when we start recording tokens we'll want to ensure | |
285 | /// that this, the first token, is included in the output. | |
286 | /// | |
287 | /// You can find some more example usage of this in the `collect_tokens` method | |
288 | /// on the parser. | |
289 | #[derive(Clone)] | |
290 | enum LastToken { | |
8faf50e0 XL |
291 | Collecting(Vec<TokenStream>), |
292 | Was(Option<TokenStream>), | |
8bb4bdeb XL |
293 | } |
294 | ||
295 | impl TokenCursorFrame { | |
b7449926 | 296 | fn new(sp: DelimSpan, delimited: &Delimited) -> Self { |
8bb4bdeb XL |
297 | TokenCursorFrame { |
298 | delim: delimited.delim, | |
299 | span: sp, | |
300 | open_delim: delimited.delim == token::NoDelim, | |
301 | tree_cursor: delimited.stream().into_trees(), | |
302 | close_delim: delimited.delim == token::NoDelim, | |
3b2f2976 | 303 | last_token: LastToken::Was(None), |
8bb4bdeb XL |
304 | } |
305 | } | |
306 | } | |
307 | ||
308 | impl TokenCursor { | |
309 | fn next(&mut self) -> TokenAndSpan { | |
310 | loop { | |
311 | let tree = if !self.frame.open_delim { | |
312 | self.frame.open_delim = true; | |
313 | Delimited { delim: self.frame.delim, tts: TokenStream::empty().into() } | |
b7449926 | 314 | .open_tt(self.frame.span.open) |
8bb4bdeb XL |
315 | } else if let Some(tree) = self.frame.tree_cursor.next() { |
316 | tree | |
317 | } else if !self.frame.close_delim { | |
318 | self.frame.close_delim = true; | |
319 | Delimited { delim: self.frame.delim, tts: TokenStream::empty().into() } | |
b7449926 | 320 | .close_tt(self.frame.span.close) |
8bb4bdeb XL |
321 | } else if let Some(frame) = self.stack.pop() { |
322 | self.frame = frame; | |
323 | continue | |
324 | } else { | |
325 | return TokenAndSpan { tok: token::Eof, sp: syntax_pos::DUMMY_SP } | |
326 | }; | |
327 | ||
3b2f2976 | 328 | match self.frame.last_token { |
8faf50e0 XL |
329 | LastToken::Collecting(ref mut v) => v.push(tree.clone().into()), |
330 | LastToken::Was(ref mut t) => *t = Some(tree.clone().into()), | |
3b2f2976 XL |
331 | } |
332 | ||
8bb4bdeb XL |
333 | match tree { |
334 | TokenTree::Token(sp, tok) => return TokenAndSpan { tok: tok, sp: sp }, | |
335 | TokenTree::Delimited(sp, ref delimited) => { | |
336 | let frame = TokenCursorFrame::new(sp, delimited); | |
337 | self.stack.push(mem::replace(&mut self.frame, frame)); | |
338 | } | |
339 | } | |
340 | } | |
341 | } | |
342 | ||
343 | fn next_desugared(&mut self) -> TokenAndSpan { | |
344 | let (sp, name) = match self.next() { | |
345 | TokenAndSpan { sp, tok: token::DocComment(name) } => (sp, name), | |
7cac9316 | 346 | tok => return tok, |
8bb4bdeb XL |
347 | }; |
348 | ||
349 | let stripped = strip_doc_comment_decoration(&name.as_str()); | |
350 | ||
351 | // Searches for the occurrences of `"#*` and returns the minimum number of `#`s | |
352 | // required to wrap the text. | |
353 | let mut num_of_hashes = 0; | |
354 | let mut count = 0; | |
355 | for ch in stripped.chars() { | |
356 | count = match ch { | |
357 | '"' => 1, | |
358 | '#' if count > 0 => count + 1, | |
359 | _ => 0, | |
360 | }; | |
361 | num_of_hashes = cmp::max(num_of_hashes, count); | |
362 | } | |
363 | ||
b7449926 XL |
364 | let delim_span = DelimSpan::from_single(sp); |
365 | let body = TokenTree::Delimited(delim_span, Delimited { | |
8bb4bdeb | 366 | delim: token::Bracket, |
0531ce1d | 367 | tts: [TokenTree::Token(sp, token::Ident(ast::Ident::from_str("doc"), false)), |
8bb4bdeb XL |
368 | TokenTree::Token(sp, token::Eq), |
369 | TokenTree::Token(sp, token::Literal( | |
370 | token::StrRaw(Symbol::intern(&stripped), num_of_hashes), None))] | |
371 | .iter().cloned().collect::<TokenStream>().into(), | |
372 | }); | |
373 | ||
b7449926 | 374 | self.stack.push(mem::replace(&mut self.frame, TokenCursorFrame::new(delim_span, &Delimited { |
8bb4bdeb XL |
375 | delim: token::NoDelim, |
376 | tts: if doc_comment_style(&name.as_str()) == AttrStyle::Inner { | |
377 | [TokenTree::Token(sp, token::Pound), TokenTree::Token(sp, token::Not), body] | |
378 | .iter().cloned().collect::<TokenStream>().into() | |
379 | } else { | |
380 | [TokenTree::Token(sp, token::Pound), body] | |
381 | .iter().cloned().collect::<TokenStream>().into() | |
382 | }, | |
383 | }))); | |
384 | ||
385 | self.next() | |
386 | } | |
387 | } | |
388 | ||
8faf50e0 | 389 | #[derive(Clone, PartialEq)] |
94b46f34 | 390 | crate enum TokenType { |
1a4d82fc | 391 | Token(token::Token), |
85aaf69f | 392 | Keyword(keywords::Keyword), |
1a4d82fc | 393 | Operator, |
32a655c1 SL |
394 | Lifetime, |
395 | Ident, | |
396 | Path, | |
397 | Type, | |
1a4d82fc | 398 | } |
223e47cc | 399 | |
1a4d82fc JJ |
400 | impl TokenType { |
401 | fn to_string(&self) -> String { | |
402 | match *self { | |
94b46f34 | 403 | TokenType::Token(ref t) => format!("`{}`", pprust::token_to_string(t)), |
a7813a04 | 404 | TokenType::Keyword(kw) => format!("`{}`", kw.name()), |
32a655c1 SL |
405 | TokenType::Operator => "an operator".to_string(), |
406 | TokenType::Lifetime => "lifetime".to_string(), | |
407 | TokenType::Ident => "identifier".to_string(), | |
408 | TokenType::Path => "path".to_string(), | |
409 | TokenType::Type => "type".to_string(), | |
1a4d82fc JJ |
410 | } |
411 | } | |
223e47cc LB |
412 | } |
413 | ||
0531ce1d XL |
414 | /// Returns true if `IDENT t` can start a type - `IDENT::a::b`, `IDENT<u8, u8>`, |
415 | /// `IDENT<<u8 as Trait>::AssocTy>`. | |
416 | /// | |
417 | /// Types can also be of the form `IDENT(u8, u8) -> u8`, however this assumes | |
418 | /// that IDENT is not the ident of a fn trait | |
419 | fn can_continue_type_after_non_fn_ident(t: &token::Token) -> bool { | |
abe05a73 | 420 | t == &token::ModSep || t == &token::Lt || |
0531ce1d | 421 | t == &token::BinOp(token::Shl) |
223e47cc LB |
422 | } |
423 | ||
c1a9b12d SL |
424 | /// Information about the path to a module. |
425 | pub struct ModulePath { | |
94b46f34 XL |
426 | name: String, |
427 | path_exists: bool, | |
8bb4bdeb | 428 | pub result: Result<ModulePathSuccess, Error>, |
c1a9b12d SL |
429 | } |
430 | ||
431 | pub struct ModulePathSuccess { | |
476ff2be SL |
432 | pub path: PathBuf, |
433 | pub directory_ownership: DirectoryOwnership, | |
434 | warn: bool, | |
c1a9b12d SL |
435 | } |
436 | ||
8bb4bdeb XL |
437 | pub enum Error { |
438 | FileNotFoundForModule { | |
439 | mod_name: String, | |
440 | default_path: String, | |
441 | secondary_path: String, | |
442 | dir_path: String, | |
443 | }, | |
444 | DuplicatePaths { | |
445 | mod_name: String, | |
446 | default_path: String, | |
447 | secondary_path: String, | |
448 | }, | |
449 | UselessDocComment, | |
450 | InclusiveRangeWithNoEnd, | |
451 | } | |
452 | ||
453 | impl Error { | |
94b46f34 | 454 | fn span_err<S: Into<MultiSpan>>(self, |
2c00a5a8 XL |
455 | sp: S, |
456 | handler: &errors::Handler) -> DiagnosticBuilder { | |
8bb4bdeb XL |
457 | match self { |
458 | Error::FileNotFoundForModule { ref mod_name, | |
459 | ref default_path, | |
460 | ref secondary_path, | |
461 | ref dir_path } => { | |
462 | let mut err = struct_span_err!(handler, sp, E0583, | |
463 | "file not found for module `{}`", mod_name); | |
0531ce1d | 464 | err.help(&format!("name the file either {} or {} inside the directory \"{}\"", |
8bb4bdeb XL |
465 | default_path, |
466 | secondary_path, | |
467 | dir_path)); | |
468 | err | |
469 | } | |
470 | Error::DuplicatePaths { ref mod_name, ref default_path, ref secondary_path } => { | |
471 | let mut err = struct_span_err!(handler, sp, E0584, | |
472 | "file for module `{}` found at both {} and {}", | |
473 | mod_name, | |
474 | default_path, | |
475 | secondary_path); | |
476 | err.help("delete or rename one of them to remove the ambiguity"); | |
477 | err | |
478 | } | |
479 | Error::UselessDocComment => { | |
480 | let mut err = struct_span_err!(handler, sp, E0585, | |
481 | "found a documentation comment that doesn't document anything"); | |
482 | err.help("doc comments must come before what they document, maybe a comment was \ | |
483 | intended with `//`?"); | |
484 | err | |
485 | } | |
486 | Error::InclusiveRangeWithNoEnd => { | |
487 | let mut err = struct_span_err!(handler, sp, E0586, | |
488 | "inclusive range with no end"); | |
ea8adc8c | 489 | err.help("inclusive ranges must be bounded at the end (`..=b` or `a..=b`)"); |
8bb4bdeb XL |
490 | err |
491 | } | |
492 | } | |
493 | } | |
494 | } | |
495 | ||
041b39d2 | 496 | #[derive(Debug)] |
94b46f34 | 497 | enum LhsExpr { |
92a42be0 | 498 | NotYetParsed, |
3157f602 | 499 | AttributesParsed(ThinVec<Attribute>), |
92a42be0 SL |
500 | AlreadyParsed(P<Expr>), |
501 | } | |
502 | ||
3157f602 XL |
503 | impl From<Option<ThinVec<Attribute>>> for LhsExpr { |
504 | fn from(o: Option<ThinVec<Attribute>>) -> Self { | |
92a42be0 SL |
505 | if let Some(attrs) = o { |
506 | LhsExpr::AttributesParsed(attrs) | |
507 | } else { | |
508 | LhsExpr::NotYetParsed | |
509 | } | |
510 | } | |
511 | } | |
512 | ||
513 | impl From<P<Expr>> for LhsExpr { | |
514 | fn from(expr: P<Expr>) -> Self { | |
515 | LhsExpr::AlreadyParsed(expr) | |
516 | } | |
517 | } | |
c1a9b12d | 518 | |
cc61c64b XL |
519 | /// Create a placeholder argument. |
520 | fn dummy_arg(span: Span) -> Arg { | |
83c7162d | 521 | let ident = Ident::new(keywords::Invalid.name(), span); |
cc61c64b XL |
522 | let pat = P(Pat { |
523 | id: ast::DUMMY_NODE_ID, | |
83c7162d | 524 | node: PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), ident, None), |
3b2f2976 | 525 | span, |
cc61c64b XL |
526 | }); |
527 | let ty = Ty { | |
528 | node: TyKind::Err, | |
3b2f2976 | 529 | span, |
cc61c64b XL |
530 | id: ast::DUMMY_NODE_ID |
531 | }; | |
532 | Arg { ty: P(ty), pat: pat, id: ast::DUMMY_NODE_ID } | |
533 | } | |
534 | ||
8faf50e0 | 535 | #[derive(Copy, Clone, Debug)] |
ea8adc8c XL |
536 | enum TokenExpectType { |
537 | Expect, | |
538 | NoExpect, | |
539 | } | |
540 | ||
1a4d82fc | 541 | impl<'a> Parser<'a> { |
476ff2be | 542 | pub fn new(sess: &'a ParseSess, |
8bb4bdeb | 543 | tokens: TokenStream, |
94b46f34 | 544 | directory: Option<Directory<'a>>, |
7cac9316 | 545 | recurse_into_file_modules: bool, |
476ff2be SL |
546 | desugar_doc_comments: bool) |
547 | -> Self { | |
c30ab7b3 | 548 | let mut parser = Parser { |
3b2f2976 | 549 | sess, |
0531ce1d | 550 | token: token::Whitespace, |
c30ab7b3 SL |
551 | span: syntax_pos::DUMMY_SP, |
552 | prev_span: syntax_pos::DUMMY_SP, | |
cc61c64b | 553 | meta_var_span: None, |
c30ab7b3 | 554 | prev_token_kind: PrevTokenKind::Other, |
d9579d0f | 555 | restrictions: Restrictions::empty(), |
3b2f2976 | 556 | recurse_into_file_modules, |
ff7c6d11 | 557 | directory: Directory { |
94b46f34 | 558 | path: Cow::from(PathBuf::new()), |
ff7c6d11 XL |
559 | ownership: DirectoryOwnership::Owned { relative: None } |
560 | }, | |
1a4d82fc JJ |
561 | root_module_name: None, |
562 | expected_tokens: Vec::new(), | |
8bb4bdeb | 563 | token_cursor: TokenCursor { |
b7449926 | 564 | frame: TokenCursorFrame::new(DelimSpan::dummy(), &Delimited { |
8bb4bdeb XL |
565 | delim: token::NoDelim, |
566 | tts: tokens.into(), | |
567 | }), | |
568 | stack: Vec::new(), | |
569 | }, | |
3b2f2976 | 570 | desugar_doc_comments, |
32a655c1 | 571 | cfg_mods: true, |
c30ab7b3 SL |
572 | }; |
573 | ||
574 | let tok = parser.next_tok(); | |
575 | parser.token = tok.tok; | |
576 | parser.span = tok.sp; | |
7cac9316 | 577 | |
476ff2be SL |
578 | if let Some(directory) = directory { |
579 | parser.directory = directory; | |
8faf50e0 | 580 | } else if !parser.span.is_dummy() { |
b7449926 | 581 | if let FileName::Real(mut path) = sess.source_map().span_to_unmapped_path(parser.span) { |
94b46f34 XL |
582 | path.pop(); |
583 | parser.directory.path = Cow::from(path); | |
ff7c6d11 | 584 | } |
c30ab7b3 | 585 | } |
7cac9316 | 586 | |
cc61c64b | 587 | parser.process_potential_macro_variable(); |
c30ab7b3 SL |
588 | parser |
589 | } | |
590 | ||
591 | fn next_tok(&mut self) -> TokenAndSpan { | |
7cac9316 XL |
592 | let mut next = if self.desugar_doc_comments { |
593 | self.token_cursor.next_desugared() | |
594 | } else { | |
595 | self.token_cursor.next() | |
8bb4bdeb | 596 | }; |
8faf50e0 | 597 | if next.sp.is_dummy() { |
83c7162d XL |
598 | // Tweak the location for better diagnostics, but keep syntactic context intact. |
599 | next.sp = self.prev_span.with_ctxt(next.sp.ctxt()); | |
1a4d82fc | 600 | } |
8bb4bdeb | 601 | next |
1a4d82fc JJ |
602 | } |
603 | ||
1a4d82fc | 604 | /// Convert the current token to a string using self's reader |
85aaf69f | 605 | pub fn this_token_to_string(&self) -> String { |
94b46f34 | 606 | pprust::token_to_string(&self.token) |
1a4d82fc JJ |
607 | } |
608 | ||
94b46f34 | 609 | fn token_descr(&self) -> Option<&'static str> { |
2c00a5a8 XL |
610 | Some(match &self.token { |
611 | t if t.is_special_ident() => "reserved identifier", | |
612 | t if t.is_used_keyword() => "keyword", | |
613 | t if t.is_unused_keyword() => "reserved keyword", | |
614 | _ => return None, | |
615 | }) | |
616 | } | |
617 | ||
94b46f34 | 618 | fn this_token_descr(&self) -> String { |
2c00a5a8 XL |
619 | if let Some(prefix) = self.token_descr() { |
620 | format!("{} `{}`", prefix, self.this_token_to_string()) | |
621 | } else { | |
622 | format!("`{}`", self.this_token_to_string()) | |
623 | } | |
a7813a04 XL |
624 | } |
625 | ||
94b46f34 XL |
626 | fn unexpected_last<T>(&self, t: &token::Token) -> PResult<'a, T> { |
627 | let token_str = pprust::token_to_string(t); | |
c30ab7b3 | 628 | Err(self.span_fatal(self.prev_span, &format!("unexpected token: `{}`", token_str))) |
1a4d82fc JJ |
629 | } |
630 | ||
94b46f34 | 631 | crate fn unexpected<T>(&mut self) -> PResult<'a, T> { |
9346a6ac | 632 | match self.expect_one_of(&[], &[]) { |
9cc50fc6 SL |
633 | Err(e) => Err(e), |
634 | Ok(_) => unreachable!(), | |
9346a6ac | 635 | } |
1a4d82fc JJ |
636 | } |
637 | ||
638 | /// Expect and consume the token t. Signal an error if | |
639 | /// the next token is not t. | |
9cc50fc6 | 640 | pub fn expect(&mut self, t: &token::Token) -> PResult<'a, ()> { |
1a4d82fc JJ |
641 | if self.expected_tokens.is_empty() { |
642 | if self.token == *t { | |
9cc50fc6 SL |
643 | self.bump(); |
644 | Ok(()) | |
1a4d82fc | 645 | } else { |
94b46f34 | 646 | let token_str = pprust::token_to_string(t); |
1a4d82fc | 647 | let this_token_str = self.this_token_to_string(); |
0531ce1d XL |
648 | let mut err = self.fatal(&format!("expected `{}`, found `{}`", |
649 | token_str, | |
650 | this_token_str)); | |
8faf50e0 XL |
651 | |
652 | let sp = if self.token == token::Token::Eof { | |
653 | // EOF, don't want to point at the following char, but rather the last token | |
654 | self.prev_span | |
655 | } else { | |
b7449926 | 656 | self.sess.source_map().next_point(self.prev_span) |
8faf50e0 XL |
657 | }; |
658 | let label_exp = format!("expected `{}`", token_str); | |
b7449926 | 659 | let cm = self.sess.source_map(); |
8faf50e0 XL |
660 | match (cm.lookup_line(self.span.lo()), cm.lookup_line(sp.lo())) { |
661 | (Ok(ref a), Ok(ref b)) if a.line == b.line => { | |
662 | // When the spans are in the same line, it means that the only content | |
663 | // between them is whitespace, point only at the found token. | |
664 | err.span_label(self.span, label_exp); | |
665 | } | |
666 | _ => { | |
667 | err.span_label(sp, label_exp); | |
668 | err.span_label(self.span, "unexpected token"); | |
669 | } | |
670 | } | |
0531ce1d | 671 | Err(err) |
1a4d82fc JJ |
672 | } |
673 | } else { | |
94b46f34 | 674 | self.expect_one_of(slice::from_ref(t), &[]) |
1a4d82fc JJ |
675 | } |
676 | } | |
677 | ||
678 | /// Expect next token to be edible or inedible token. If edible, | |
679 | /// then consume it; if inedible, then return without consuming | |
680 | /// anything. Signal a fatal error if next token is unexpected. | |
0bf4aa26 | 681 | pub fn expect_one_of(&mut self, |
1a4d82fc | 682 | edible: &[token::Token], |
9cc50fc6 | 683 | inedible: &[token::Token]) -> PResult<'a, ()>{ |
1a4d82fc JJ |
684 | fn tokens_to_string(tokens: &[TokenType]) -> String { |
685 | let mut i = tokens.iter(); | |
686 | // This might be a sign we need a connect method on Iterator. | |
687 | let b = i.next() | |
b7449926 | 688 | .map_or(String::new(), |t| t.to_string()); |
7cac9316 | 689 | i.enumerate().fold(b, |mut b, (i, a)| { |
1a4d82fc JJ |
690 | if tokens.len() > 2 && i == tokens.len() - 2 { |
691 | b.push_str(", or "); | |
692 | } else if tokens.len() == 2 && i == tokens.len() - 2 { | |
693 | b.push_str(" or "); | |
694 | } else { | |
695 | b.push_str(", "); | |
696 | } | |
7453a54e | 697 | b.push_str(&a.to_string()); |
1a4d82fc JJ |
698 | b |
699 | }) | |
700 | } | |
701 | if edible.contains(&self.token) { | |
9cc50fc6 SL |
702 | self.bump(); |
703 | Ok(()) | |
1a4d82fc JJ |
704 | } else if inedible.contains(&self.token) { |
705 | // leave it in the input | |
9346a6ac | 706 | Ok(()) |
1a4d82fc | 707 | } else { |
d9579d0f AL |
708 | let mut expected = edible.iter() |
709 | .map(|x| TokenType::Token(x.clone())) | |
710 | .chain(inedible.iter().map(|x| TokenType::Token(x.clone()))) | |
711 | .chain(self.expected_tokens.iter().cloned()) | |
712 | .collect::<Vec<_>>(); | |
83c7162d | 713 | expected.sort_by_cached_key(|x| x.to_string()); |
1a4d82fc | 714 | expected.dedup(); |
85aaf69f | 715 | let expect = tokens_to_string(&expected[..]); |
1a4d82fc | 716 | let actual = self.this_token_to_string(); |
cc61c64b XL |
717 | let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 { |
718 | let short_expect = if expected.len() > 6 { | |
719 | format!("{} possible tokens", expected.len()) | |
1a4d82fc | 720 | } else { |
cc61c64b XL |
721 | expect.clone() |
722 | }; | |
723 | (format!("expected one of {}, found `{}`", expect, actual), | |
b7449926 | 724 | (self.sess.source_map().next_point(self.prev_span), |
2c00a5a8 | 725 | format!("expected one of {} here", short_expect))) |
cc61c64b XL |
726 | } else if expected.is_empty() { |
727 | (format!("unexpected token: `{}`", actual), | |
728 | (self.prev_span, "unexpected token after this".to_string())) | |
729 | } else { | |
730 | (format!("expected {}, found `{}`", expect, actual), | |
b7449926 | 731 | (self.sess.source_map().next_point(self.prev_span), |
2c00a5a8 | 732 | format!("expected {} here", expect))) |
cc61c64b XL |
733 | }; |
734 | let mut err = self.fatal(&msg_exp); | |
b7449926 XL |
735 | if self.token.is_ident_named("and") { |
736 | err.span_suggestion_short_with_applicability( | |
737 | self.span, | |
738 | "use `&&` instead of `and` for the boolean operator", | |
739 | "&&".to_string(), | |
740 | Applicability::MaybeIncorrect, | |
741 | ); | |
742 | } | |
743 | if self.token.is_ident_named("or") { | |
744 | err.span_suggestion_short_with_applicability( | |
745 | self.span, | |
746 | "use `||` instead of `or` for the boolean operator", | |
747 | "||".to_string(), | |
748 | Applicability::MaybeIncorrect, | |
749 | ); | |
750 | } | |
cc61c64b XL |
751 | let sp = if self.token == token::Token::Eof { |
752 | // This is EOF, don't want to point at the following char, but rather the last token | |
753 | self.prev_span | |
754 | } else { | |
755 | label_sp | |
756 | }; | |
ff7c6d11 | 757 | |
b7449926 | 758 | let cm = self.sess.source_map(); |
ff7c6d11 XL |
759 | match (cm.lookup_line(self.span.lo()), cm.lookup_line(sp.lo())) { |
760 | (Ok(ref a), Ok(ref b)) if a.line == b.line => { | |
761 | // When the spans are in the same line, it means that the only content between | |
762 | // them is whitespace, point at the found token in that case: | |
763 | // | |
764 | // X | () => { syntax error }; | |
765 | // | ^^^^^ expected one of 8 possible tokens here | |
766 | // | |
767 | // instead of having: | |
768 | // | |
769 | // X | () => { syntax error }; | |
770 | // | -^^^^^ unexpected token | |
771 | // | | | |
772 | // | expected one of 8 possible tokens here | |
773 | err.span_label(self.span, label_exp); | |
774 | } | |
0bf4aa26 XL |
775 | _ if self.prev_span == syntax_pos::DUMMY_SP => { |
776 | // Account for macro context where the previous span might not be | |
777 | // available to avoid incorrect output (#54841). | |
778 | err.span_label(self.span, "unexpected token"); | |
779 | } | |
ff7c6d11 XL |
780 | _ => { |
781 | err.span_label(sp, label_exp); | |
782 | err.span_label(self.span, "unexpected token"); | |
783 | } | |
cc61c64b XL |
784 | } |
785 | Err(err) | |
1a4d82fc | 786 | } |
970d7e83 LB |
787 | } |
788 | ||
7453a54e SL |
789 | /// returns the span of expr, if it was not interpolated or the span of the interpolated token |
790 | fn interpolated_or_expr_span(&self, | |
791 | expr: PResult<'a, P<Expr>>) | |
792 | -> PResult<'a, (Span, P<Expr>)> { | |
793 | expr.map(|e| { | |
c30ab7b3 SL |
794 | if self.prev_token_kind == PrevTokenKind::Interpolated { |
795 | (self.prev_span, e) | |
7453a54e SL |
796 | } else { |
797 | (e.span, e) | |
798 | } | |
799 | }) | |
800 | } | |
801 | ||
2c00a5a8 XL |
802 | fn expected_ident_found(&self) -> DiagnosticBuilder<'a> { |
803 | let mut err = self.struct_span_err(self.span, | |
804 | &format!("expected identifier, found {}", | |
805 | self.this_token_descr())); | |
806 | if let Some(token_descr) = self.token_descr() { | |
807 | err.span_label(self.span, format!("expected identifier, found {}", token_descr)); | |
808 | } else { | |
809 | err.span_label(self.span, "expected identifier"); | |
8faf50e0 | 810 | if self.token == token::Comma && self.look_ahead(1, |t| t.is_ident()) { |
b7449926 XL |
811 | err.span_suggestion_with_applicability( |
812 | self.span, | |
813 | "remove this comma", | |
814 | String::new(), | |
815 | Applicability::MachineApplicable, | |
816 | ); | |
8faf50e0 | 817 | } |
2c00a5a8 XL |
818 | } |
819 | err | |
820 | } | |
821 | ||
9cc50fc6 | 822 | pub fn parse_ident(&mut self) -> PResult<'a, ast::Ident> { |
2c00a5a8 XL |
823 | self.parse_ident_common(true) |
824 | } | |
825 | ||
826 | fn parse_ident_common(&mut self, recover: bool) -> PResult<'a, ast::Ident> { | |
1a4d82fc | 827 | match self.token { |
83c7162d | 828 | token::Ident(ident, _) => { |
041b39d2 | 829 | if self.token.is_reserved_ident() { |
2c00a5a8 XL |
830 | let mut err = self.expected_ident_found(); |
831 | if recover { | |
832 | err.emit(); | |
833 | } else { | |
834 | return Err(err); | |
835 | } | |
041b39d2 | 836 | } |
83c7162d | 837 | let span = self.span; |
9cc50fc6 | 838 | self.bump(); |
83c7162d | 839 | Ok(Ident::new(ident.name, span)) |
970d7e83 | 840 | } |
970d7e83 | 841 | _ => { |
c30ab7b3 | 842 | Err(if self.prev_token_kind == PrevTokenKind::DocComment { |
8bb4bdeb | 843 | self.span_fatal_err(self.prev_span, Error::UselessDocComment) |
9e0c209e | 844 | } else { |
0531ce1d | 845 | self.expected_ident_found() |
9e0c209e | 846 | }) |
970d7e83 LB |
847 | } |
848 | } | |
849 | } | |
850 | ||
1a4d82fc JJ |
851 | /// Check if the next token is `tok`, and return `true` if so. |
852 | /// | |
7453a54e | 853 | /// This method will automatically add `tok` to `expected_tokens` if `tok` is not |
1a4d82fc | 854 | /// encountered. |
b7449926 | 855 | crate fn check(&mut self, tok: &token::Token) -> bool { |
1a4d82fc JJ |
856 | let is_present = self.token == *tok; |
857 | if !is_present { self.expected_tokens.push(TokenType::Token(tok.clone())); } | |
858 | is_present | |
970d7e83 LB |
859 | } |
860 | ||
1a4d82fc JJ |
861 | /// Consume token 'tok' if it exists. Returns true if the given |
862 | /// token was present, false otherwise. | |
9cc50fc6 | 863 | pub fn eat(&mut self, tok: &token::Token) -> bool { |
1a4d82fc | 864 | let is_present = self.check(tok); |
9cc50fc6 SL |
865 | if is_present { self.bump() } |
866 | is_present | |
970d7e83 LB |
867 | } |
868 | ||
94b46f34 | 869 | fn check_keyword(&mut self, kw: keywords::Keyword) -> bool { |
85aaf69f SL |
870 | self.expected_tokens.push(TokenType::Keyword(kw)); |
871 | self.token.is_keyword(kw) | |
872 | } | |
873 | ||
1a4d82fc JJ |
874 | /// If the next token is the given keyword, eat it and return |
875 | /// true. Otherwise, return false. | |
9cc50fc6 | 876 | pub fn eat_keyword(&mut self, kw: keywords::Keyword) -> bool { |
85aaf69f | 877 | if self.check_keyword(kw) { |
9cc50fc6 SL |
878 | self.bump(); |
879 | true | |
85aaf69f | 880 | } else { |
9cc50fc6 | 881 | false |
85aaf69f SL |
882 | } |
883 | } | |
884 | ||
94b46f34 | 885 | fn eat_keyword_noexpect(&mut self, kw: keywords::Keyword) -> bool { |
1a4d82fc | 886 | if self.token.is_keyword(kw) { |
9cc50fc6 SL |
887 | self.bump(); |
888 | true | |
1a4d82fc | 889 | } else { |
9cc50fc6 | 890 | false |
1a4d82fc | 891 | } |
970d7e83 LB |
892 | } |
893 | ||
1a4d82fc JJ |
894 | /// If the given word is not a keyword, signal an error. |
895 | /// If the next token is not the given word, signal an error. | |
896 | /// Otherwise, eat it. | |
94b46f34 | 897 | fn expect_keyword(&mut self, kw: keywords::Keyword) -> PResult<'a, ()> { |
9cc50fc6 SL |
898 | if !self.eat_keyword(kw) { |
899 | self.unexpected() | |
9346a6ac AL |
900 | } else { |
901 | Ok(()) | |
970d7e83 LB |
902 | } |
903 | } | |
904 | ||
32a655c1 SL |
905 | fn check_ident(&mut self) -> bool { |
906 | if self.token.is_ident() { | |
907 | true | |
908 | } else { | |
909 | self.expected_tokens.push(TokenType::Ident); | |
910 | false | |
911 | } | |
912 | } | |
913 | ||
914 | fn check_path(&mut self) -> bool { | |
915 | if self.token.is_path_start() { | |
916 | true | |
917 | } else { | |
918 | self.expected_tokens.push(TokenType::Path); | |
919 | false | |
920 | } | |
921 | } | |
922 | ||
923 | fn check_type(&mut self) -> bool { | |
924 | if self.token.can_begin_type() { | |
925 | true | |
926 | } else { | |
927 | self.expected_tokens.push(TokenType::Type); | |
928 | false | |
929 | } | |
930 | } | |
931 | ||
94b46f34 XL |
932 | /// Expect and consume a `+`. if `+=` is seen, replace it with a `=` |
933 | /// and continue. If a `+` is not seen, return false. | |
934 | /// | |
935 | /// This is using when token splitting += into +. | |
936 | /// See issue 47856 for an example of when this may occur. | |
937 | fn eat_plus(&mut self) -> bool { | |
938 | self.expected_tokens.push(TokenType::Token(token::BinOp(token::Plus))); | |
939 | match self.token { | |
940 | token::BinOp(token::Plus) => { | |
941 | self.bump(); | |
942 | true | |
943 | } | |
944 | token::BinOpEq(token::Plus) => { | |
945 | let span = self.span.with_lo(self.span.lo() + BytePos(1)); | |
946 | self.bump_with(token::Eq, span); | |
947 | true | |
948 | } | |
949 | _ => false, | |
950 | } | |
951 | } | |
952 | ||
953 | ||
954 | /// Checks to see if the next token is either `+` or `+=`. | |
955 | /// Otherwise returns false. | |
956 | fn check_plus(&mut self) -> bool { | |
957 | if self.token.is_like_plus() { | |
958 | true | |
959 | } | |
960 | else { | |
961 | self.expected_tokens.push(TokenType::Token(token::BinOp(token::Plus))); | |
962 | false | |
963 | } | |
964 | } | |
965 | ||
1a4d82fc JJ |
966 | /// Expect and consume an `&`. If `&&` is seen, replace it with a single |
967 | /// `&` and continue. If an `&` is not seen, signal an error. | |
9cc50fc6 | 968 | fn expect_and(&mut self) -> PResult<'a, ()> { |
85aaf69f | 969 | self.expected_tokens.push(TokenType::Token(token::BinOp(token::And))); |
1a4d82fc | 970 | match self.token { |
9cc50fc6 SL |
971 | token::BinOp(token::And) => { |
972 | self.bump(); | |
973 | Ok(()) | |
974 | } | |
1a4d82fc | 975 | token::AndAnd => { |
ea8adc8c XL |
976 | let span = self.span.with_lo(self.span.lo() + BytePos(1)); |
977 | Ok(self.bump_with(token::BinOp(token::And), span)) | |
978 | } | |
979 | _ => self.unexpected() | |
980 | } | |
981 | } | |
982 | ||
983 | /// Expect and consume an `|`. If `||` is seen, replace it with a single | |
984 | /// `|` and continue. If an `|` is not seen, signal an error. | |
985 | fn expect_or(&mut self) -> PResult<'a, ()> { | |
986 | self.expected_tokens.push(TokenType::Token(token::BinOp(token::Or))); | |
987 | match self.token { | |
988 | token::BinOp(token::Or) => { | |
989 | self.bump(); | |
990 | Ok(()) | |
991 | } | |
992 | token::OrOr => { | |
993 | let span = self.span.with_lo(self.span.lo() + BytePos(1)); | |
994 | Ok(self.bump_with(token::BinOp(token::Or), span)) | |
1a4d82fc | 995 | } |
9cc50fc6 | 996 | _ => self.unexpected() |
970d7e83 LB |
997 | } |
998 | } | |
999 | ||
94b46f34 | 1000 | fn expect_no_suffix(&self, sp: Span, kind: &str, suffix: Option<ast::Name>) { |
1a4d82fc JJ |
1001 | match suffix { |
1002 | None => {/* everything ok */} | |
1003 | Some(suf) => { | |
1004 | let text = suf.as_str(); | |
1005 | if text.is_empty() { | |
1006 | self.span_bug(sp, "found empty literal suffix in Some") | |
1007 | } | |
7453a54e | 1008 | self.span_err(sp, &format!("{} with a suffix is invalid", kind)); |
1a4d82fc JJ |
1009 | } |
1010 | } | |
1011 | } | |
1012 | ||
1a4d82fc JJ |
1013 | /// Attempt to consume a `<`. If `<<` is seen, replace it with a single |
1014 | /// `<` and continue. If a `<` is not seen, return false. | |
1015 | /// | |
1016 | /// This is meant to be used when parsing generics on a path to get the | |
1017 | /// starting token. | |
9cc50fc6 | 1018 | fn eat_lt(&mut self) -> bool { |
85aaf69f | 1019 | self.expected_tokens.push(TokenType::Token(token::Lt)); |
1a4d82fc | 1020 | match self.token { |
9cc50fc6 SL |
1021 | token::Lt => { |
1022 | self.bump(); | |
1023 | true | |
1024 | } | |
1a4d82fc | 1025 | token::BinOp(token::Shl) => { |
ea8adc8c XL |
1026 | let span = self.span.with_lo(self.span.lo() + BytePos(1)); |
1027 | self.bump_with(token::Lt, span); | |
9cc50fc6 | 1028 | true |
1a4d82fc | 1029 | } |
9cc50fc6 | 1030 | _ => false, |
1a4d82fc JJ |
1031 | } |
1032 | } | |
1033 | ||
9cc50fc6 SL |
1034 | fn expect_lt(&mut self) -> PResult<'a, ()> { |
1035 | if !self.eat_lt() { | |
1036 | self.unexpected() | |
9346a6ac AL |
1037 | } else { |
1038 | Ok(()) | |
1a4d82fc JJ |
1039 | } |
1040 | } | |
1041 | ||
1a4d82fc JJ |
1042 | /// Expect and consume a GT. if a >> is seen, replace it |
1043 | /// with a single > and continue. If a GT is not seen, | |
1044 | /// signal an error. | |
94b46f34 | 1045 | fn expect_gt(&mut self) -> PResult<'a, ()> { |
85aaf69f | 1046 | self.expected_tokens.push(TokenType::Token(token::Gt)); |
1a4d82fc | 1047 | match self.token { |
9cc50fc6 SL |
1048 | token::Gt => { |
1049 | self.bump(); | |
1050 | Ok(()) | |
1051 | } | |
1a4d82fc | 1052 | token::BinOp(token::Shr) => { |
ea8adc8c XL |
1053 | let span = self.span.with_lo(self.span.lo() + BytePos(1)); |
1054 | Ok(self.bump_with(token::Gt, span)) | |
1a4d82fc JJ |
1055 | } |
1056 | token::BinOpEq(token::Shr) => { | |
ea8adc8c XL |
1057 | let span = self.span.with_lo(self.span.lo() + BytePos(1)); |
1058 | Ok(self.bump_with(token::Ge, span)) | |
1a4d82fc JJ |
1059 | } |
1060 | token::Ge => { | |
ea8adc8c XL |
1061 | let span = self.span.with_lo(self.span.lo() + BytePos(1)); |
1062 | Ok(self.bump_with(token::Eq, span)) | |
1a4d82fc | 1063 | } |
32a655c1 | 1064 | _ => self.unexpected() |
1a4d82fc JJ |
1065 | } |
1066 | } | |
1067 | ||
7453a54e SL |
1068 | /// Eat and discard tokens until one of `kets` is encountered. Respects token trees, |
1069 | /// passes through any errors encountered. Used for error recovery. | |
94b46f34 | 1070 | fn eat_to_tokens(&mut self, kets: &[&token::Token]) { |
9e0c209e SL |
1071 | let handler = self.diagnostic(); |
1072 | ||
abe05a73 XL |
1073 | if let Err(ref mut err) = self.parse_seq_to_before_tokens(kets, |
1074 | SeqSep::none(), | |
1075 | TokenExpectType::Expect, | |
1076 | |p| Ok(p.parse_token_tree())) { | |
1077 | handler.cancel(err); | |
1078 | } | |
7453a54e SL |
1079 | } |
1080 | ||
1a4d82fc JJ |
1081 | /// Parse a sequence, including the closing delimiter. The function |
1082 | /// f must consume tokens until reaching the next separator or | |
1083 | /// closing bracket. | |
1084 | pub fn parse_seq_to_end<T, F>(&mut self, | |
1085 | ket: &token::Token, | |
1086 | sep: SeqSep, | |
1087 | f: F) | |
9cc50fc6 SL |
1088 | -> PResult<'a, Vec<T>> where |
1089 | F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, | |
1a4d82fc | 1090 | { |
abe05a73 | 1091 | let val = self.parse_seq_to_before_end(ket, sep, f)?; |
9cc50fc6 | 1092 | self.bump(); |
9346a6ac | 1093 | Ok(val) |
970d7e83 LB |
1094 | } |
1095 | ||
1a4d82fc JJ |
1096 | /// Parse a sequence, not including the closing delimiter. The function |
1097 | /// f must consume tokens until reaching the next separator or | |
1098 | /// closing bracket. | |
8faf50e0 | 1099 | pub fn parse_seq_to_before_end<T, F>(&mut self, |
1a4d82fc JJ |
1100 | ket: &token::Token, |
1101 | sep: SeqSep, | |
7453a54e | 1102 | f: F) |
abe05a73 XL |
1103 | -> PResult<'a, Vec<T>> |
1104 | where F: FnMut(&mut Parser<'a>) -> PResult<'a, T> | |
7453a54e | 1105 | { |
abe05a73 | 1106 | self.parse_seq_to_before_tokens(&[ket], sep, TokenExpectType::Expect, f) |
7453a54e SL |
1107 | } |
1108 | ||
b7449926 XL |
1109 | fn parse_seq_to_before_tokens<T, F>( |
1110 | &mut self, | |
1111 | kets: &[&token::Token], | |
1112 | sep: SeqSep, | |
1113 | expect: TokenExpectType, | |
1114 | mut f: F, | |
1115 | ) -> PResult<'a, Vec<T>> | |
abe05a73 | 1116 | where F: FnMut(&mut Parser<'a>) -> PResult<'a, T> |
1a4d82fc | 1117 | { |
970d7e83 | 1118 | let mut first: bool = true; |
c30ab7b3 | 1119 | let mut v = vec![]; |
94b46f34 XL |
1120 | while !kets.iter().any(|k| { |
1121 | match expect { | |
1122 | TokenExpectType::Expect => self.check(k), | |
1123 | TokenExpectType::NoExpect => self.token == **k, | |
1124 | } | |
1125 | }) { | |
32a655c1 SL |
1126 | match self.token { |
1127 | token::CloseDelim(..) | token::Eof => break, | |
1128 | _ => {} | |
1129 | }; | |
7cac9316 XL |
1130 | if let Some(ref t) = sep.sep { |
1131 | if first { | |
1132 | first = false; | |
1133 | } else { | |
abe05a73 XL |
1134 | if let Err(mut e) = self.expect(t) { |
1135 | // Attempt to keep parsing if it was a similar separator | |
1136 | if let Some(ref tokens) = t.similar_tokens() { | |
1137 | if tokens.contains(&self.token) { | |
1138 | self.bump(); | |
1139 | } | |
1140 | } | |
1141 | e.emit(); | |
1142 | // Attempt to keep parsing if it was an omitted separator | |
1143 | match f(self) { | |
1144 | Ok(t) => { | |
1145 | v.push(t); | |
1146 | continue; | |
1147 | }, | |
1148 | Err(mut e) => { | |
1149 | e.cancel(); | |
1150 | break; | |
1151 | } | |
1152 | } | |
7453a54e SL |
1153 | } |
1154 | } | |
7453a54e | 1155 | } |
ea8adc8c XL |
1156 | if sep.trailing_sep_allowed && kets.iter().any(|k| { |
1157 | match expect { | |
1158 | TokenExpectType::Expect => self.check(k), | |
1159 | TokenExpectType::NoExpect => self.token == **k, | |
1160 | } | |
1161 | }) { | |
7453a54e SL |
1162 | break; |
1163 | } | |
1164 | ||
abe05a73 XL |
1165 | let t = f(self)?; |
1166 | v.push(t); | |
970d7e83 | 1167 | } |
7453a54e | 1168 | |
abe05a73 | 1169 | Ok(v) |
970d7e83 LB |
1170 | } |
1171 | ||
1a4d82fc JJ |
1172 | /// Parse a sequence, including the closing delimiter. The function |
1173 | /// f must consume tokens until reaching the next separator or | |
1174 | /// closing bracket. | |
94b46f34 | 1175 | fn parse_unspanned_seq<T, F>(&mut self, |
1a4d82fc JJ |
1176 | bra: &token::Token, |
1177 | ket: &token::Token, | |
1178 | sep: SeqSep, | |
1179 | f: F) | |
9cc50fc6 | 1180 | -> PResult<'a, Vec<T>> where |
0531ce1d | 1181 | F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, |
1a4d82fc | 1182 | { |
54a0048b | 1183 | self.expect(bra)?; |
abe05a73 | 1184 | let result = self.parse_seq_to_before_end(ket, sep, f)?; |
b7449926 | 1185 | self.eat(ket); |
9346a6ac | 1186 | Ok(result) |
970d7e83 LB |
1187 | } |
1188 | ||
1a4d82fc | 1189 | /// Advance the parser by one token |
9cc50fc6 | 1190 | pub fn bump(&mut self) { |
c30ab7b3 | 1191 | if self.prev_token_kind == PrevTokenKind::Eof { |
7453a54e SL |
1192 | // Bumping after EOF is a bad sign, usually an infinite loop. |
1193 | self.bug("attempted to bump the parser past EOF (may be stuck in a loop)"); | |
1194 | } | |
1195 | ||
cc61c64b | 1196 | self.prev_span = self.meta_var_span.take().unwrap_or(self.span); |
9e0c209e SL |
1197 | |
1198 | // Record last token kind for possible error recovery. | |
c30ab7b3 SL |
1199 | self.prev_token_kind = match self.token { |
1200 | token::DocComment(..) => PrevTokenKind::DocComment, | |
1201 | token::Comma => PrevTokenKind::Comma, | |
cc61c64b | 1202 | token::BinOp(token::Plus) => PrevTokenKind::Plus, |
c30ab7b3 SL |
1203 | token::Interpolated(..) => PrevTokenKind::Interpolated, |
1204 | token::Eof => PrevTokenKind::Eof, | |
041b39d2 | 1205 | token::Ident(..) => PrevTokenKind::Ident, |
c30ab7b3 | 1206 | _ => PrevTokenKind::Other, |
1a4d82fc | 1207 | }; |
9e0c209e | 1208 | |
32a655c1 | 1209 | let next = self.next_tok(); |
1a4d82fc JJ |
1210 | self.span = next.sp; |
1211 | self.token = next.tok; | |
1a4d82fc JJ |
1212 | self.expected_tokens.clear(); |
1213 | // check after each token | |
cc61c64b | 1214 | self.process_potential_macro_variable(); |
223e47cc | 1215 | } |
1a4d82fc | 1216 | |
7453a54e SL |
1217 | /// Advance the parser using provided token as a next one. Use this when |
1218 | /// consuming a part of a token. For example a single `<` from `<<`. | |
94b46f34 | 1219 | fn bump_with(&mut self, next: token::Token, span: Span) { |
ea8adc8c | 1220 | self.prev_span = self.span.with_hi(span.lo()); |
9e0c209e SL |
1221 | // It would be incorrect to record the kind of the current token, but |
1222 | // fortunately for tokens currently using `bump_with`, the | |
c30ab7b3 SL |
1223 | // prev_token_kind will be of no use anyway. |
1224 | self.prev_token_kind = PrevTokenKind::Other; | |
cc61c64b | 1225 | self.span = span; |
7453a54e SL |
1226 | self.token = next; |
1227 | self.expected_tokens.clear(); | |
223e47cc | 1228 | } |
7453a54e | 1229 | |
8bb4bdeb | 1230 | pub fn look_ahead<R, F>(&self, dist: usize, f: F) -> R where |
1a4d82fc JJ |
1231 | F: FnOnce(&token::Token) -> R, |
1232 | { | |
c30ab7b3 | 1233 | if dist == 0 { |
8bb4bdeb | 1234 | return f(&self.token) |
223e47cc | 1235 | } |
8bb4bdeb XL |
1236 | |
1237 | f(&match self.token_cursor.frame.tree_cursor.look_ahead(dist - 1) { | |
1238 | Some(tree) => match tree { | |
1239 | TokenTree::Token(_, tok) => tok, | |
1240 | TokenTree::Delimited(_, delimited) => token::OpenDelim(delimited.delim), | |
1241 | }, | |
1242 | None => token::CloseDelim(self.token_cursor.frame.delim), | |
1243 | }) | |
223e47cc | 1244 | } |
ff7c6d11 | 1245 | |
041b39d2 XL |
1246 | fn look_ahead_span(&self, dist: usize) -> Span { |
1247 | if dist == 0 { | |
1248 | return self.span | |
1249 | } | |
1250 | ||
1251 | match self.token_cursor.frame.tree_cursor.look_ahead(dist - 1) { | |
b7449926 XL |
1252 | Some(TokenTree::Token(span, _)) => span, |
1253 | Some(TokenTree::Delimited(span, _)) => span.entire(), | |
041b39d2 XL |
1254 | None => self.look_ahead_span(dist - 1), |
1255 | } | |
1256 | } | |
9cc50fc6 SL |
1257 | pub fn fatal(&self, m: &str) -> DiagnosticBuilder<'a> { |
1258 | self.sess.span_diagnostic.struct_span_fatal(self.span, m) | |
223e47cc | 1259 | } |
2c00a5a8 | 1260 | pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> { |
9cc50fc6 | 1261 | self.sess.span_diagnostic.struct_span_fatal(sp, m) |
1a4d82fc | 1262 | } |
94b46f34 | 1263 | fn span_fatal_err<S: Into<MultiSpan>>(&self, sp: S, err: Error) -> DiagnosticBuilder<'a> { |
8bb4bdeb XL |
1264 | err.span_err(sp, self.diagnostic()) |
1265 | } | |
94b46f34 | 1266 | fn bug(&self, m: &str) -> ! { |
1a4d82fc JJ |
1267 | self.sess.span_diagnostic.span_bug(self.span, m) |
1268 | } | |
94b46f34 | 1269 | fn span_err<S: Into<MultiSpan>>(&self, sp: S, m: &str) { |
223e47cc LB |
1270 | self.sess.span_diagnostic.span_err(sp, m) |
1271 | } | |
94b46f34 | 1272 | fn struct_span_err<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> { |
ff7c6d11 XL |
1273 | self.sess.span_diagnostic.struct_span_err(sp, m) |
1274 | } | |
94b46f34 | 1275 | crate fn span_bug<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> ! { |
1a4d82fc JJ |
1276 | self.sess.span_diagnostic.span_bug(sp, m) |
1277 | } | |
94b46f34 | 1278 | crate fn abort_if_errors(&self) { |
9cc50fc6 SL |
1279 | self.sess.span_diagnostic.abort_if_errors(); |
1280 | } | |
1281 | ||
9e0c209e SL |
1282 | fn cancel(&self, err: &mut DiagnosticBuilder) { |
1283 | self.sess.span_diagnostic.cancel(err) | |
1284 | } | |
1285 | ||
94b46f34 | 1286 | crate fn diagnostic(&self) -> &'a errors::Handler { |
9cc50fc6 | 1287 | &self.sess.span_diagnostic |
223e47cc | 1288 | } |
223e47cc | 1289 | |
1a4d82fc JJ |
1290 | /// Is the current token one of the keywords that signals a bare function |
1291 | /// type? | |
94b46f34 | 1292 | fn token_is_bare_fn_keyword(&mut self) -> bool { |
85aaf69f SL |
1293 | self.check_keyword(keywords::Fn) || |
1294 | self.check_keyword(keywords::Unsafe) || | |
0531ce1d | 1295 | self.check_keyword(keywords::Extern) && self.is_extern_non_path() |
223e47cc LB |
1296 | } |
1297 | ||
7453a54e | 1298 | /// parse a TyKind::BareFn type: |
8faf50e0 | 1299 | fn parse_ty_bare_fn(&mut self, generic_params: Vec<GenericParam>) -> PResult<'a, TyKind> { |
1a4d82fc | 1300 | /* |
223e47cc | 1301 | |
54a0048b SL |
1302 | [unsafe] [extern "ABI"] fn (S) -> T |
1303 | ^~~~^ ^~~~^ ^~^ ^ | |
1304 | | | | | | |
1305 | | | | Return type | |
1306 | | | Argument types | |
1307 | | | | |
1a4d82fc JJ |
1308 | | ABI |
1309 | Function Style | |
223e47cc LB |
1310 | */ |
1311 | ||
2c00a5a8 | 1312 | let unsafety = self.parse_unsafety(); |
9cc50fc6 | 1313 | let abi = if self.eat_keyword(keywords::Extern) { |
54a0048b | 1314 | self.parse_opt_abi()?.unwrap_or(Abi::C) |
1a4d82fc | 1315 | } else { |
7453a54e | 1316 | Abi::Rust |
1a4d82fc JJ |
1317 | }; |
1318 | ||
54a0048b SL |
1319 | self.expect_keyword(keywords::Fn)?; |
1320 | let (inputs, variadic) = self.parse_fn_args(false, true)?; | |
2c00a5a8 | 1321 | let ret_ty = self.parse_ret_ty(false)?; |
1a4d82fc | 1322 | let decl = P(FnDecl { |
3b2f2976 | 1323 | inputs, |
1a4d82fc | 1324 | output: ret_ty, |
3b2f2976 | 1325 | variadic, |
223e47cc | 1326 | }); |
7453a54e | 1327 | Ok(TyKind::BareFn(P(BareFnTy { |
3b2f2976 XL |
1328 | abi, |
1329 | unsafety, | |
ff7c6d11 | 1330 | generic_params, |
3b2f2976 | 1331 | decl, |
9346a6ac | 1332 | }))) |
223e47cc LB |
1333 | } |
1334 | ||
8faf50e0 XL |
1335 | /// Parse asyncness: `async` or nothing |
1336 | fn parse_asyncness(&mut self) -> IsAsync { | |
1337 | if self.eat_keyword(keywords::Async) { | |
1338 | IsAsync::Async { | |
1339 | closure_id: ast::DUMMY_NODE_ID, | |
1340 | return_impl_trait_id: ast::DUMMY_NODE_ID, | |
1341 | } | |
1342 | } else { | |
1343 | IsAsync::NotAsync | |
1344 | } | |
1345 | } | |
1346 | ||
2c00a5a8 XL |
1347 | /// Parse unsafety: `unsafe` or nothing. |
1348 | fn parse_unsafety(&mut self) -> Unsafety { | |
9cc50fc6 | 1349 | if self.eat_keyword(keywords::Unsafe) { |
2c00a5a8 | 1350 | Unsafety::Unsafe |
1a4d82fc | 1351 | } else { |
2c00a5a8 | 1352 | Unsafety::Normal |
1a4d82fc JJ |
1353 | } |
1354 | } | |
1355 | ||
1a4d82fc | 1356 | /// Parse the items in a trait declaration |
cc61c64b | 1357 | pub fn parse_trait_item(&mut self, at_end: &mut bool) -> PResult<'a, TraitItem> { |
c30ab7b3 | 1358 | maybe_whole!(self, NtTraitItem, |x| x); |
3b2f2976 XL |
1359 | let attrs = self.parse_outer_attributes()?; |
1360 | let (mut item, tokens) = self.collect_tokens(|this| { | |
1361 | this.parse_trait_item_(at_end, attrs) | |
1362 | })?; | |
1363 | // See `parse_item` for why this clause is here. | |
1364 | if !item.attrs.iter().any(|attr| attr.style == AttrStyle::Inner) { | |
1365 | item.tokens = Some(tokens); | |
1366 | } | |
1367 | Ok(item) | |
1368 | } | |
1369 | ||
1370 | fn parse_trait_item_(&mut self, | |
1371 | at_end: &mut bool, | |
1372 | mut attrs: Vec<Attribute>) -> PResult<'a, TraitItem> { | |
cc61c64b | 1373 | let lo = self.span; |
3157f602 | 1374 | |
abe05a73 | 1375 | let (name, node, generics) = if self.eat_keyword(keywords::Type) { |
8faf50e0 | 1376 | self.parse_trait_item_assoc_ty()? |
3157f602 | 1377 | } else if self.is_const_item() { |
cc61c64b | 1378 | self.expect_keyword(keywords::Const)?; |
3157f602 XL |
1379 | let ident = self.parse_ident()?; |
1380 | self.expect(&token::Colon)?; | |
32a655c1 | 1381 | let ty = self.parse_ty()?; |
b7449926 | 1382 | let default = if self.eat(&token::Eq) { |
3157f602 | 1383 | let expr = self.parse_expr()?; |
5bcae85e | 1384 | self.expect(&token::Semi)?; |
3157f602 XL |
1385 | Some(expr) |
1386 | } else { | |
1387 | self.expect(&token::Semi)?; | |
1388 | None | |
1389 | }; | |
abe05a73 | 1390 | (ident, TraitItemKind::Const(ty, default), ast::Generics::default()) |
83c7162d | 1391 | } else if let Some(mac) = self.parse_assoc_macro_invoc("trait", None, &mut false)? { |
9e0c209e | 1392 | // trait item macro. |
abe05a73 | 1393 | (keywords::Invalid.ident(), ast::TraitItemKind::Macro(mac), ast::Generics::default()) |
9e0c209e | 1394 | } else { |
8faf50e0 | 1395 | let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?; |
1a4d82fc | 1396 | |
9e0c209e SL |
1397 | let ident = self.parse_ident()?; |
1398 | let mut generics = self.parse_generics()?; | |
1a4d82fc | 1399 | |
b7449926 | 1400 | let d = self.parse_fn_decl_with_self(|p: &mut Parser<'a>| { |
9e0c209e SL |
1401 | // This is somewhat dubious; We don't want to allow |
1402 | // argument names to be left off if there is a | |
1403 | // definition... | |
b7449926 XL |
1404 | |
1405 | // We don't allow argument names to be left off in edition 2018. | |
1406 | if p.span.edition() >= Edition::Edition2018 { | |
1407 | p.parse_arg_general(true) | |
1408 | } else { | |
1409 | p.parse_arg_general(false) | |
1410 | } | |
9e0c209e | 1411 | })?; |
9e0c209e | 1412 | generics.where_clause = self.parse_where_clause()?; |
abe05a73 | 1413 | |
9e0c209e | 1414 | let sig = ast::MethodSig { |
8faf50e0 XL |
1415 | header: FnHeader { |
1416 | unsafety, | |
1417 | constness, | |
1418 | abi, | |
1419 | asyncness, | |
1420 | }, | |
9e0c209e | 1421 | decl: d, |
9e0c209e | 1422 | }; |
1a4d82fc | 1423 | |
9e0c209e SL |
1424 | let body = match self.token { |
1425 | token::Semi => { | |
1426 | self.bump(); | |
cc61c64b | 1427 | *at_end = true; |
9e0c209e SL |
1428 | debug!("parse_trait_methods(): parsing required method"); |
1429 | None | |
1430 | } | |
1431 | token::OpenDelim(token::Brace) => { | |
1432 | debug!("parse_trait_methods(): parsing provided method"); | |
cc61c64b | 1433 | *at_end = true; |
9e0c209e SL |
1434 | let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; |
1435 | attrs.extend(inner_attrs.iter().cloned()); | |
1436 | Some(body) | |
1437 | } | |
0bf4aa26 XL |
1438 | token::Interpolated(ref nt) => { |
1439 | match &nt.0 { | |
1440 | token::NtBlock(..) => { | |
1441 | *at_end = true; | |
1442 | let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; | |
1443 | attrs.extend(inner_attrs.iter().cloned()); | |
1444 | Some(body) | |
1445 | } | |
1446 | _ => { | |
1447 | let token_str = self.this_token_to_string(); | |
1448 | let mut err = self.fatal(&format!("expected `;` or `{{`, found `{}`", | |
1449 | token_str)); | |
1450 | err.span_label(self.span, "expected `;` or `{`"); | |
1451 | return Err(err); | |
1452 | } | |
1453 | } | |
1454 | } | |
9e0c209e SL |
1455 | _ => { |
1456 | let token_str = self.this_token_to_string(); | |
0531ce1d XL |
1457 | let mut err = self.fatal(&format!("expected `;` or `{{`, found `{}`", |
1458 | token_str)); | |
1459 | err.span_label(self.span, "expected `;` or `{`"); | |
1460 | return Err(err); | |
9e0c209e | 1461 | } |
c34b1796 | 1462 | }; |
abe05a73 | 1463 | (ident, ast::TraitItemKind::Method(sig, body), generics) |
9e0c209e SL |
1464 | }; |
1465 | ||
3157f602 XL |
1466 | Ok(TraitItem { |
1467 | id: ast::DUMMY_NODE_ID, | |
1468 | ident: name, | |
3b2f2976 | 1469 | attrs, |
abe05a73 | 1470 | generics, |
3b2f2976 | 1471 | node, |
cc61c64b | 1472 | span: lo.to(self.prev_span), |
3b2f2976 | 1473 | tokens: None, |
3157f602 XL |
1474 | }) |
1475 | } | |
c34b1796 | 1476 | |
1a4d82fc | 1477 | /// Parse optional return type [ -> TY ] in function decl |
2c00a5a8 | 1478 | fn parse_ret_ty(&mut self, allow_plus: bool) -> PResult<'a, FunctionRetTy> { |
9cc50fc6 | 1479 | if self.eat(&token::RArrow) { |
2c00a5a8 | 1480 | Ok(FunctionRetTy::Ty(self.parse_ty_common(allow_plus, true)?)) |
223e47cc | 1481 | } else { |
0531ce1d | 1482 | Ok(FunctionRetTy::Default(self.span.shrink_to_lo())) |
1a4d82fc JJ |
1483 | } |
1484 | } | |
1485 | ||
cc61c64b | 1486 | // Parse a type |
32a655c1 | 1487 | pub fn parse_ty(&mut self) -> PResult<'a, P<Ty>> { |
ff7c6d11 | 1488 | self.parse_ty_common(true, true) |
223e47cc LB |
1489 | } |
1490 | ||
32a655c1 SL |
1491 | /// Parse a type in restricted contexts where `+` is not permitted. |
1492 | /// Example 1: `&'a TYPE` | |
1493 | /// `+` is prohibited to maintain operator priority (P(+) < P(&)). | |
1494 | /// Example 2: `value1 as TYPE + value2` | |
1495 | /// `+` is prohibited to avoid interactions with expression grammar. | |
cc61c64b | 1496 | fn parse_ty_no_plus(&mut self) -> PResult<'a, P<Ty>> { |
ff7c6d11 | 1497 | self.parse_ty_common(false, true) |
cc61c64b | 1498 | } |
223e47cc | 1499 | |
ff7c6d11 XL |
1500 | fn parse_ty_common(&mut self, allow_plus: bool, allow_qpath_recovery: bool) |
1501 | -> PResult<'a, P<Ty>> { | |
cc61c64b | 1502 | maybe_whole!(self, NtTy, |x| x); |
223e47cc | 1503 | |
cc61c64b | 1504 | let lo = self.span; |
2c00a5a8 | 1505 | let mut impl_dyn_multi = false; |
cc61c64b XL |
1506 | let node = if self.eat(&token::OpenDelim(token::Paren)) { |
1507 | // `(TYPE)` is a parenthesized type. | |
1508 | // `(TYPE,)` is a tuple with a single field of type TYPE. | |
1a4d82fc JJ |
1509 | let mut ts = vec![]; |
1510 | let mut last_comma = false; | |
1511 | while self.token != token::CloseDelim(token::Paren) { | |
32a655c1 SL |
1512 | ts.push(self.parse_ty()?); |
1513 | if self.eat(&token::Comma) { | |
1a4d82fc | 1514 | last_comma = true; |
223e47cc | 1515 | } else { |
1a4d82fc JJ |
1516 | last_comma = false; |
1517 | break; | |
1518 | } | |
223e47cc | 1519 | } |
cc61c64b | 1520 | let trailing_plus = self.prev_token_kind == PrevTokenKind::Plus; |
54a0048b | 1521 | self.expect(&token::CloseDelim(token::Paren))?; |
cc61c64b | 1522 | |
1a4d82fc | 1523 | if ts.len() == 1 && !last_comma { |
ff7c6d11 | 1524 | let ty = ts.into_iter().nth(0).unwrap().into_inner(); |
94b46f34 | 1525 | let maybe_bounds = allow_plus && self.token.is_like_plus(); |
cc61c64b XL |
1526 | match ty.node { |
1527 | // `(TY_BOUND_NOPAREN) + BOUND + ...`. | |
1528 | TyKind::Path(None, ref path) if maybe_bounds => { | |
1529 | self.parse_remaining_bounds(Vec::new(), path.clone(), lo, true)? | |
1530 | } | |
abe05a73 | 1531 | TyKind::TraitObject(ref bounds, TraitObjectSyntax::None) |
cc61c64b XL |
1532 | if maybe_bounds && bounds.len() == 1 && !trailing_plus => { |
1533 | let path = match bounds[0] { | |
8faf50e0 | 1534 | GenericBound::Trait(ref pt, ..) => pt.trait_ref.path.clone(), |
cc61c64b XL |
1535 | _ => self.bug("unexpected lifetime bound"), |
1536 | }; | |
1537 | self.parse_remaining_bounds(Vec::new(), path, lo, true)? | |
1538 | } | |
1539 | // `(TYPE)` | |
1540 | _ => TyKind::Paren(P(ty)) | |
1541 | } | |
1a4d82fc | 1542 | } else { |
7453a54e | 1543 | TyKind::Tup(ts) |
1a4d82fc | 1544 | } |
5bcae85e | 1545 | } else if self.eat(&token::Not) { |
cc61c64b | 1546 | // Never type `!` |
5bcae85e | 1547 | TyKind::Never |
32a655c1 | 1548 | } else if self.eat(&token::BinOp(token::Star)) { |
cc61c64b | 1549 | // Raw pointer |
54a0048b | 1550 | TyKind::Ptr(self.parse_ptr()?) |
32a655c1 | 1551 | } else if self.eat(&token::OpenDelim(token::Bracket)) { |
cc61c64b | 1552 | // Array or slice |
32a655c1 | 1553 | let t = self.parse_ty()?; |
cc61c64b | 1554 | // Parse optional `; EXPR` in `[TYPE; EXPR]` |
54a0048b | 1555 | let t = match self.maybe_parse_fixed_length_of_vec()? { |
c30ab7b3 | 1556 | None => TyKind::Slice(t), |
94b46f34 XL |
1557 | Some(length) => TyKind::Array(t, AnonConst { |
1558 | id: ast::DUMMY_NODE_ID, | |
1559 | value: length, | |
1560 | }), | |
223e47cc | 1561 | }; |
54a0048b | 1562 | self.expect(&token::CloseDelim(token::Bracket))?; |
223e47cc | 1563 | t |
cc61c64b XL |
1564 | } else if self.check(&token::BinOp(token::And)) || self.check(&token::AndAnd) { |
1565 | // Reference | |
54a0048b SL |
1566 | self.expect_and()?; |
1567 | self.parse_borrowed_pointee()? | |
9cc50fc6 | 1568 | } else if self.eat_keyword_noexpect(keywords::Typeof) { |
cc61c64b | 1569 | // `typeof(EXPR)` |
1a4d82fc | 1570 | // In order to not be ambiguous, the type must be surrounded by parens. |
54a0048b | 1571 | self.expect(&token::OpenDelim(token::Paren))?; |
94b46f34 XL |
1572 | let e = AnonConst { |
1573 | id: ast::DUMMY_NODE_ID, | |
1574 | value: self.parse_expr()?, | |
1575 | }; | |
54a0048b | 1576 | self.expect(&token::CloseDelim(token::Paren))?; |
7453a54e | 1577 | TyKind::Typeof(e) |
0531ce1d | 1578 | } else if self.eat_keyword(keywords::Underscore) { |
cc61c64b XL |
1579 | // A type to be inferred `_` |
1580 | TyKind::Infer | |
cc61c64b XL |
1581 | } else if self.token_is_bare_fn_keyword() { |
1582 | // Function pointer type | |
1583 | self.parse_ty_bare_fn(Vec::new())? | |
1584 | } else if self.check_keyword(keywords::For) { | |
1585 | // Function pointer type or bound list (trait object type) starting with a poly-trait. | |
1586 | // `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T` | |
1587 | // `for<'lt> Trait1<'lt> + Trait2 + 'a` | |
1588 | let lo = self.span; | |
1589 | let lifetime_defs = self.parse_late_bound_lifetime_defs()?; | |
1590 | if self.token_is_bare_fn_keyword() { | |
1591 | self.parse_ty_bare_fn(lifetime_defs)? | |
1592 | } else { | |
1593 | let path = self.parse_path(PathStyle::Type)?; | |
94b46f34 | 1594 | let parse_plus = allow_plus && self.check_plus(); |
cc61c64b XL |
1595 | self.parse_remaining_bounds(lifetime_defs, path, lo, parse_plus)? |
1596 | } | |
1597 | } else if self.eat_keyword(keywords::Impl) { | |
2c00a5a8 | 1598 | // Always parse bounds greedily for better error recovery. |
8faf50e0 | 1599 | let bounds = self.parse_generic_bounds()?; |
2c00a5a8 | 1600 | impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus; |
8faf50e0 | 1601 | TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds) |
abe05a73 | 1602 | } else if self.check_keyword(keywords::Dyn) && |
0bf4aa26 XL |
1603 | (self.span.edition() == Edition::Edition2018 || |
1604 | self.look_ahead(1, |t| t.can_begin_bound() && | |
1605 | !can_continue_type_after_non_fn_ident(t))) { | |
abe05a73 | 1606 | self.bump(); // `dyn` |
2c00a5a8 | 1607 | // Always parse bounds greedily for better error recovery. |
8faf50e0 | 1608 | let bounds = self.parse_generic_bounds()?; |
2c00a5a8 XL |
1609 | impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus; |
1610 | TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn) | |
7cac9316 | 1611 | } else if self.check(&token::Question) || |
94b46f34 | 1612 | self.check_lifetime() && self.look_ahead(1, |t| t.is_like_plus()) { |
cc61c64b | 1613 | // Bound list (trait object type) |
8faf50e0 | 1614 | TyKind::TraitObject(self.parse_generic_bounds_common(allow_plus)?, |
abe05a73 XL |
1615 | TraitObjectSyntax::None) |
1616 | } else if self.eat_lt() { | |
1617 | // Qualified path | |
1618 | let (qself, path) = self.parse_qpath(PathStyle::Type)?; | |
1619 | TyKind::Path(Some(qself), path) | |
1620 | } else if self.token.is_path_start() { | |
1621 | // Simple path | |
1622 | let path = self.parse_path(PathStyle::Type)?; | |
1623 | if self.eat(&token::Not) { | |
1624 | // Macro invocation in type position | |
94b46f34 XL |
1625 | let (delim, tts) = self.expect_delimited_token_tree()?; |
1626 | let node = Mac_ { path, tts, delim }; | |
1627 | TyKind::Mac(respan(lo.to(self.prev_span), node)) | |
abe05a73 XL |
1628 | } else { |
1629 | // Just a type path or bound list (trait object type) starting with a trait. | |
1630 | // `Type` | |
1631 | // `Trait1 + Trait2 + 'a` | |
94b46f34 | 1632 | if allow_plus && self.check_plus() { |
abe05a73 XL |
1633 | self.parse_remaining_bounds(Vec::new(), path, lo, true)? |
1634 | } else { | |
1635 | TyKind::Path(None, path) | |
1636 | } | |
1637 | } | |
223e47cc | 1638 | } else { |
a7813a04 XL |
1639 | let msg = format!("expected type, found {}", self.this_token_descr()); |
1640 | return Err(self.fatal(&msg)); | |
223e47cc LB |
1641 | }; |
1642 | ||
cc61c64b | 1643 | let span = lo.to(self.prev_span); |
abe05a73 | 1644 | let ty = Ty { node, span, id: ast::DUMMY_NODE_ID }; |
cc61c64b XL |
1645 | |
1646 | // Try to recover from use of `+` with incorrect priority. | |
2c00a5a8 | 1647 | self.maybe_report_ambiguous_plus(allow_plus, impl_dyn_multi, &ty); |
cc61c64b | 1648 | self.maybe_recover_from_bad_type_plus(allow_plus, &ty)?; |
ff7c6d11 | 1649 | let ty = self.maybe_recover_from_bad_qpath(ty, allow_qpath_recovery)?; |
cc61c64b XL |
1650 | |
1651 | Ok(P(ty)) | |
1652 | } | |
1653 | ||
ff7c6d11 | 1654 | fn parse_remaining_bounds(&mut self, generic_params: Vec<GenericParam>, path: ast::Path, |
cc61c64b | 1655 | lo: Span, parse_plus: bool) -> PResult<'a, TyKind> { |
ff7c6d11 | 1656 | let poly_trait_ref = PolyTraitRef::new(generic_params, path, lo.to(self.prev_span)); |
8faf50e0 | 1657 | let mut bounds = vec![GenericBound::Trait(poly_trait_ref, TraitBoundModifier::None)]; |
cc61c64b | 1658 | if parse_plus { |
94b46f34 | 1659 | self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded |
8faf50e0 | 1660 | bounds.append(&mut self.parse_generic_bounds()?); |
cc61c64b | 1661 | } |
abe05a73 | 1662 | Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None)) |
223e47cc LB |
1663 | } |
1664 | ||
2c00a5a8 XL |
1665 | fn maybe_report_ambiguous_plus(&mut self, allow_plus: bool, impl_dyn_multi: bool, ty: &Ty) { |
1666 | if !allow_plus && impl_dyn_multi { | |
1667 | let sum_with_parens = format!("({})", pprust::ty_to_string(&ty)); | |
1668 | self.struct_span_err(ty.span, "ambiguous `+` in a type") | |
94b46f34 XL |
1669 | .span_suggestion_with_applicability( |
1670 | ty.span, | |
1671 | "use parentheses to disambiguate", | |
1672 | sum_with_parens, | |
1673 | Applicability::MachineApplicable | |
1674 | ).emit(); | |
2c00a5a8 XL |
1675 | } |
1676 | } | |
1677 | ||
cc61c64b XL |
1678 | fn maybe_recover_from_bad_type_plus(&mut self, allow_plus: bool, ty: &Ty) -> PResult<'a, ()> { |
1679 | // Do not add `+` to expected tokens. | |
94b46f34 | 1680 | if !allow_plus || !self.token.is_like_plus() { |
cc61c64b XL |
1681 | return Ok(()) |
1682 | } | |
1683 | ||
1684 | self.bump(); // `+` | |
8faf50e0 | 1685 | let bounds = self.parse_generic_bounds()?; |
cc61c64b XL |
1686 | let sum_span = ty.span.to(self.prev_span); |
1687 | ||
7cac9316 XL |
1688 | let mut err = struct_span_err!(self.sess.span_diagnostic, sum_span, E0178, |
1689 | "expected a path on the left-hand side of `+`, not `{}`", pprust::ty_to_string(ty)); | |
cc61c64b XL |
1690 | |
1691 | match ty.node { | |
1692 | TyKind::Rptr(ref lifetime, ref mut_ty) => { | |
1693 | let sum_with_parens = pprust::to_string(|s| { | |
cc61c64b XL |
1694 | use print::pprust::PrintState; |
1695 | ||
041b39d2 | 1696 | s.s.word("&")?; |
cc61c64b XL |
1697 | s.print_opt_lifetime(lifetime)?; |
1698 | s.print_mutability(mut_ty.mutbl)?; | |
1699 | s.popen()?; | |
1700 | s.print_type(&mut_ty.ty)?; | |
8faf50e0 | 1701 | s.print_type_bounds(" +", &bounds)?; |
cc61c64b XL |
1702 | s.pclose() |
1703 | }); | |
94b46f34 XL |
1704 | err.span_suggestion_with_applicability( |
1705 | sum_span, | |
1706 | "try adding parentheses", | |
1707 | sum_with_parens, | |
1708 | Applicability::MachineApplicable | |
1709 | ); | |
cc61c64b XL |
1710 | } |
1711 | TyKind::Ptr(..) | TyKind::BareFn(..) => { | |
7cac9316 | 1712 | err.span_label(sum_span, "perhaps you forgot parentheses?"); |
cc61c64b | 1713 | } |
7cac9316 XL |
1714 | _ => { |
1715 | err.span_label(sum_span, "expected a path"); | |
1716 | }, | |
cc61c64b XL |
1717 | } |
1718 | err.emit(); | |
1719 | Ok(()) | |
1720 | } | |
1721 | ||
ff7c6d11 XL |
1722 | // Try to recover from associated item paths like `[T]::AssocItem`/`(T, U)::AssocItem`. |
1723 | fn maybe_recover_from_bad_qpath<T: RecoverQPath>(&mut self, base: T, allow_recovery: bool) | |
1724 | -> PResult<'a, T> { | |
1725 | // Do not add `::` to expected tokens. | |
1726 | if !allow_recovery || self.token != token::ModSep { | |
1727 | return Ok(base); | |
1728 | } | |
1729 | let ty = match base.to_ty() { | |
1730 | Some(ty) => ty, | |
1731 | None => return Ok(base), | |
1732 | }; | |
1733 | ||
1734 | self.bump(); // `::` | |
1735 | let mut segments = Vec::new(); | |
1736 | self.parse_path_segments(&mut segments, T::PATH_STYLE, true)?; | |
1737 | ||
1738 | let span = ty.span.to(self.prev_span); | |
94b46f34 XL |
1739 | let path_span = span.to(span); // use an empty path since `position` == 0 |
1740 | let recovered = base.to_recovered( | |
1741 | Some(QSelf { ty, path_span, position: 0 }), | |
1742 | ast::Path { segments, span }, | |
1743 | ); | |
ff7c6d11 XL |
1744 | |
1745 | self.diagnostic() | |
1746 | .struct_span_err(span, "missing angle brackets in associated item path") | |
94b46f34 XL |
1747 | .span_suggestion_with_applicability( // this is a best-effort recovery |
1748 | span, "try", recovered.to_string(), Applicability::MaybeIncorrect | |
1749 | ).emit(); | |
ff7c6d11 XL |
1750 | |
1751 | Ok(recovered) | |
1752 | } | |
1753 | ||
cc61c64b XL |
1754 | fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> { |
1755 | let opt_lifetime = if self.check_lifetime() { Some(self.expect_lifetime()) } else { None }; | |
1756 | let mutbl = self.parse_mutability(); | |
32a655c1 SL |
1757 | let ty = self.parse_ty_no_plus()?; |
1758 | return Ok(TyKind::Rptr(opt_lifetime, MutTy { ty: ty, mutbl: mutbl })); | |
1a4d82fc JJ |
1759 | } |
1760 | ||
94b46f34 | 1761 | fn parse_ptr(&mut self) -> PResult<'a, MutTy> { |
9cc50fc6 | 1762 | let mutbl = if self.eat_keyword(keywords::Mut) { |
7453a54e | 1763 | Mutability::Mutable |
9cc50fc6 | 1764 | } else if self.eat_keyword(keywords::Const) { |
7453a54e | 1765 | Mutability::Immutable |
223e47cc | 1766 | } else { |
c30ab7b3 | 1767 | let span = self.prev_span; |
1a4d82fc | 1768 | self.span_err(span, |
a7813a04 XL |
1769 | "expected mut or const in raw pointer type (use \ |
1770 | `*mut T` or `*const T` as appropriate)"); | |
7453a54e | 1771 | Mutability::Immutable |
1a4d82fc | 1772 | }; |
32a655c1 | 1773 | let t = self.parse_ty_no_plus()?; |
9346a6ac | 1774 | Ok(MutTy { ty: t, mutbl: mutbl }) |
223e47cc LB |
1775 | } |
1776 | ||
abe05a73 | 1777 | fn is_named_argument(&mut self) -> bool { |
1a4d82fc | 1778 | let offset = match self.token { |
abe05a73 XL |
1779 | token::Interpolated(ref nt) => match nt.0 { |
1780 | token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon), | |
1781 | _ => 0, | |
1782 | } | |
1783 | token::BinOp(token::And) | token::AndAnd => 1, | |
1a4d82fc | 1784 | _ if self.token.is_keyword(keywords::Mut) => 1, |
abe05a73 | 1785 | _ => 0, |
1a4d82fc JJ |
1786 | }; |
1787 | ||
0531ce1d | 1788 | self.look_ahead(offset, |t| t.is_ident()) && |
abe05a73 | 1789 | self.look_ahead(offset + 1, |t| t == &token::Colon) |
223e47cc LB |
1790 | } |
1791 | ||
1a4d82fc JJ |
1792 | /// This version of parse arg doesn't necessarily require |
1793 | /// identifier names. | |
94b46f34 | 1794 | fn parse_arg_general(&mut self, require_name: bool) -> PResult<'a, Arg> { |
c30ab7b3 | 1795 | maybe_whole!(self, NtArg, |x| x); |
92a42be0 | 1796 | |
94b46f34 | 1797 | let (pat, ty) = if require_name || self.is_named_argument() { |
1a4d82fc JJ |
1798 | debug!("parse_arg_general parse_pat (require_name:{})", |
1799 | require_name); | |
54a0048b | 1800 | let pat = self.parse_pat()?; |
970d7e83 | 1801 | |
0bf4aa26 XL |
1802 | if let Err(mut err) = self.expect(&token::Colon) { |
1803 | // If we find a pattern followed by an identifier, it could be an (incorrect) | |
1804 | // C-style parameter declaration. | |
1805 | if self.check_ident() && self.look_ahead(1, |t| { | |
1806 | *t == token::Comma || *t == token::CloseDelim(token::Paren) | |
1807 | }) { | |
1808 | let ident = self.parse_ident().unwrap(); | |
1809 | let span = pat.span.with_hi(ident.span.hi()); | |
b7449926 | 1810 | |
0bf4aa26 XL |
1811 | err.span_suggestion_with_applicability( |
1812 | span, | |
1813 | "declare the type after the parameter binding", | |
1814 | String::from("<identifier>: <type>"), | |
1815 | Applicability::HasPlaceholders, | |
1816 | ); | |
1817 | } | |
b7449926 | 1818 | |
0bf4aa26 | 1819 | return Err(err); |
b7449926 XL |
1820 | } |
1821 | ||
0bf4aa26 XL |
1822 | (pat, self.parse_ty()?) |
1823 | } else { | |
1824 | debug!("parse_arg_general ident_to_pat"); | |
1825 | let parser_snapshot_before_ty = self.clone(); | |
1826 | let mut ty = self.parse_ty(); | |
1827 | if ty.is_ok() && self.token == token::Colon { | |
1828 | // This wasn't actually a type, but a pattern looking like a type, | |
1829 | // so we are going to rollback and re-parse for recovery. | |
1830 | ty = self.unexpected(); | |
1831 | } | |
1832 | match ty { | |
1833 | Ok(ty) => { | |
1834 | let ident = Ident::new(keywords::Invalid.name(), self.prev_span); | |
1835 | let pat = P(Pat { | |
1836 | id: ast::DUMMY_NODE_ID, | |
1837 | node: PatKind::Ident( | |
1838 | BindingMode::ByValue(Mutability::Immutable), ident, None), | |
1839 | span: ty.span, | |
1840 | }); | |
1841 | (pat, ty) | |
1842 | } | |
1843 | Err(mut err) => { | |
1844 | // Recover from attempting to parse the argument as a type without pattern. | |
1845 | err.cancel(); | |
1846 | mem::replace(self, parser_snapshot_before_ty); | |
1847 | let pat = self.parse_pat()?; | |
1848 | self.expect(&token::Colon)?; | |
1849 | let ty = self.parse_ty()?; | |
b7449926 | 1850 | |
b7449926 XL |
1851 | let mut err = self.diagnostic().struct_span_err_with_code( |
1852 | pat.span, | |
1853 | "patterns aren't allowed in methods without bodies", | |
1854 | DiagnosticId::Error("E0642".into()), | |
1855 | ); | |
1856 | err.span_suggestion_short_with_applicability( | |
1857 | pat.span, | |
1858 | "give this argument a name or use an underscore to ignore it", | |
1859 | "_".to_owned(), | |
1860 | Applicability::MachineApplicable, | |
1861 | ); | |
1862 | err.emit(); | |
0bf4aa26 | 1863 | |
b7449926 XL |
1864 | // Pretend the pattern is `_`, to avoid duplicate errors from AST validation. |
1865 | let pat = P(Pat { | |
1866 | node: PatKind::Wild, | |
1867 | span: pat.span, | |
1868 | id: ast::DUMMY_NODE_ID | |
1869 | }); | |
1870 | (pat, ty) | |
1871 | } | |
b7449926 | 1872 | } |
223e47cc LB |
1873 | }; |
1874 | ||
b7449926 | 1875 | Ok(Arg { ty, pat, id: ast::DUMMY_NODE_ID }) |
223e47cc LB |
1876 | } |
1877 | ||
1a4d82fc | 1878 | /// Parse a single function argument |
94b46f34 | 1879 | crate fn parse_arg(&mut self) -> PResult<'a, Arg> { |
1a4d82fc | 1880 | self.parse_arg_general(true) |
223e47cc LB |
1881 | } |
1882 | ||
1a4d82fc | 1883 | /// Parse an argument in a lambda header e.g. |arg, arg| |
94b46f34 | 1884 | fn parse_fn_block_arg(&mut self) -> PResult<'a, Arg> { |
54a0048b | 1885 | let pat = self.parse_pat()?; |
9cc50fc6 | 1886 | let t = if self.eat(&token::Colon) { |
32a655c1 | 1887 | self.parse_ty()? |
223e47cc | 1888 | } else { |
1a4d82fc JJ |
1889 | P(Ty { |
1890 | id: ast::DUMMY_NODE_ID, | |
7453a54e | 1891 | node: TyKind::Infer, |
0bf4aa26 | 1892 | span: self.prev_span, |
1a4d82fc | 1893 | }) |
223e47cc | 1894 | }; |
9346a6ac | 1895 | Ok(Arg { |
223e47cc | 1896 | ty: t, |
3b2f2976 | 1897 | pat, |
1a4d82fc | 1898 | id: ast::DUMMY_NODE_ID |
9346a6ac | 1899 | }) |
223e47cc LB |
1900 | } |
1901 | ||
94b46f34 | 1902 | fn maybe_parse_fixed_length_of_vec(&mut self) -> PResult<'a, Option<P<ast::Expr>>> { |
32a655c1 | 1903 | if self.eat(&token::Semi) { |
54a0048b | 1904 | Ok(Some(self.parse_expr()?)) |
223e47cc | 1905 | } else { |
9346a6ac | 1906 | Ok(None) |
223e47cc LB |
1907 | } |
1908 | } | |
1909 | ||
1a4d82fc | 1910 | /// Matches token_lit = LIT_INTEGER | ... |
94b46f34 | 1911 | fn parse_lit_token(&mut self) -> PResult<'a, LitKind> { |
a7813a04 | 1912 | let out = match self.token { |
041b39d2 | 1913 | token::Interpolated(ref nt) => match nt.0 { |
94b46f34 | 1914 | token::NtExpr(ref v) | token::NtLiteral(ref v) => match v.node { |
a7813a04 XL |
1915 | ExprKind::Lit(ref lit) => { lit.node.clone() } |
1916 | _ => { return self.unexpected_last(&self.token); } | |
c30ab7b3 SL |
1917 | }, |
1918 | _ => { return self.unexpected_last(&self.token); } | |
1919 | }, | |
1a4d82fc | 1920 | token::Literal(lit, suf) => { |
cc61c64b XL |
1921 | let diag = Some((self.span, &self.sess.span_diagnostic)); |
1922 | let (suffix_illegal, result) = parse::lit_token(lit, suf, diag); | |
1a4d82fc JJ |
1923 | |
1924 | if suffix_illegal { | |
a7813a04 | 1925 | let sp = self.span; |
7453a54e | 1926 | self.expect_no_suffix(sp, &format!("{} literal", lit.short_name()), suf) |
1a4d82fc JJ |
1927 | } |
1928 | ||
cc61c64b | 1929 | result.unwrap() |
1a4d82fc | 1930 | } |
a7813a04 XL |
1931 | _ => { return self.unexpected_last(&self.token); } |
1932 | }; | |
1933 | ||
1934 | self.bump(); | |
1935 | Ok(out) | |
223e47cc LB |
1936 | } |
1937 | ||
1a4d82fc | 1938 | /// Matches lit = true | false | token_lit |
94b46f34 | 1939 | crate fn parse_lit(&mut self) -> PResult<'a, Lit> { |
cc61c64b | 1940 | let lo = self.span; |
9cc50fc6 | 1941 | let lit = if self.eat_keyword(keywords::True) { |
7453a54e | 1942 | LitKind::Bool(true) |
9cc50fc6 | 1943 | } else if self.eat_keyword(keywords::False) { |
7453a54e | 1944 | LitKind::Bool(false) |
223e47cc | 1945 | } else { |
a7813a04 | 1946 | let lit = self.parse_lit_token()?; |
1a4d82fc | 1947 | lit |
223e47cc | 1948 | }; |
b7449926 | 1949 | Ok(source_map::Spanned { node: lit, span: lo.to(self.prev_span) }) |
223e47cc LB |
1950 | } |
1951 | ||
041b39d2 | 1952 | /// matches '-' lit | lit (cf. ast_validation::AstValidator::check_expr_within_pat) |
94b46f34 | 1953 | crate fn parse_literal_maybe_minus(&mut self) -> PResult<'a, P<Expr>> { |
041b39d2 XL |
1954 | maybe_whole_expr!(self); |
1955 | ||
cc61c64b | 1956 | let minus_lo = self.span; |
9cc50fc6 | 1957 | let minus_present = self.eat(&token::BinOp(token::Minus)); |
cc61c64b | 1958 | let lo = self.span; |
54a0048b | 1959 | let literal = P(self.parse_lit()?); |
cc61c64b XL |
1960 | let hi = self.prev_span; |
1961 | let expr = self.mk_expr(lo.to(hi), ExprKind::Lit(literal), ThinVec::new()); | |
970d7e83 LB |
1962 | |
1963 | if minus_present { | |
cc61c64b | 1964 | let minus_hi = self.prev_span; |
7453a54e | 1965 | let unary = self.mk_unary(UnOp::Neg, expr); |
cc61c64b | 1966 | Ok(self.mk_expr(minus_lo.to(minus_hi), unary, ThinVec::new())) |
970d7e83 | 1967 | } else { |
9346a6ac | 1968 | Ok(expr) |
970d7e83 LB |
1969 | } |
1970 | } | |
1971 | ||
94b46f34 | 1972 | fn parse_path_segment_ident(&mut self) -> PResult<'a, ast::Ident> { |
a7813a04 | 1973 | match self.token { |
83c7162d XL |
1974 | token::Ident(ident, _) if self.token.is_path_segment_keyword() => { |
1975 | let span = self.span; | |
a7813a04 | 1976 | self.bump(); |
83c7162d | 1977 | Ok(Ident::new(ident.name, span)) |
a7813a04 XL |
1978 | } |
1979 | _ => self.parse_ident(), | |
83c7162d XL |
1980 | } |
1981 | } | |
a7813a04 | 1982 | |
b039eaaf | 1983 | /// Parses qualified path. |
b039eaaf SL |
1984 | /// Assumes that the leading `<` has been parsed already. |
1985 | /// | |
b039eaaf SL |
1986 | /// `qualified_path = <type [as trait_ref]>::path` |
1987 | /// | |
3b2f2976 | 1988 | /// # Examples |
94b46f34 | 1989 | /// `<T>::default` |
b039eaaf | 1990 | /// `<T as U>::a` |
3b2f2976 XL |
1991 | /// `<T as U>::F::a<S>` (without disambiguator) |
1992 | /// `<T as U>::F::a::<S>` (with disambiguator) | |
1993 | fn parse_qpath(&mut self, style: PathStyle) -> PResult<'a, (QSelf, ast::Path)> { | |
1994 | let lo = self.prev_span; | |
1995 | let ty = self.parse_ty()?; | |
94b46f34 XL |
1996 | |
1997 | // `path` will contain the prefix of the path up to the `>`, | |
1998 | // if any (e.g., `U` in the `<T as U>::*` examples | |
1999 | // above). `path_span` has the span of that path, or an empty | |
2000 | // span in the case of something like `<T>::Bar`. | |
2001 | let (mut path, path_span); | |
2002 | if self.eat_keyword(keywords::As) { | |
2003 | let path_lo = self.span; | |
2004 | path = self.parse_path(PathStyle::Type)?; | |
2005 | path_span = path_lo.to(self.prev_span); | |
d9579d0f | 2006 | } else { |
94b46f34 XL |
2007 | path = ast::Path { segments: Vec::new(), span: syntax_pos::DUMMY_SP }; |
2008 | path_span = self.span.to(self.span); | |
2009 | } | |
2010 | ||
54a0048b SL |
2011 | self.expect(&token::Gt)?; |
2012 | self.expect(&token::ModSep)?; | |
d9579d0f | 2013 | |
94b46f34 | 2014 | let qself = QSelf { ty, path_span, position: path.segments.len() }; |
3b2f2976 | 2015 | self.parse_path_segments(&mut path.segments, style, true)?; |
d9579d0f | 2016 | |
3b2f2976 | 2017 | Ok((qself, ast::Path { segments: path.segments, span: lo.to(self.prev_span) })) |
d9579d0f AL |
2018 | } |
2019 | ||
3b2f2976 XL |
2020 | /// Parses simple paths. |
2021 | /// | |
2022 | /// `path = [::] segment+` | |
2023 | /// `segment = ident | ident[::]<args> | ident[::](args) [-> type]` | |
2024 | /// | |
2025 | /// # Examples | |
2026 | /// `a::b::C<D>` (without disambiguator) | |
2027 | /// `a::b::C::<D>` (with disambiguator) | |
2028 | /// `Fn(Args)` (without disambiguator) | |
2029 | /// `Fn::(Args)` (with disambiguator) | |
2030 | pub fn parse_path(&mut self, style: PathStyle) -> PResult<'a, ast::Path> { | |
2031 | self.parse_path_common(style, true) | |
041b39d2 XL |
2032 | } |
2033 | ||
94b46f34 | 2034 | crate fn parse_path_common(&mut self, style: PathStyle, enable_warning: bool) |
3b2f2976 | 2035 | -> PResult<'a, ast::Path> { |
041b39d2 | 2036 | maybe_whole!(self, NtPath, |path| { |
3b2f2976 | 2037 | if style == PathStyle::Mod && |
8faf50e0 | 2038 | path.segments.iter().any(|segment| segment.args.is_some()) { |
041b39d2 XL |
2039 | self.diagnostic().span_err(path.span, "unexpected generic arguments in path"); |
2040 | } | |
2041 | path | |
2042 | }); | |
970d7e83 | 2043 | |
cc61c64b | 2044 | let lo = self.meta_var_span.unwrap_or(self.span); |
3b2f2976 XL |
2045 | let mut segments = Vec::new(); |
2046 | if self.eat(&token::ModSep) { | |
0531ce1d | 2047 | segments.push(PathSegment::crate_root(lo.shrink_to_lo())); |
32a655c1 | 2048 | } |
3b2f2976 | 2049 | self.parse_path_segments(&mut segments, style, enable_warning)?; |
32a655c1 | 2050 | |
3b2f2976 | 2051 | Ok(ast::Path { segments, span: lo.to(self.prev_span) }) |
223e47cc LB |
2052 | } |
2053 | ||
cc61c64b XL |
2054 | /// Like `parse_path`, but also supports parsing `Word` meta items into paths for back-compat. |
2055 | /// This is used when parsing derive macro paths in `#[derive]` attributes. | |
3b2f2976 | 2056 | pub fn parse_path_allowing_meta(&mut self, style: PathStyle) -> PResult<'a, ast::Path> { |
cc61c64b | 2057 | let meta_ident = match self.token { |
041b39d2 | 2058 | token::Interpolated(ref nt) => match nt.0 { |
cc61c64b | 2059 | token::NtMeta(ref meta) => match meta.node { |
83c7162d | 2060 | ast::MetaItemKind::Word => Some(meta.ident.clone()), |
cc61c64b XL |
2061 | _ => None, |
2062 | }, | |
2063 | _ => None, | |
2064 | }, | |
2065 | _ => None, | |
2066 | }; | |
83c7162d | 2067 | if let Some(path) = meta_ident { |
cc61c64b | 2068 | self.bump(); |
83c7162d | 2069 | return Ok(path); |
cc61c64b | 2070 | } |
3b2f2976 | 2071 | self.parse_path(style) |
cc61c64b XL |
2072 | } |
2073 | ||
abe05a73 XL |
2074 | fn parse_path_segments(&mut self, |
2075 | segments: &mut Vec<PathSegment>, | |
2076 | style: PathStyle, | |
2077 | enable_warning: bool) | |
2078 | -> PResult<'a, ()> { | |
1a4d82fc | 2079 | loop { |
3b2f2976 | 2080 | segments.push(self.parse_path_segment(style, enable_warning)?); |
223e47cc | 2081 | |
0531ce1d | 2082 | if self.is_import_coupler() || !self.eat(&token::ModSep) { |
3b2f2976 | 2083 | return Ok(()); |
223e47cc | 2084 | } |
1a4d82fc JJ |
2085 | } |
2086 | } | |
223e47cc | 2087 | |
3b2f2976 XL |
2088 | fn parse_path_segment(&mut self, style: PathStyle, enable_warning: bool) |
2089 | -> PResult<'a, PathSegment> { | |
3b2f2976 XL |
2090 | let ident = self.parse_path_segment_ident()?; |
2091 | ||
2092 | let is_args_start = |token: &token::Token| match *token { | |
2093 | token::Lt | token::BinOp(token::Shl) | token::OpenDelim(token::Paren) => true, | |
2094 | _ => false, | |
2095 | }; | |
2096 | let check_args_start = |this: &mut Self| { | |
2097 | this.expected_tokens.extend_from_slice( | |
2098 | &[TokenType::Token(token::Lt), TokenType::Token(token::OpenDelim(token::Paren))] | |
2099 | ); | |
2100 | is_args_start(&this.token) | |
2101 | }; | |
1a4d82fc | 2102 | |
3b2f2976 XL |
2103 | Ok(if style == PathStyle::Type && check_args_start(self) || |
2104 | style != PathStyle::Mod && self.check(&token::ModSep) | |
2105 | && self.look_ahead(1, |t| is_args_start(t)) { | |
2106 | // Generic arguments are found - `<`, `(`, `::<` or `::(`. | |
2107 | let lo = self.span; | |
2108 | if self.eat(&token::ModSep) && style == PathStyle::Type && enable_warning { | |
2109 | self.diagnostic().struct_span_warn(self.prev_span, "unnecessary path disambiguator") | |
2110 | .span_label(self.prev_span, "try removing `::`").emit(); | |
1a4d82fc | 2111 | } |
223e47cc | 2112 | |
8faf50e0 | 2113 | let args = if self.eat_lt() { |
3b2f2976 | 2114 | // `<'a, T, A = U>` |
8faf50e0 | 2115 | let (args, bindings) = self.parse_generic_args()?; |
32a655c1 | 2116 | self.expect_gt()?; |
3b2f2976 | 2117 | let span = lo.to(self.prev_span); |
8faf50e0 | 2118 | AngleBracketedArgs { args, bindings, span }.into() |
1a4d82fc | 2119 | } else { |
3b2f2976 XL |
2120 | // `(T, U) -> R` |
2121 | self.bump(); // `(` | |
abe05a73 XL |
2122 | let inputs = self.parse_seq_to_before_tokens( |
2123 | &[&token::CloseDelim(token::Paren)], | |
2124 | SeqSep::trailing_allowed(token::Comma), | |
2125 | TokenExpectType::Expect, | |
2126 | |p| p.parse_ty())?; | |
2127 | self.bump(); // `)` | |
b7449926 | 2128 | let span = lo.to(self.prev_span); |
3b2f2976 | 2129 | let output = if self.eat(&token::RArrow) { |
ff7c6d11 | 2130 | Some(self.parse_ty_common(false, false)?) |
3b2f2976 XL |
2131 | } else { |
2132 | None | |
2133 | }; | |
8faf50e0 | 2134 | ParenthesisedArgs { inputs, output, span }.into() |
3b2f2976 | 2135 | }; |
223e47cc | 2136 | |
8faf50e0 | 2137 | PathSegment { ident, args } |
3b2f2976 XL |
2138 | } else { |
2139 | // Generic arguments are not found. | |
83c7162d | 2140 | PathSegment::from_ident(ident) |
3b2f2976 | 2141 | }) |
1a4d82fc | 2142 | } |
223e47cc | 2143 | |
94b46f34 | 2144 | crate fn check_lifetime(&mut self) -> bool { |
cc61c64b XL |
2145 | self.expected_tokens.push(TokenType::Lifetime); |
2146 | self.token.is_lifetime() | |
2147 | } | |
2148 | ||
2149 | /// Parse single lifetime 'a or panic. | |
94b46f34 | 2150 | crate fn expect_lifetime(&mut self) -> Lifetime { |
83c7162d XL |
2151 | if let Some(ident) = self.token.lifetime() { |
2152 | let span = self.span; | |
ff7c6d11 | 2153 | self.bump(); |
83c7162d | 2154 | Lifetime { ident: Ident::new(ident.name, span), id: ast::DUMMY_NODE_ID } |
ff7c6d11 XL |
2155 | } else { |
2156 | self.span_bug(self.span, "not a lifetime") | |
1a4d82fc | 2157 | } |
223e47cc LB |
2158 | } |
2159 | ||
83c7162d XL |
2160 | fn eat_label(&mut self) -> Option<Label> { |
2161 | if let Some(ident) = self.token.lifetime() { | |
2162 | let span = self.span; | |
2163 | self.bump(); | |
2164 | Some(Label { ident: Ident::new(ident.name, span) }) | |
2165 | } else { | |
2166 | None | |
2167 | } | |
2168 | } | |
2169 | ||
a7813a04 | 2170 | /// Parse mutability (`mut` or nothing). |
cc61c64b | 2171 | fn parse_mutability(&mut self) -> Mutability { |
9cc50fc6 | 2172 | if self.eat_keyword(keywords::Mut) { |
cc61c64b | 2173 | Mutability::Mutable |
223e47cc | 2174 | } else { |
cc61c64b | 2175 | Mutability::Immutable |
223e47cc LB |
2176 | } |
2177 | } | |
2178 | ||
94b46f34 | 2179 | fn parse_field_name(&mut self) -> PResult<'a, Ident> { |
5bcae85e SL |
2180 | if let token::Literal(token::Integer(name), None) = self.token { |
2181 | self.bump(); | |
83c7162d | 2182 | Ok(Ident::new(name, self.prev_span)) |
5bcae85e | 2183 | } else { |
2c00a5a8 | 2184 | self.parse_ident_common(false) |
5bcae85e SL |
2185 | } |
2186 | } | |
2187 | ||
c30ab7b3 | 2188 | /// Parse ident (COLON expr)? |
94b46f34 | 2189 | fn parse_field(&mut self) -> PResult<'a, Field> { |
32a655c1 | 2190 | let attrs = self.parse_outer_attributes()?; |
cc61c64b | 2191 | let lo = self.span; |
c30ab7b3 SL |
2192 | |
2193 | // Check if a colon exists one ahead. This means we're parsing a fieldname. | |
2194 | let (fieldname, expr, is_shorthand) = if self.look_ahead(1, |t| t == &token::Colon) { | |
2195 | let fieldname = self.parse_field_name()?; | |
83c7162d | 2196 | self.bump(); // `:` |
c30ab7b3 SL |
2197 | (fieldname, self.parse_expr()?, false) |
2198 | } else { | |
2c00a5a8 | 2199 | let fieldname = self.parse_ident_common(false)?; |
c30ab7b3 SL |
2200 | |
2201 | // Mimic `x: x` for the `x` field shorthand. | |
83c7162d XL |
2202 | let path = ast::Path::from_ident(fieldname); |
2203 | let expr = self.mk_expr(fieldname.span, ExprKind::Path(None, path), ThinVec::new()); | |
2204 | (fieldname, expr, true) | |
c30ab7b3 | 2205 | }; |
9346a6ac | 2206 | Ok(ast::Field { |
83c7162d | 2207 | ident: fieldname, |
cc61c64b | 2208 | span: lo.to(expr.span), |
3b2f2976 XL |
2209 | expr, |
2210 | is_shorthand, | |
32a655c1 | 2211 | attrs: attrs.into(), |
9346a6ac | 2212 | }) |
223e47cc LB |
2213 | } |
2214 | ||
94b46f34 | 2215 | fn mk_expr(&mut self, span: Span, node: ExprKind, attrs: ThinVec<Attribute>) -> P<Expr> { |
ff7c6d11 | 2216 | P(Expr { node, span, attrs, id: ast::DUMMY_NODE_ID }) |
1a4d82fc JJ |
2217 | } |
2218 | ||
94b46f34 | 2219 | fn mk_unary(&mut self, unop: ast::UnOp, expr: P<Expr>) -> ast::ExprKind { |
7453a54e | 2220 | ExprKind::Unary(unop, expr) |
1a4d82fc JJ |
2221 | } |
2222 | ||
94b46f34 | 2223 | fn mk_binary(&mut self, binop: ast::BinOp, lhs: P<Expr>, rhs: P<Expr>) -> ast::ExprKind { |
7453a54e | 2224 | ExprKind::Binary(binop, lhs, rhs) |
223e47cc LB |
2225 | } |
2226 | ||
94b46f34 | 2227 | fn mk_call(&mut self, f: P<Expr>, args: Vec<P<Expr>>) -> ast::ExprKind { |
7453a54e | 2228 | ExprKind::Call(f, args) |
970d7e83 LB |
2229 | } |
2230 | ||
94b46f34 | 2231 | fn mk_index(&mut self, expr: P<Expr>, idx: P<Expr>) -> ast::ExprKind { |
7453a54e | 2232 | ExprKind::Index(expr, idx) |
970d7e83 LB |
2233 | } |
2234 | ||
94b46f34 | 2235 | fn mk_range(&mut self, |
1a4d82fc | 2236 | start: Option<P<Expr>>, |
54a0048b SL |
2237 | end: Option<P<Expr>>, |
2238 | limits: RangeLimits) | |
2239 | -> PResult<'a, ast::ExprKind> { | |
2240 | if end.is_none() && limits == RangeLimits::Closed { | |
8bb4bdeb | 2241 | Err(self.span_fatal_err(self.span, Error::InclusiveRangeWithNoEnd)) |
54a0048b SL |
2242 | } else { |
2243 | Ok(ExprKind::Range(start, end, limits)) | |
2244 | } | |
970d7e83 LB |
2245 | } |
2246 | ||
94b46f34 | 2247 | fn mk_assign_op(&mut self, binop: ast::BinOp, |
7453a54e SL |
2248 | lhs: P<Expr>, rhs: P<Expr>) -> ast::ExprKind { |
2249 | ExprKind::AssignOp(binop, lhs, rhs) | |
970d7e83 LB |
2250 | } |
2251 | ||
8faf50e0 | 2252 | pub fn mk_mac_expr(&mut self, span: Span, m: Mac_, attrs: ThinVec<Attribute>) -> P<Expr> { |
1a4d82fc JJ |
2253 | P(Expr { |
2254 | id: ast::DUMMY_NODE_ID, | |
b7449926 | 2255 | node: ExprKind::Mac(source_map::Spanned {node: m, span: span}), |
3b2f2976 XL |
2256 | span, |
2257 | attrs, | |
1a4d82fc | 2258 | }) |
223e47cc LB |
2259 | } |
2260 | ||
94b46f34 XL |
2261 | fn expect_delimited_token_tree(&mut self) -> PResult<'a, (MacDelimiter, ThinTokenStream)> { |
2262 | let delim = match self.token { | |
2263 | token::OpenDelim(delim) => delim, | |
0531ce1d XL |
2264 | _ => { |
2265 | let msg = "expected open delimiter"; | |
2266 | let mut err = self.fatal(msg); | |
2267 | err.span_label(self.span, msg); | |
94b46f34 | 2268 | return Err(err) |
0531ce1d | 2269 | } |
94b46f34 XL |
2270 | }; |
2271 | let delimited = match self.parse_token_tree() { | |
2272 | TokenTree::Delimited(_, delimited) => delimited, | |
2273 | _ => unreachable!(), | |
2274 | }; | |
2275 | let delim = match delim { | |
2276 | token::Paren => MacDelimiter::Parenthesis, | |
2277 | token::Bracket => MacDelimiter::Bracket, | |
2278 | token::Brace => MacDelimiter::Brace, | |
2279 | token::NoDelim => self.bug("unexpected no delimiter"), | |
2280 | }; | |
2281 | Ok((delim, delimited.stream().into())) | |
223e47cc LB |
2282 | } |
2283 | ||
1a4d82fc JJ |
2284 | /// At the bottom (top?) of the precedence hierarchy, |
2285 | /// parse things like parenthesized exprs, | |
2286 | /// macros, return, etc. | |
92a42be0 SL |
2287 | /// |
2288 | /// NB: This does not parse outer attributes, | |
2289 | /// and is private because it only works | |
2290 | /// correctly if called from parse_dot_or_call_expr(). | |
9cc50fc6 | 2291 | fn parse_bottom_expr(&mut self) -> PResult<'a, P<Expr>> { |
223e47cc LB |
2292 | maybe_whole_expr!(self); |
2293 | ||
92a42be0 SL |
2294 | // Outer attributes are already parsed and will be |
2295 | // added to the return value after the fact. | |
2296 | // | |
2297 | // Therefore, prevent sub-parser from parsing | |
2298 | // attributes by giving them a empty "already parsed" list. | |
3157f602 | 2299 | let mut attrs = ThinVec::new(); |
92a42be0 | 2300 | |
cc61c64b XL |
2301 | let lo = self.span; |
2302 | let mut hi = self.span; | |
223e47cc | 2303 | |
7453a54e | 2304 | let ex: ExprKind; |
223e47cc | 2305 | |
85aaf69f | 2306 | // Note: when adding new syntax here, don't forget to adjust Token::can_begin_expr(). |
1a4d82fc JJ |
2307 | match self.token { |
2308 | token::OpenDelim(token::Paren) => { | |
9cc50fc6 | 2309 | self.bump(); |
1a4d82fc | 2310 | |
3157f602 | 2311 | attrs.extend(self.parse_inner_attributes()?); |
92a42be0 | 2312 | |
1a4d82fc JJ |
2313 | // (e) is parenthesized e |
2314 | // (e,) is a tuple with only one field, e | |
2315 | let mut es = vec![]; | |
2316 | let mut trailing_comma = false; | |
2317 | while self.token != token::CloseDelim(token::Paren) { | |
54a0048b | 2318 | es.push(self.parse_expr()?); |
5bcae85e | 2319 | self.expect_one_of(&[], &[token::Comma, token::CloseDelim(token::Paren)])?; |
b7449926 | 2320 | if self.eat(&token::Comma) { |
1a4d82fc | 2321 | trailing_comma = true; |
1a4d82fc JJ |
2322 | } else { |
2323 | trailing_comma = false; | |
2324 | break; | |
2325 | } | |
223e47cc | 2326 | } |
9cc50fc6 | 2327 | self.bump(); |
1a4d82fc | 2328 | |
cc61c64b | 2329 | hi = self.prev_span; |
ff7c6d11 XL |
2330 | ex = if es.len() == 1 && !trailing_comma { |
2331 | ExprKind::Paren(es.into_iter().nth(0).unwrap()) | |
1a4d82fc | 2332 | } else { |
ff7c6d11 XL |
2333 | ExprKind::Tup(es) |
2334 | }; | |
3b2f2976 | 2335 | } |
1a4d82fc | 2336 | token::OpenDelim(token::Brace) => { |
94b46f34 | 2337 | return self.parse_block_expr(None, lo, BlockCheckMode::Default, attrs); |
3b2f2976 XL |
2338 | } |
2339 | token::BinOp(token::Or) | token::OrOr => { | |
2c00a5a8 | 2340 | return self.parse_lambda_expr(attrs); |
3b2f2976 | 2341 | } |
1a4d82fc | 2342 | token::OpenDelim(token::Bracket) => { |
9cc50fc6 | 2343 | self.bump(); |
223e47cc | 2344 | |
3157f602 | 2345 | attrs.extend(self.parse_inner_attributes()?); |
92a42be0 | 2346 | |
b7449926 | 2347 | if self.eat(&token::CloseDelim(token::Bracket)) { |
1a4d82fc | 2348 | // Empty vector. |
32a655c1 | 2349 | ex = ExprKind::Array(Vec::new()); |
223e47cc | 2350 | } else { |
1a4d82fc | 2351 | // Nonempty vector. |
54a0048b | 2352 | let first_expr = self.parse_expr()?; |
b7449926 | 2353 | if self.eat(&token::Semi) { |
e9174d1e | 2354 | // Repeating array syntax: [ 0; 512 ] |
94b46f34 XL |
2355 | let count = AnonConst { |
2356 | id: ast::DUMMY_NODE_ID, | |
2357 | value: self.parse_expr()?, | |
2358 | }; | |
54a0048b | 2359 | self.expect(&token::CloseDelim(token::Bracket))?; |
7453a54e | 2360 | ex = ExprKind::Repeat(first_expr, count); |
b7449926 | 2361 | } else if self.eat(&token::Comma) { |
1a4d82fc | 2362 | // Vector with two or more elements. |
54a0048b | 2363 | let remaining_exprs = self.parse_seq_to_end( |
1a4d82fc | 2364 | &token::CloseDelim(token::Bracket), |
7453a54e | 2365 | SeqSep::trailing_allowed(token::Comma), |
54a0048b SL |
2366 | |p| Ok(p.parse_expr()?) |
2367 | )?; | |
c30ab7b3 | 2368 | let mut exprs = vec![first_expr]; |
62682a34 | 2369 | exprs.extend(remaining_exprs); |
32a655c1 | 2370 | ex = ExprKind::Array(exprs); |
1a4d82fc JJ |
2371 | } else { |
2372 | // Vector with one element. | |
54a0048b | 2373 | self.expect(&token::CloseDelim(token::Bracket))?; |
32a655c1 | 2374 | ex = ExprKind::Array(vec![first_expr]); |
1a4d82fc | 2375 | } |
223e47cc | 2376 | } |
cc61c64b | 2377 | hi = self.prev_span; |
223e47cc | 2378 | } |
1a4d82fc | 2379 | _ => { |
9cc50fc6 | 2380 | if self.eat_lt() { |
3b2f2976 | 2381 | let (qself, path) = self.parse_qpath(PathStyle::Expr)?; |
cc61c64b XL |
2382 | hi = path.span; |
2383 | return Ok(self.mk_expr(lo.to(hi), ExprKind::Path(Some(qself), path), attrs)); | |
85aaf69f | 2384 | } |
8faf50e0 XL |
2385 | if self.span.edition() >= Edition::Edition2018 && |
2386 | self.check_keyword(keywords::Async) | |
2387 | { | |
2388 | if self.is_async_block() { // check for `async {` and `async move {` | |
2389 | return self.parse_async_block(attrs); | |
2390 | } else { | |
2391 | return self.parse_lambda_expr(attrs); | |
2392 | } | |
2393 | } | |
2c00a5a8 XL |
2394 | if self.check_keyword(keywords::Move) || self.check_keyword(keywords::Static) { |
2395 | return self.parse_lambda_expr(attrs); | |
1a4d82fc | 2396 | } |
9cc50fc6 | 2397 | if self.eat_keyword(keywords::If) { |
92a42be0 | 2398 | return self.parse_if_expr(attrs); |
1a4d82fc | 2399 | } |
9cc50fc6 | 2400 | if self.eat_keyword(keywords::For) { |
cc61c64b | 2401 | let lo = self.prev_span; |
92a42be0 | 2402 | return self.parse_for_expr(None, lo, attrs); |
1a4d82fc | 2403 | } |
9cc50fc6 | 2404 | if self.eat_keyword(keywords::While) { |
cc61c64b | 2405 | let lo = self.prev_span; |
92a42be0 | 2406 | return self.parse_while_expr(None, lo, attrs); |
1a4d82fc | 2407 | } |
2c00a5a8 | 2408 | if let Some(label) = self.eat_label() { |
83c7162d | 2409 | let lo = label.ident.span; |
54a0048b | 2410 | self.expect(&token::Colon)?; |
9cc50fc6 | 2411 | if self.eat_keyword(keywords::While) { |
3157f602 | 2412 | return self.parse_while_expr(Some(label), lo, attrs) |
1a4d82fc | 2413 | } |
9cc50fc6 | 2414 | if self.eat_keyword(keywords::For) { |
3157f602 | 2415 | return self.parse_for_expr(Some(label), lo, attrs) |
1a4d82fc | 2416 | } |
9cc50fc6 | 2417 | if self.eat_keyword(keywords::Loop) { |
3157f602 | 2418 | return self.parse_loop_expr(Some(label), lo, attrs) |
1a4d82fc | 2419 | } |
94b46f34 XL |
2420 | if self.token == token::OpenDelim(token::Brace) { |
2421 | return self.parse_block_expr(Some(label), | |
2422 | lo, | |
2423 | BlockCheckMode::Default, | |
2424 | attrs); | |
2425 | } | |
2426 | let msg = "expected `while`, `for`, `loop` or `{` after a label"; | |
0531ce1d XL |
2427 | let mut err = self.fatal(msg); |
2428 | err.span_label(self.span, msg); | |
2429 | return Err(err); | |
1a4d82fc | 2430 | } |
9cc50fc6 | 2431 | if self.eat_keyword(keywords::Loop) { |
cc61c64b | 2432 | let lo = self.prev_span; |
92a42be0 | 2433 | return self.parse_loop_expr(None, lo, attrs); |
1a4d82fc | 2434 | } |
9cc50fc6 | 2435 | if self.eat_keyword(keywords::Continue) { |
2c00a5a8 XL |
2436 | let label = self.eat_label(); |
2437 | let ex = ExprKind::Continue(label); | |
cc61c64b XL |
2438 | let hi = self.prev_span; |
2439 | return Ok(self.mk_expr(lo.to(hi), ex, attrs)); | |
1a4d82fc | 2440 | } |
9cc50fc6 | 2441 | if self.eat_keyword(keywords::Match) { |
92a42be0 | 2442 | return self.parse_match_expr(attrs); |
1a4d82fc | 2443 | } |
9cc50fc6 | 2444 | if self.eat_keyword(keywords::Unsafe) { |
1a4d82fc | 2445 | return self.parse_block_expr( |
94b46f34 | 2446 | None, |
1a4d82fc | 2447 | lo, |
7453a54e | 2448 | BlockCheckMode::Unsafe(ast::UserProvided), |
92a42be0 | 2449 | attrs); |
1a4d82fc | 2450 | } |
b7449926 XL |
2451 | if self.is_do_catch_block() { |
2452 | let mut db = self.fatal("found removed `do catch` syntax"); | |
2453 | db.help("Following RFC #2388, the new non-placeholder syntax is `try`"); | |
2454 | return Err(db); | |
2455 | } | |
2456 | if self.is_try_block() { | |
3b2f2976 | 2457 | let lo = self.span; |
b7449926 XL |
2458 | assert!(self.eat_keyword(keywords::Try)); |
2459 | return self.parse_try_block(lo, attrs); | |
cc61c64b | 2460 | } |
9cc50fc6 | 2461 | if self.eat_keyword(keywords::Return) { |
1a4d82fc | 2462 | if self.token.can_begin_expr() { |
54a0048b | 2463 | let e = self.parse_expr()?; |
cc61c64b | 2464 | hi = e.span; |
7453a54e | 2465 | ex = ExprKind::Ret(Some(e)); |
1a4d82fc | 2466 | } else { |
7453a54e | 2467 | ex = ExprKind::Ret(None); |
1a4d82fc | 2468 | } |
9cc50fc6 | 2469 | } else if self.eat_keyword(keywords::Break) { |
2c00a5a8 | 2470 | let label = self.eat_label(); |
476ff2be SL |
2471 | let e = if self.token.can_begin_expr() |
2472 | && !(self.token == token::OpenDelim(token::Brace) | |
2473 | && self.restrictions.contains( | |
ea8adc8c | 2474 | Restrictions::NO_STRUCT_LITERAL)) { |
476ff2be SL |
2475 | Some(self.parse_expr()?) |
2476 | } else { | |
2477 | None | |
2478 | }; | |
2c00a5a8 | 2479 | ex = ExprKind::Break(label, e); |
cc61c64b | 2480 | hi = self.prev_span; |
ea8adc8c XL |
2481 | } else if self.eat_keyword(keywords::Yield) { |
2482 | if self.token.can_begin_expr() { | |
2483 | let e = self.parse_expr()?; | |
2484 | hi = e.span; | |
2485 | ex = ExprKind::Yield(Some(e)); | |
2486 | } else { | |
2487 | ex = ExprKind::Yield(None); | |
2488 | } | |
7453a54e | 2489 | } else if self.token.is_keyword(keywords::Let) { |
041b39d2 | 2490 | // Catch this syntax error here, instead of in `parse_ident`, so |
7453a54e SL |
2491 | // that we can explicitly mention that let is not to be used as an expression |
2492 | let mut db = self.fatal("expected expression, found statement (`let`)"); | |
0531ce1d | 2493 | db.span_label(self.span, "expected expression"); |
7453a54e SL |
2494 | db.note("variable declaration using `let` is a statement"); |
2495 | return Err(db); | |
a7813a04 XL |
2496 | } else if self.token.is_path_start() { |
2497 | let pth = self.parse_path(PathStyle::Expr)?; | |
1a4d82fc JJ |
2498 | |
2499 | // `!`, as an operator, is prefix, so we know this isn't that | |
9e0c209e | 2500 | if self.eat(&token::Not) { |
1a4d82fc | 2501 | // MACRO INVOCATION expression |
94b46f34 | 2502 | let (delim, tts) = self.expect_delimited_token_tree()?; |
cc61c64b | 2503 | let hi = self.prev_span; |
94b46f34 XL |
2504 | let node = Mac_ { path: pth, tts, delim }; |
2505 | return Ok(self.mk_mac_expr(lo.to(hi), node, attrs)) | |
1a4d82fc JJ |
2506 | } |
2507 | if self.check(&token::OpenDelim(token::Brace)) { | |
2508 | // This is a struct literal, unless we're prohibited | |
2509 | // from parsing struct literals here. | |
d9579d0f | 2510 | let prohibited = self.restrictions.contains( |
ea8adc8c | 2511 | Restrictions::NO_STRUCT_LITERAL |
d9579d0f AL |
2512 | ); |
2513 | if !prohibited { | |
9e0c209e | 2514 | return self.parse_struct_expr(lo, pth, attrs); |
223e47cc | 2515 | } |
223e47cc LB |
2516 | } |
2517 | ||
cc61c64b | 2518 | hi = pth.span; |
7453a54e | 2519 | ex = ExprKind::Path(None, pth); |
1a4d82fc | 2520 | } else { |
94b46f34 XL |
2521 | match self.parse_literal_maybe_minus() { |
2522 | Ok(expr) => { | |
2523 | hi = expr.span; | |
2524 | ex = expr.node.clone(); | |
a7813a04 XL |
2525 | } |
2526 | Err(mut err) => { | |
9e0c209e | 2527 | self.cancel(&mut err); |
a7813a04 XL |
2528 | let msg = format!("expected expression, found {}", |
2529 | self.this_token_descr()); | |
0531ce1d XL |
2530 | let mut err = self.fatal(&msg); |
2531 | err.span_label(self.span, "expected expression"); | |
2532 | return Err(err); | |
a7813a04 XL |
2533 | } |
2534 | } | |
223e47cc LB |
2535 | } |
2536 | } | |
223e47cc LB |
2537 | } |
2538 | ||
ff7c6d11 XL |
2539 | let expr = Expr { node: ex, span: lo.to(hi), id: ast::DUMMY_NODE_ID, attrs }; |
2540 | let expr = self.maybe_recover_from_bad_qpath(expr, true)?; | |
2541 | ||
2542 | return Ok(P(expr)); | |
92a42be0 SL |
2543 | } |
2544 | ||
cc61c64b | 2545 | fn parse_struct_expr(&mut self, lo: Span, pth: ast::Path, mut attrs: ThinVec<Attribute>) |
9e0c209e | 2546 | -> PResult<'a, P<Expr>> { |
2c00a5a8 | 2547 | let struct_sp = lo.to(self.prev_span); |
9e0c209e SL |
2548 | self.bump(); |
2549 | let mut fields = Vec::new(); | |
2550 | let mut base = None; | |
2551 | ||
2552 | attrs.extend(self.parse_inner_attributes()?); | |
2553 | ||
2554 | while self.token != token::CloseDelim(token::Brace) { | |
2555 | if self.eat(&token::DotDot) { | |
abe05a73 | 2556 | let exp_span = self.prev_span; |
9e0c209e SL |
2557 | match self.parse_expr() { |
2558 | Ok(e) => { | |
2559 | base = Some(e); | |
2560 | } | |
2561 | Err(mut e) => { | |
2562 | e.emit(); | |
2563 | self.recover_stmt(); | |
2564 | } | |
2565 | } | |
abe05a73 XL |
2566 | if self.token == token::Comma { |
2567 | let mut err = self.sess.span_diagnostic.mut_span_err( | |
2568 | exp_span.to(self.prev_span), | |
2569 | "cannot use a comma after the base struct", | |
2570 | ); | |
94b46f34 XL |
2571 | err.span_suggestion_short_with_applicability( |
2572 | self.span, | |
2573 | "remove this comma", | |
b7449926 | 2574 | String::new(), |
94b46f34 XL |
2575 | Applicability::MachineApplicable |
2576 | ); | |
abe05a73 XL |
2577 | err.note("the base struct must always be the last field"); |
2578 | err.emit(); | |
2579 | self.recover_stmt(); | |
2580 | } | |
9e0c209e SL |
2581 | break; |
2582 | } | |
2583 | ||
2584 | match self.parse_field() { | |
2585 | Ok(f) => fields.push(f), | |
2586 | Err(mut e) => { | |
2c00a5a8 | 2587 | e.span_label(struct_sp, "while parsing this struct"); |
9e0c209e | 2588 | e.emit(); |
8faf50e0 XL |
2589 | |
2590 | // If the next token is a comma, then try to parse | |
2591 | // what comes next as additional fields, rather than | |
2592 | // bailing out until next `}`. | |
2593 | if self.token != token::Comma { | |
2594 | self.recover_stmt(); | |
2595 | break; | |
2596 | } | |
9e0c209e SL |
2597 | } |
2598 | } | |
2599 | ||
2600 | match self.expect_one_of(&[token::Comma], | |
2601 | &[token::CloseDelim(token::Brace)]) { | |
2602 | Ok(()) => {} | |
2603 | Err(mut e) => { | |
2604 | e.emit(); | |
2605 | self.recover_stmt(); | |
2606 | break; | |
2607 | } | |
2608 | } | |
2609 | } | |
2610 | ||
cc61c64b | 2611 | let span = lo.to(self.span); |
9e0c209e | 2612 | self.expect(&token::CloseDelim(token::Brace))?; |
cc61c64b | 2613 | return Ok(self.mk_expr(span, ExprKind::Struct(pth, fields, base), attrs)); |
9e0c209e SL |
2614 | } |
2615 | ||
92a42be0 | 2616 | fn parse_or_use_outer_attributes(&mut self, |
3157f602 XL |
2617 | already_parsed_attrs: Option<ThinVec<Attribute>>) |
2618 | -> PResult<'a, ThinVec<Attribute>> { | |
92a42be0 SL |
2619 | if let Some(attrs) = already_parsed_attrs { |
2620 | Ok(attrs) | |
2621 | } else { | |
3157f602 | 2622 | self.parse_outer_attributes().map(|a| a.into()) |
92a42be0 | 2623 | } |
223e47cc LB |
2624 | } |
2625 | ||
1a4d82fc | 2626 | /// Parse a block or unsafe block |
94b46f34 XL |
2627 | fn parse_block_expr(&mut self, opt_label: Option<Label>, |
2628 | lo: Span, blk_mode: BlockCheckMode, | |
3157f602 | 2629 | outer_attrs: ThinVec<Attribute>) |
9cc50fc6 | 2630 | -> PResult<'a, P<Expr>> { |
54a0048b | 2631 | self.expect(&token::OpenDelim(token::Brace))?; |
92a42be0 | 2632 | |
3157f602 XL |
2633 | let mut attrs = outer_attrs; |
2634 | attrs.extend(self.parse_inner_attributes()?); | |
92a42be0 | 2635 | |
54a0048b | 2636 | let blk = self.parse_block_tail(lo, blk_mode)?; |
94b46f34 | 2637 | return Ok(self.mk_expr(blk.span, ExprKind::Block(blk, opt_label), attrs)); |
223e47cc LB |
2638 | } |
2639 | ||
1a4d82fc | 2640 | /// parse a.b or a(13) or a[4] or just a |
94b46f34 | 2641 | fn parse_dot_or_call_expr(&mut self, |
3157f602 | 2642 | already_parsed_attrs: Option<ThinVec<Attribute>>) |
9cc50fc6 | 2643 | -> PResult<'a, P<Expr>> { |
54a0048b | 2644 | let attrs = self.parse_or_use_outer_attributes(already_parsed_attrs)?; |
92a42be0 | 2645 | |
7453a54e | 2646 | let b = self.parse_bottom_expr(); |
54a0048b | 2647 | let (span, b) = self.interpolated_or_expr_span(b)?; |
cc61c64b | 2648 | self.parse_dot_or_call_expr_with(b, span, attrs) |
92a42be0 SL |
2649 | } |
2650 | ||
94b46f34 | 2651 | fn parse_dot_or_call_expr_with(&mut self, |
92a42be0 | 2652 | e0: P<Expr>, |
cc61c64b | 2653 | lo: Span, |
3157f602 | 2654 | mut attrs: ThinVec<Attribute>) |
9cc50fc6 | 2655 | -> PResult<'a, P<Expr>> { |
92a42be0 SL |
2656 | // Stitch the list of outer attributes onto the return value. |
2657 | // A little bit ugly, but the best way given the current code | |
2658 | // structure | |
7453a54e | 2659 | self.parse_dot_or_call_expr_with_(e0, lo) |
92a42be0 SL |
2660 | .map(|expr| |
2661 | expr.map(|mut expr| { | |
3157f602 XL |
2662 | attrs.extend::<Vec<_>>(expr.attrs.into()); |
2663 | expr.attrs = attrs; | |
92a42be0 | 2664 | match expr.node { |
7453a54e | 2665 | ExprKind::If(..) | ExprKind::IfLet(..) => { |
3157f602 | 2666 | if !expr.attrs.is_empty() { |
92a42be0 | 2667 | // Just point to the first attribute in there... |
3157f602 | 2668 | let span = expr.attrs[0].span; |
92a42be0 SL |
2669 | |
2670 | self.span_err(span, | |
2671 | "attributes are not yet allowed on `if` \ | |
2672 | expressions"); | |
2673 | } | |
2674 | } | |
2675 | _ => {} | |
2676 | } | |
2677 | expr | |
2678 | }) | |
2679 | ) | |
223e47cc LB |
2680 | } |
2681 | ||
3b2f2976 XL |
2682 | // Assuming we have just parsed `.`, continue parsing into an expression. |
2683 | fn parse_dot_suffix(&mut self, self_arg: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> { | |
2684 | let segment = self.parse_path_segment(PathStyle::Expr, true)?; | |
7453a54e | 2685 | Ok(match self.token { |
7453a54e | 2686 | token::OpenDelim(token::Paren) => { |
3b2f2976 XL |
2687 | // Method call `expr.f()` |
2688 | let mut args = self.parse_unspanned_seq( | |
7453a54e SL |
2689 | &token::OpenDelim(token::Paren), |
2690 | &token::CloseDelim(token::Paren), | |
2691 | SeqSep::trailing_allowed(token::Comma), | |
54a0048b SL |
2692 | |p| Ok(p.parse_expr()?) |
2693 | )?; | |
3b2f2976 | 2694 | args.insert(0, self_arg); |
7453a54e | 2695 | |
3b2f2976 XL |
2696 | let span = lo.to(self.prev_span); |
2697 | self.mk_expr(span, ExprKind::MethodCall(segment, args), ThinVec::new()) | |
7453a54e | 2698 | } |
7453a54e | 2699 | _ => { |
3b2f2976 | 2700 | // Field access `expr.f` |
8faf50e0 XL |
2701 | if let Some(args) = segment.args { |
2702 | self.span_err(args.span(), | |
041b39d2 | 2703 | "field expressions may not have generic arguments"); |
7453a54e SL |
2704 | } |
2705 | ||
3b2f2976 | 2706 | let span = lo.to(self.prev_span); |
83c7162d | 2707 | self.mk_expr(span, ExprKind::Field(self_arg, segment.ident), ThinVec::new()) |
7453a54e SL |
2708 | } |
2709 | }) | |
2710 | } | |
2711 | ||
cc61c64b | 2712 | fn parse_dot_or_call_expr_with_(&mut self, e0: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> { |
223e47cc | 2713 | let mut e = e0; |
223e47cc LB |
2714 | let mut hi; |
2715 | loop { | |
54a0048b SL |
2716 | // expr? |
2717 | while self.eat(&token::Question) { | |
cc61c64b XL |
2718 | let hi = self.prev_span; |
2719 | e = self.mk_expr(lo.to(hi), ExprKind::Try(e), ThinVec::new()); | |
54a0048b SL |
2720 | } |
2721 | ||
223e47cc | 2722 | // expr.f |
9cc50fc6 | 2723 | if self.eat(&token::Dot) { |
1a4d82fc | 2724 | match self.token { |
3b2f2976 XL |
2725 | token::Ident(..) => { |
2726 | e = self.parse_dot_suffix(e, lo)?; | |
1a4d82fc | 2727 | } |
83c7162d XL |
2728 | token::Literal(token::Integer(name), _) => { |
2729 | let span = self.span; | |
9cc50fc6 | 2730 | self.bump(); |
83c7162d XL |
2731 | let field = ExprKind::Field(e, Ident::new(name, span)); |
2732 | e = self.mk_expr(lo.to(span), field, ThinVec::new()); | |
223e47cc | 2733 | } |
1a4d82fc | 2734 | token::Literal(token::Float(n), _suf) => { |
9cc50fc6 | 2735 | self.bump(); |
1a4d82fc | 2736 | let fstr = n.as_str(); |
0bf4aa26 XL |
2737 | let mut err = self.diagnostic() |
2738 | .struct_span_err(self.prev_span, &format!("unexpected token: `{}`", n)); | |
7cac9316 | 2739 | err.span_label(self.prev_span, "unexpected token"); |
c34b1796 | 2740 | if fstr.chars().all(|x| "0123456789.".contains(x)) { |
85aaf69f | 2741 | let float = match fstr.parse::<f64>().ok() { |
1a4d82fc JJ |
2742 | Some(f) => f, |
2743 | None => continue, | |
2744 | }; | |
8bb4bdeb XL |
2745 | let sugg = pprust::to_string(|s| { |
2746 | use print::pprust::PrintState; | |
8bb4bdeb XL |
2747 | s.popen()?; |
2748 | s.print_expr(&e)?; | |
041b39d2 | 2749 | s.s.word( ".")?; |
8bb4bdeb XL |
2750 | s.print_usize(float.trunc() as usize)?; |
2751 | s.pclose()?; | |
041b39d2 XL |
2752 | s.s.word(".")?; |
2753 | s.s.word(fstr.splitn(2, ".").last().unwrap()) | |
8bb4bdeb | 2754 | }); |
94b46f34 | 2755 | err.span_suggestion_with_applicability( |
cc61c64b | 2756 | lo.to(self.prev_span), |
8bb4bdeb | 2757 | "try parenthesizing the first index", |
94b46f34 XL |
2758 | sugg, |
2759 | Applicability::MachineApplicable | |
2760 | ); | |
1a4d82fc | 2761 | } |
7453a54e | 2762 | return Err(err); |
1a4d82fc JJ |
2763 | |
2764 | } | |
7453a54e SL |
2765 | _ => { |
2766 | // FIXME Could factor this out into non_fatal_unexpected or something. | |
2767 | let actual = self.this_token_to_string(); | |
2768 | self.span_err(self.span, &format!("unexpected token: `{}`", actual)); | |
7453a54e | 2769 | } |
223e47cc | 2770 | } |
1a4d82fc | 2771 | continue; |
223e47cc | 2772 | } |
7453a54e | 2773 | if self.expr_is_complete(&e) { break; } |
1a4d82fc | 2774 | match self.token { |
223e47cc | 2775 | // expr(...) |
1a4d82fc | 2776 | token::OpenDelim(token::Paren) => { |
54a0048b | 2777 | let es = self.parse_unspanned_seq( |
1a4d82fc JJ |
2778 | &token::OpenDelim(token::Paren), |
2779 | &token::CloseDelim(token::Paren), | |
7453a54e | 2780 | SeqSep::trailing_allowed(token::Comma), |
54a0048b SL |
2781 | |p| Ok(p.parse_expr()?) |
2782 | )?; | |
cc61c64b | 2783 | hi = self.prev_span; |
223e47cc | 2784 | |
1a4d82fc | 2785 | let nd = self.mk_call(e, es); |
cc61c64b | 2786 | e = self.mk_expr(lo.to(hi), nd, ThinVec::new()); |
223e47cc LB |
2787 | } |
2788 | ||
2789 | // expr[...] | |
1a4d82fc JJ |
2790 | // Could be either an index expression or a slicing expression. |
2791 | token::OpenDelim(token::Bracket) => { | |
9cc50fc6 | 2792 | self.bump(); |
54a0048b | 2793 | let ix = self.parse_expr()?; |
cc61c64b | 2794 | hi = self.span; |
5bcae85e | 2795 | self.expect(&token::CloseDelim(token::Bracket))?; |
c34b1796 | 2796 | let index = self.mk_index(e, ix); |
cc61c64b | 2797 | e = self.mk_expr(lo.to(hi), index, ThinVec::new()) |
1a4d82fc | 2798 | } |
9346a6ac | 2799 | _ => return Ok(e) |
223e47cc LB |
2800 | } |
2801 | } | |
9346a6ac | 2802 | return Ok(e); |
223e47cc LB |
2803 | } |
2804 | ||
94b46f34 | 2805 | crate fn process_potential_macro_variable(&mut self) { |
83c7162d | 2806 | let (token, span) = match self.token { |
ea8adc8c | 2807 | token::Dollar if self.span.ctxt() != syntax_pos::hygiene::SyntaxContext::empty() && |
041b39d2 XL |
2808 | self.look_ahead(1, |t| t.is_ident()) => { |
2809 | self.bump(); | |
0531ce1d XL |
2810 | let name = match self.token { |
2811 | token::Ident(ident, _) => ident, | |
2812 | _ => unreachable!() | |
2813 | }; | |
2814 | let mut err = self.fatal(&format!("unknown macro variable `{}`", name)); | |
2815 | err.span_label(self.span, "unknown macro variable"); | |
2816 | err.emit(); | |
cc61c64b XL |
2817 | return |
2818 | } | |
2819 | token::Interpolated(ref nt) => { | |
2820 | self.meta_var_span = Some(self.span); | |
83c7162d XL |
2821 | // Interpolated identifier and lifetime tokens are replaced with usual identifier |
2822 | // and lifetime tokens, so the former are never encountered during normal parsing. | |
041b39d2 | 2823 | match nt.0 { |
83c7162d XL |
2824 | token::NtIdent(ident, is_raw) => (token::Ident(ident, is_raw), ident.span), |
2825 | token::NtLifetime(ident) => (token::Lifetime(ident), ident.span), | |
cc61c64b XL |
2826 | _ => return, |
2827 | } | |
2828 | } | |
2829 | _ => return, | |
2830 | }; | |
83c7162d XL |
2831 | self.token = token; |
2832 | self.span = span; | |
223e47cc LB |
2833 | } |
2834 | ||
1a4d82fc | 2835 | /// parse a single token tree from the input. |
94b46f34 | 2836 | crate fn parse_token_tree(&mut self) -> TokenTree { |
1a4d82fc | 2837 | match self.token { |
8bb4bdeb XL |
2838 | token::OpenDelim(..) => { |
2839 | let frame = mem::replace(&mut self.token_cursor.frame, | |
2840 | self.token_cursor.stack.pop().unwrap()); | |
b7449926 | 2841 | self.span = frame.span.entire(); |
32a655c1 | 2842 | self.bump(); |
cc61c64b | 2843 | TokenTree::Delimited(frame.span, Delimited { |
8bb4bdeb XL |
2844 | delim: frame.delim, |
2845 | tts: frame.tree_cursor.original_stream().into(), | |
cc61c64b | 2846 | }) |
1a4d82fc | 2847 | }, |
8bb4bdeb XL |
2848 | token::CloseDelim(_) | token::Eof => unreachable!(), |
2849 | _ => { | |
0531ce1d | 2850 | let (token, span) = (mem::replace(&mut self.token, token::Whitespace), self.span); |
8bb4bdeb | 2851 | self.bump(); |
cc61c64b | 2852 | TokenTree::Token(span, token) |
8bb4bdeb | 2853 | } |
1a4d82fc | 2854 | } |
223e47cc LB |
2855 | } |
2856 | ||
1a4d82fc JJ |
2857 | // parse a stream of tokens into a list of TokenTree's, |
2858 | // up to EOF. | |
9cc50fc6 | 2859 | pub fn parse_all_token_trees(&mut self) -> PResult<'a, Vec<TokenTree>> { |
1a4d82fc JJ |
2860 | let mut tts = Vec::new(); |
2861 | while self.token != token::Eof { | |
cc61c64b | 2862 | tts.push(self.parse_token_tree()); |
1a4d82fc | 2863 | } |
9346a6ac | 2864 | Ok(tts) |
223e47cc LB |
2865 | } |
2866 | ||
cc61c64b XL |
2867 | pub fn parse_tokens(&mut self) -> TokenStream { |
2868 | let mut result = Vec::new(); | |
2869 | loop { | |
2870 | match self.token { | |
2871 | token::Eof | token::CloseDelim(..) => break, | |
2872 | _ => result.push(self.parse_token_tree().into()), | |
2873 | } | |
2874 | } | |
2875 | TokenStream::concat(result) | |
2876 | } | |
2877 | ||
92a42be0 | 2878 | /// Parse a prefix-unary-operator expr |
94b46f34 | 2879 | fn parse_prefix_expr(&mut self, |
3157f602 | 2880 | already_parsed_attrs: Option<ThinVec<Attribute>>) |
9cc50fc6 | 2881 | -> PResult<'a, P<Expr>> { |
54a0048b | 2882 | let attrs = self.parse_or_use_outer_attributes(already_parsed_attrs)?; |
cc61c64b | 2883 | let lo = self.span; |
85aaf69f | 2884 | // Note: when adding new unary operators, don't forget to adjust Token::can_begin_expr() |
cc61c64b | 2885 | let (hi, ex) = match self.token { |
92a42be0 | 2886 | token::Not => { |
9cc50fc6 | 2887 | self.bump(); |
7453a54e | 2888 | let e = self.parse_prefix_expr(None); |
54a0048b | 2889 | let (span, e) = self.interpolated_or_expr_span(e)?; |
ea8adc8c | 2890 | (lo.to(span), self.mk_unary(UnOp::Not, e)) |
92a42be0 | 2891 | } |
7cac9316 XL |
2892 | // Suggest `!` for bitwise negation when encountering a `~` |
2893 | token::Tilde => { | |
2894 | self.bump(); | |
2895 | let e = self.parse_prefix_expr(None); | |
2896 | let (span, e) = self.interpolated_or_expr_span(e)?; | |
2897 | let span_of_tilde = lo; | |
0bf4aa26 XL |
2898 | let mut err = self.diagnostic() |
2899 | .struct_span_err(span_of_tilde, "`~` cannot be used as a unary operator"); | |
94b46f34 XL |
2900 | err.span_suggestion_short_with_applicability( |
2901 | span_of_tilde, | |
2902 | "use `!` to perform bitwise negation", | |
2903 | "!".to_owned(), | |
2904 | Applicability::MachineApplicable | |
2905 | ); | |
7cac9316 | 2906 | err.emit(); |
ea8adc8c | 2907 | (lo.to(span), self.mk_unary(UnOp::Not, e)) |
7cac9316 | 2908 | } |
92a42be0 | 2909 | token::BinOp(token::Minus) => { |
9cc50fc6 | 2910 | self.bump(); |
7453a54e | 2911 | let e = self.parse_prefix_expr(None); |
54a0048b | 2912 | let (span, e) = self.interpolated_or_expr_span(e)?; |
ea8adc8c | 2913 | (lo.to(span), self.mk_unary(UnOp::Neg, e)) |
92a42be0 SL |
2914 | } |
2915 | token::BinOp(token::Star) => { | |
9cc50fc6 | 2916 | self.bump(); |
7453a54e | 2917 | let e = self.parse_prefix_expr(None); |
54a0048b | 2918 | let (span, e) = self.interpolated_or_expr_span(e)?; |
ea8adc8c | 2919 | (lo.to(span), self.mk_unary(UnOp::Deref, e)) |
92a42be0 SL |
2920 | } |
2921 | token::BinOp(token::And) | token::AndAnd => { | |
54a0048b | 2922 | self.expect_and()?; |
cc61c64b | 2923 | let m = self.parse_mutability(); |
7453a54e | 2924 | let e = self.parse_prefix_expr(None); |
54a0048b | 2925 | let (span, e) = self.interpolated_or_expr_span(e)?; |
ea8adc8c | 2926 | (lo.to(span), ExprKind::AddrOf(m, e)) |
92a42be0 SL |
2927 | } |
2928 | token::Ident(..) if self.token.is_keyword(keywords::In) => { | |
9cc50fc6 | 2929 | self.bump(); |
54a0048b | 2930 | let place = self.parse_expr_res( |
ea8adc8c | 2931 | Restrictions::NO_STRUCT_LITERAL, |
92a42be0 | 2932 | None, |
54a0048b SL |
2933 | )?; |
2934 | let blk = self.parse_block()?; | |
92a42be0 | 2935 | let span = blk.span; |
94b46f34 | 2936 | let blk_expr = self.mk_expr(span, ExprKind::Block(blk, None), ThinVec::new()); |
83c7162d | 2937 | (lo.to(span), ExprKind::ObsoleteInPlace(place, blk_expr)) |
92a42be0 SL |
2938 | } |
2939 | token::Ident(..) if self.token.is_keyword(keywords::Box) => { | |
9cc50fc6 | 2940 | self.bump(); |
7453a54e | 2941 | let e = self.parse_prefix_expr(None); |
54a0048b | 2942 | let (span, e) = self.interpolated_or_expr_span(e)?; |
ea8adc8c | 2943 | (lo.to(span), ExprKind::Box(e)) |
92a42be0 | 2944 | } |
83c7162d XL |
2945 | token::Ident(..) if self.token.is_ident_named("not") => { |
2946 | // `not` is just an ordinary identifier in Rust-the-language, | |
2947 | // but as `rustc`-the-compiler, we can issue clever diagnostics | |
2948 | // for confused users who really want to say `!` | |
2949 | let token_cannot_continue_expr = |t: &token::Token| match *t { | |
2950 | // These tokens can start an expression after `!`, but | |
2951 | // can't continue an expression after an ident | |
2952 | token::Ident(ident, is_raw) => token::ident_can_begin_expr(ident, is_raw), | |
2953 | token::Literal(..) | token::Pound => true, | |
2954 | token::Interpolated(ref nt) => match nt.0 { | |
2955 | token::NtIdent(..) | token::NtExpr(..) | | |
2956 | token::NtBlock(..) | token::NtPath(..) => true, | |
2957 | _ => false, | |
2958 | }, | |
2959 | _ => false | |
2960 | }; | |
2961 | let cannot_continue_expr = self.look_ahead(1, token_cannot_continue_expr); | |
2962 | if cannot_continue_expr { | |
2963 | self.bump(); | |
2964 | // Emit the error ... | |
2965 | let mut err = self.diagnostic() | |
2966 | .struct_span_err(self.span, | |
2967 | &format!("unexpected {} after identifier", | |
2968 | self.this_token_descr())); | |
2969 | // span the `not` plus trailing whitespace to avoid | |
2970 | // trailing whitespace after the `!` in our suggestion | |
b7449926 | 2971 | let to_replace = self.sess.source_map() |
83c7162d | 2972 | .span_until_non_whitespace(lo.to(self.span)); |
94b46f34 XL |
2973 | err.span_suggestion_short_with_applicability( |
2974 | to_replace, | |
2975 | "use `!` to perform logical negation", | |
2976 | "!".to_owned(), | |
2977 | Applicability::MachineApplicable | |
2978 | ); | |
83c7162d XL |
2979 | err.emit(); |
2980 | // —and recover! (just as if we were in the block | |
2981 | // for the `token::Not` arm) | |
2982 | let e = self.parse_prefix_expr(None); | |
2983 | let (span, e) = self.interpolated_or_expr_span(e)?; | |
2984 | (lo.to(span), self.mk_unary(UnOp::Not, e)) | |
2985 | } else { | |
2986 | return self.parse_dot_or_call_expr(Some(attrs)); | |
2987 | } | |
2988 | } | |
2989 | _ => { return self.parse_dot_or_call_expr(Some(attrs)); } | |
92a42be0 | 2990 | }; |
cc61c64b | 2991 | return Ok(self.mk_expr(lo.to(hi), ex, attrs)); |
223e47cc LB |
2992 | } |
2993 | ||
92a42be0 SL |
2994 | /// Parse an associative expression |
2995 | /// | |
2996 | /// This parses an expression accounting for associativity and precedence of the operators in | |
2997 | /// the expression. | |
94b46f34 | 2998 | fn parse_assoc_expr(&mut self, |
3157f602 | 2999 | already_parsed_attrs: Option<ThinVec<Attribute>>) |
9cc50fc6 | 3000 | -> PResult<'a, P<Expr>> { |
92a42be0 | 3001 | self.parse_assoc_expr_with(0, already_parsed_attrs.into()) |
223e47cc LB |
3002 | } |
3003 | ||
92a42be0 | 3004 | /// Parse an associative expression with operators of at least `min_prec` precedence |
94b46f34 | 3005 | fn parse_assoc_expr_with(&mut self, |
92a42be0 SL |
3006 | min_prec: usize, |
3007 | lhs: LhsExpr) | |
9cc50fc6 | 3008 | -> PResult<'a, P<Expr>> { |
92a42be0 SL |
3009 | let mut lhs = if let LhsExpr::AlreadyParsed(expr) = lhs { |
3010 | expr | |
3011 | } else { | |
3012 | let attrs = match lhs { | |
3013 | LhsExpr::AttributesParsed(attrs) => Some(attrs), | |
3014 | _ => None, | |
3015 | }; | |
ea8adc8c | 3016 | if [token::DotDot, token::DotDotDot, token::DotDotEq].contains(&self.token) { |
92a42be0 SL |
3017 | return self.parse_prefix_range_expr(attrs); |
3018 | } else { | |
54a0048b | 3019 | self.parse_prefix_expr(attrs)? |
92a42be0 SL |
3020 | } |
3021 | }; | |
7453a54e | 3022 | |
7453a54e | 3023 | if self.expr_is_complete(&lhs) { |
92a42be0 SL |
3024 | // Semi-statement forms are odd. See https://github.com/rust-lang/rust/issues/29071 |
3025 | return Ok(lhs); | |
3026 | } | |
1a4d82fc | 3027 | self.expected_tokens.push(TokenType::Operator); |
92a42be0 | 3028 | while let Some(op) = AssocOp::from_token(&self.token) { |
7453a54e | 3029 | |
041b39d2 XL |
3030 | // Adjust the span for interpolated LHS to point to the `$lhs` token and not to what |
3031 | // it refers to. Interpolated identifiers are unwrapped early and never show up here | |
3032 | // as `PrevTokenKind::Interpolated` so if LHS is a single identifier we always process | |
3033 | // it as "interpolated", it doesn't change the answer for non-interpolated idents. | |
3034 | let lhs_span = match (self.prev_token_kind, &lhs.node) { | |
3035 | (PrevTokenKind::Interpolated, _) => self.prev_span, | |
3036 | (PrevTokenKind::Ident, &ExprKind::Path(None, ref path)) | |
3037 | if path.segments.len() == 1 => self.prev_span, | |
3038 | _ => lhs.span, | |
7453a54e SL |
3039 | }; |
3040 | ||
92a42be0 SL |
3041 | let cur_op_span = self.span; |
3042 | let restrictions = if op.is_assign_like() { | |
ea8adc8c | 3043 | self.restrictions & Restrictions::NO_STRUCT_LITERAL |
92a42be0 SL |
3044 | } else { |
3045 | self.restrictions | |
3046 | }; | |
3047 | if op.precedence() < min_prec { | |
3048 | break; | |
3049 | } | |
abe05a73 XL |
3050 | // Check for deprecated `...` syntax |
3051 | if self.token == token::DotDotDot && op == AssocOp::DotDotEq { | |
3052 | self.err_dotdotdot_syntax(self.span); | |
ea8adc8c | 3053 | } |
abe05a73 | 3054 | |
9cc50fc6 | 3055 | self.bump(); |
92a42be0 | 3056 | if op.is_comparison() { |
7453a54e | 3057 | self.check_no_chained_comparison(&lhs, &op); |
92a42be0 SL |
3058 | } |
3059 | // Special cases: | |
3060 | if op == AssocOp::As { | |
041b39d2 | 3061 | lhs = self.parse_assoc_op_cast(lhs, lhs_span, ExprKind::Cast)?; |
92a42be0 | 3062 | continue |
9cc50fc6 | 3063 | } else if op == AssocOp::Colon { |
3b2f2976 XL |
3064 | lhs = match self.parse_assoc_op_cast(lhs, lhs_span, ExprKind::Type) { |
3065 | Ok(lhs) => lhs, | |
3066 | Err(mut err) => { | |
3067 | err.span_label(self.span, | |
3068 | "expecting a type here because of type ascription"); | |
b7449926 | 3069 | let cm = self.sess.source_map(); |
ea8adc8c XL |
3070 | let cur_pos = cm.lookup_char_pos(self.span.lo()); |
3071 | let op_pos = cm.lookup_char_pos(cur_op_span.hi()); | |
3b2f2976 | 3072 | if cur_pos.line != op_pos.line { |
94b46f34 XL |
3073 | err.span_suggestion_with_applicability( |
3074 | cur_op_span, | |
3075 | "try using a semicolon", | |
3076 | ";".to_string(), | |
3077 | Applicability::MaybeIncorrect // speculative | |
3078 | ); | |
3b2f2976 XL |
3079 | } |
3080 | return Err(err); | |
3081 | } | |
3082 | }; | |
9cc50fc6 | 3083 | continue |
ea8adc8c XL |
3084 | } else if op == AssocOp::DotDot || op == AssocOp::DotDotEq { |
3085 | // If we didn’t have to handle `x..`/`x..=`, it would be pretty easy to | |
54a0048b SL |
3086 | // generalise it to the Fixity::None code. |
3087 | // | |
ea8adc8c | 3088 | // We have 2 alternatives here: `x..y`/`x..=y` and `x..`/`x..=` The other |
54a0048b SL |
3089 | // two variants are handled with `parse_prefix_range_expr` call above. |
3090 | let rhs = if self.is_at_start_of_range_notation_rhs() { | |
a7813a04 XL |
3091 | Some(self.parse_assoc_expr_with(op.precedence() + 1, |
3092 | LhsExpr::NotYetParsed)?) | |
54a0048b SL |
3093 | } else { |
3094 | None | |
3095 | }; | |
3096 | let (lhs_span, rhs_span) = (lhs.span, if let Some(ref x) = rhs { | |
3097 | x.span | |
3098 | } else { | |
3099 | cur_op_span | |
3100 | }); | |
3101 | let limits = if op == AssocOp::DotDot { | |
3102 | RangeLimits::HalfOpen | |
3103 | } else { | |
3104 | RangeLimits::Closed | |
3105 | }; | |
3106 | ||
3107 | let r = try!(self.mk_range(Some(lhs), rhs, limits)); | |
cc61c64b | 3108 | lhs = self.mk_expr(lhs_span.to(rhs_span), r, ThinVec::new()); |
54a0048b | 3109 | break |
92a42be0 | 3110 | } |
1a4d82fc | 3111 | |
54a0048b | 3112 | let rhs = match op.fixity() { |
9cc50fc6 | 3113 | Fixity::Right => self.with_res( |
ea8adc8c | 3114 | restrictions - Restrictions::STMT_EXPR, |
9cc50fc6 SL |
3115 | |this| { |
3116 | this.parse_assoc_expr_with(op.precedence(), | |
3117 | LhsExpr::NotYetParsed) | |
92a42be0 | 3118 | }), |
9cc50fc6 | 3119 | Fixity::Left => self.with_res( |
ea8adc8c | 3120 | restrictions - Restrictions::STMT_EXPR, |
9cc50fc6 SL |
3121 | |this| { |
3122 | this.parse_assoc_expr_with(op.precedence() + 1, | |
3123 | LhsExpr::NotYetParsed) | |
92a42be0 SL |
3124 | }), |
3125 | // We currently have no non-associative operators that are not handled above by | |
3126 | // the special cases. The code is here only for future convenience. | |
9cc50fc6 | 3127 | Fixity::None => self.with_res( |
ea8adc8c | 3128 | restrictions - Restrictions::STMT_EXPR, |
9cc50fc6 SL |
3129 | |this| { |
3130 | this.parse_assoc_expr_with(op.precedence() + 1, | |
3131 | LhsExpr::NotYetParsed) | |
92a42be0 | 3132 | }), |
54a0048b | 3133 | }?; |
92a42be0 | 3134 | |
cc61c64b | 3135 | let span = lhs_span.to(rhs.span); |
92a42be0 SL |
3136 | lhs = match op { |
3137 | AssocOp::Add | AssocOp::Subtract | AssocOp::Multiply | AssocOp::Divide | | |
3138 | AssocOp::Modulus | AssocOp::LAnd | AssocOp::LOr | AssocOp::BitXor | | |
3139 | AssocOp::BitAnd | AssocOp::BitOr | AssocOp::ShiftLeft | AssocOp::ShiftRight | | |
3140 | AssocOp::Equal | AssocOp::Less | AssocOp::LessEqual | AssocOp::NotEqual | | |
3141 | AssocOp::Greater | AssocOp::GreaterEqual => { | |
3142 | let ast_op = op.to_ast_binop().unwrap(); | |
b7449926 | 3143 | let binary = self.mk_binary(source_map::respan(cur_op_span, ast_op), lhs, rhs); |
cc61c64b | 3144 | self.mk_expr(span, binary, ThinVec::new()) |
1a4d82fc | 3145 | } |
92a42be0 | 3146 | AssocOp::Assign => |
cc61c64b | 3147 | self.mk_expr(span, ExprKind::Assign(lhs, rhs), ThinVec::new()), |
83c7162d XL |
3148 | AssocOp::ObsoleteInPlace => |
3149 | self.mk_expr(span, ExprKind::ObsoleteInPlace(lhs, rhs), ThinVec::new()), | |
92a42be0 SL |
3150 | AssocOp::AssignOp(k) => { |
3151 | let aop = match k { | |
7453a54e SL |
3152 | token::Plus => BinOpKind::Add, |
3153 | token::Minus => BinOpKind::Sub, | |
3154 | token::Star => BinOpKind::Mul, | |
3155 | token::Slash => BinOpKind::Div, | |
3156 | token::Percent => BinOpKind::Rem, | |
3157 | token::Caret => BinOpKind::BitXor, | |
3158 | token::And => BinOpKind::BitAnd, | |
3159 | token::Or => BinOpKind::BitOr, | |
3160 | token::Shl => BinOpKind::Shl, | |
3161 | token::Shr => BinOpKind::Shr, | |
92a42be0 | 3162 | }; |
b7449926 | 3163 | let aopexpr = self.mk_assign_op(source_map::respan(cur_op_span, aop), lhs, rhs); |
cc61c64b | 3164 | self.mk_expr(span, aopexpr, ThinVec::new()) |
223e47cc | 3165 | } |
ea8adc8c XL |
3166 | AssocOp::As | AssocOp::Colon | AssocOp::DotDot | AssocOp::DotDotEq => { |
3167 | self.bug("AssocOp should have been handled by special case") | |
9cc50fc6 | 3168 | } |
92a42be0 SL |
3169 | }; |
3170 | ||
3171 | if op.fixity() == Fixity::None { break } | |
223e47cc | 3172 | } |
92a42be0 | 3173 | Ok(lhs) |
223e47cc LB |
3174 | } |
3175 | ||
041b39d2 XL |
3176 | fn parse_assoc_op_cast(&mut self, lhs: P<Expr>, lhs_span: Span, |
3177 | expr_kind: fn(P<Expr>, P<Ty>) -> ExprKind) | |
3178 | -> PResult<'a, P<Expr>> { | |
3179 | let mk_expr = |this: &mut Self, rhs: P<Ty>| { | |
3180 | this.mk_expr(lhs_span.to(rhs.span), expr_kind(lhs, rhs), ThinVec::new()) | |
3181 | }; | |
3182 | ||
3183 | // Save the state of the parser before parsing type normally, in case there is a | |
3184 | // LessThan comparison after this cast. | |
3185 | let parser_snapshot_before_type = self.clone(); | |
3186 | match self.parse_ty_no_plus() { | |
3187 | Ok(rhs) => { | |
3188 | Ok(mk_expr(self, rhs)) | |
3189 | } | |
3190 | Err(mut type_err) => { | |
3191 | // Rewind to before attempting to parse the type with generics, to recover | |
3192 | // from situations like `x as usize < y` in which we first tried to parse | |
3193 | // `usize < y` as a type with generic arguments. | |
3194 | let parser_snapshot_after_type = self.clone(); | |
3195 | mem::replace(self, parser_snapshot_before_type); | |
3196 | ||
3b2f2976 | 3197 | match self.parse_path(PathStyle::Expr) { |
041b39d2 | 3198 | Ok(path) => { |
abe05a73 XL |
3199 | let (op_noun, op_verb) = match self.token { |
3200 | token::Lt => ("comparison", "comparing"), | |
3201 | token::BinOp(token::Shl) => ("shift", "shifting"), | |
3202 | _ => { | |
3203 | // We can end up here even without `<` being the next token, for | |
3204 | // example because `parse_ty_no_plus` returns `Err` on keywords, | |
3205 | // but `parse_path` returns `Ok` on them due to error recovery. | |
3206 | // Return original error and parser state. | |
3207 | mem::replace(self, parser_snapshot_after_type); | |
3208 | return Err(type_err); | |
3209 | } | |
3210 | }; | |
3211 | ||
041b39d2 XL |
3212 | // Successfully parsed the type path leaving a `<` yet to parse. |
3213 | type_err.cancel(); | |
3214 | ||
3215 | // Report non-fatal diagnostics, keep `x as usize` as an expression | |
3216 | // in AST and continue parsing. | |
3217 | let msg = format!("`<` is interpreted as a start of generic \ | |
abe05a73 | 3218 | arguments for `{}`, not a {}", path, op_noun); |
041b39d2 XL |
3219 | let mut err = self.sess.span_diagnostic.struct_span_err(self.span, &msg); |
3220 | err.span_label(self.look_ahead_span(1).to(parser_snapshot_after_type.span), | |
3221 | "interpreted as generic arguments"); | |
abe05a73 | 3222 | err.span_label(self.span, format!("not interpreted as {}", op_noun)); |
041b39d2 XL |
3223 | |
3224 | let expr = mk_expr(self, P(Ty { | |
3225 | span: path.span, | |
3226 | node: TyKind::Path(None, path), | |
3227 | id: ast::DUMMY_NODE_ID | |
3228 | })); | |
3229 | ||
b7449926 | 3230 | let expr_str = self.sess.source_map().span_to_snippet(expr.span) |
0bf4aa26 | 3231 | .unwrap_or_else(|_| pprust::expr_to_string(&expr)); |
94b46f34 XL |
3232 | err.span_suggestion_with_applicability( |
3233 | expr.span, | |
3234 | &format!("try {} the cast value", op_verb), | |
3235 | format!("({})", expr_str), | |
3236 | Applicability::MachineApplicable | |
3237 | ); | |
041b39d2 XL |
3238 | err.emit(); |
3239 | ||
3240 | Ok(expr) | |
3241 | } | |
3242 | Err(mut path_err) => { | |
3243 | // Couldn't parse as a path, return original error and parser state. | |
3244 | path_err.cancel(); | |
3245 | mem::replace(self, parser_snapshot_after_type); | |
3246 | Err(type_err) | |
3247 | } | |
3248 | } | |
3249 | } | |
3250 | } | |
3251 | } | |
3252 | ||
1a4d82fc JJ |
3253 | /// Produce an error if comparison operators are chained (RFC #558). |
3254 | /// We only need to check lhs, not rhs, because all comparison ops | |
3255 | /// have same precedence and are left-associative | |
92a42be0 | 3256 | fn check_no_chained_comparison(&mut self, lhs: &Expr, outer_op: &AssocOp) { |
041b39d2 XL |
3257 | debug_assert!(outer_op.is_comparison(), |
3258 | "check_no_chained_comparison: {:?} is not comparison", | |
3259 | outer_op); | |
1a4d82fc | 3260 | match lhs.node { |
7453a54e | 3261 | ExprKind::Binary(op, _, _) if op.node.is_comparison() => { |
85aaf69f | 3262 | // respan to include both operators |
cc61c64b | 3263 | let op_span = op.span.to(self.span); |
9cc50fc6 | 3264 | let mut err = self.diagnostic().struct_span_err(op_span, |
85aaf69f | 3265 | "chained comparison operators require parentheses"); |
cc61c64b XL |
3266 | if op.node == BinOpKind::Lt && |
3267 | *outer_op == AssocOp::Less || // Include `<` to provide this recommendation | |
3268 | *outer_op == AssocOp::Greater // even in a case like the following: | |
3269 | { // Foo<Bar<Baz<Qux, ()>>> | |
a7813a04 | 3270 | err.help( |
85aaf69f | 3271 | "use `::<...>` instead of `<...>` if you meant to specify type arguments"); |
abe05a73 | 3272 | err.help("or use `(...)` if you meant to specify fn arguments"); |
1a4d82fc | 3273 | } |
9cc50fc6 | 3274 | err.emit(); |
1a4d82fc JJ |
3275 | } |
3276 | _ => {} | |
3277 | } | |
3278 | } | |
3279 | ||
abe05a73 | 3280 | /// Parse prefix-forms of range notation: `..expr`, `..`, `..=expr` |
92a42be0 | 3281 | fn parse_prefix_range_expr(&mut self, |
3157f602 | 3282 | already_parsed_attrs: Option<ThinVec<Attribute>>) |
9cc50fc6 | 3283 | -> PResult<'a, P<Expr>> { |
abe05a73 XL |
3284 | // Check for deprecated `...` syntax |
3285 | if self.token == token::DotDotDot { | |
3286 | self.err_dotdotdot_syntax(self.span); | |
3287 | } | |
3288 | ||
ea8adc8c | 3289 | debug_assert!([token::DotDot, token::DotDotDot, token::DotDotEq].contains(&self.token), |
abe05a73 | 3290 | "parse_prefix_range_expr: token {:?} is not DotDot/DotDotEq", |
041b39d2 | 3291 | self.token); |
54a0048b SL |
3292 | let tok = self.token.clone(); |
3293 | let attrs = self.parse_or_use_outer_attributes(already_parsed_attrs)?; | |
cc61c64b XL |
3294 | let lo = self.span; |
3295 | let mut hi = self.span; | |
9cc50fc6 | 3296 | self.bump(); |
92a42be0 | 3297 | let opt_end = if self.is_at_start_of_range_notation_rhs() { |
54a0048b SL |
3298 | // RHS must be parsed with more associativity than the dots. |
3299 | let next_prec = AssocOp::from_token(&tok).unwrap().precedence() + 1; | |
3300 | Some(self.parse_assoc_expr_with(next_prec, | |
3301 | LhsExpr::NotYetParsed) | |
3302 | .map(|x|{ | |
cc61c64b | 3303 | hi = x.span; |
54a0048b SL |
3304 | x |
3305 | })?) | |
92a42be0 SL |
3306 | } else { |
3307 | None | |
3308 | }; | |
54a0048b SL |
3309 | let limits = if tok == token::DotDot { |
3310 | RangeLimits::HalfOpen | |
3311 | } else { | |
3312 | RangeLimits::Closed | |
3313 | }; | |
3314 | ||
3315 | let r = try!(self.mk_range(None, | |
3316 | opt_end, | |
3317 | limits)); | |
cc61c64b | 3318 | Ok(self.mk_expr(lo.to(hi), r, attrs)) |
223e47cc LB |
3319 | } |
3320 | ||
85aaf69f SL |
3321 | fn is_at_start_of_range_notation_rhs(&self) -> bool { |
3322 | if self.token.can_begin_expr() { | |
3323 | // parse `for i in 1.. { }` as infinite loop, not as `for i in (1..{})`. | |
3324 | if self.token == token::OpenDelim(token::Brace) { | |
ea8adc8c | 3325 | return !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL); |
85aaf69f SL |
3326 | } |
3327 | true | |
3328 | } else { | |
3329 | false | |
3330 | } | |
3331 | } | |
3332 | ||
1a4d82fc | 3333 | /// Parse an 'if' or 'if let' expression ('if' token already eaten) |
94b46f34 | 3334 | fn parse_if_expr(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { |
85aaf69f | 3335 | if self.check_keyword(keywords::Let) { |
92a42be0 | 3336 | return self.parse_if_let_expr(attrs); |
1a4d82fc | 3337 | } |
cc61c64b | 3338 | let lo = self.prev_span; |
ea8adc8c | 3339 | let cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?; |
3b2f2976 XL |
3340 | |
3341 | // Verify that the parsed `if` condition makes sense as a condition. If it is a block, then | |
3342 | // verify that the last statement is either an implicit return (no `;`) or an explicit | |
3343 | // return. This won't catch blocks with an explicit `return`, but that would be caught by | |
3344 | // the dead code lint. | |
3345 | if self.eat_keyword(keywords::Else) || !cond.returns() { | |
b7449926 | 3346 | let sp = self.sess.source_map().next_point(lo); |
3b2f2976 XL |
3347 | let mut err = self.diagnostic() |
3348 | .struct_span_err(sp, "missing condition for `if` statemement"); | |
3349 | err.span_label(sp, "expected if condition here"); | |
3350 | return Err(err) | |
3351 | } | |
0531ce1d XL |
3352 | let not_block = self.token != token::OpenDelim(token::Brace); |
3353 | let thn = self.parse_block().map_err(|mut err| { | |
3354 | if not_block { | |
3355 | err.span_label(lo, "this `if` statement has a condition, but no block"); | |
3356 | } | |
3357 | err | |
3358 | })?; | |
1a4d82fc | 3359 | let mut els: Option<P<Expr>> = None; |
cc61c64b | 3360 | let mut hi = thn.span; |
9cc50fc6 | 3361 | if self.eat_keyword(keywords::Else) { |
54a0048b | 3362 | let elexpr = self.parse_else_expr()?; |
cc61c64b | 3363 | hi = elexpr.span; |
1a4d82fc | 3364 | els = Some(elexpr); |
223e47cc | 3365 | } |
cc61c64b | 3366 | Ok(self.mk_expr(lo.to(hi), ExprKind::If(cond, thn, els), attrs)) |
223e47cc LB |
3367 | } |
3368 | ||
1a4d82fc | 3369 | /// Parse an 'if let' expression ('if' token already eaten) |
94b46f34 | 3370 | fn parse_if_let_expr(&mut self, attrs: ThinVec<Attribute>) |
9cc50fc6 | 3371 | -> PResult<'a, P<Expr>> { |
cc61c64b | 3372 | let lo = self.prev_span; |
54a0048b | 3373 | self.expect_keyword(keywords::Let)?; |
0531ce1d | 3374 | let pats = self.parse_pats()?; |
54a0048b | 3375 | self.expect(&token::Eq)?; |
ea8adc8c | 3376 | let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?; |
54a0048b | 3377 | let thn = self.parse_block()?; |
9cc50fc6 | 3378 | let (hi, els) = if self.eat_keyword(keywords::Else) { |
54a0048b | 3379 | let expr = self.parse_else_expr()?; |
cc61c64b | 3380 | (expr.span, Some(expr)) |
1a4d82fc | 3381 | } else { |
cc61c64b | 3382 | (thn.span, None) |
1a4d82fc | 3383 | }; |
0531ce1d | 3384 | Ok(self.mk_expr(lo.to(hi), ExprKind::IfLet(pats, expr, thn, els), attrs)) |
223e47cc LB |
3385 | } |
3386 | ||
a7813a04 | 3387 | // `move |args| expr` |
94b46f34 | 3388 | fn parse_lambda_expr(&mut self, |
3157f602 | 3389 | attrs: ThinVec<Attribute>) |
9cc50fc6 | 3390 | -> PResult<'a, P<Expr>> |
1a4d82fc | 3391 | { |
2c00a5a8 XL |
3392 | let lo = self.span; |
3393 | let movability = if self.eat_keyword(keywords::Static) { | |
3394 | Movability::Static | |
3395 | } else { | |
3396 | Movability::Movable | |
3397 | }; | |
8faf50e0 XL |
3398 | let asyncness = if self.span.edition() >= Edition::Edition2018 { |
3399 | self.parse_asyncness() | |
3400 | } else { | |
3401 | IsAsync::NotAsync | |
3402 | }; | |
2c00a5a8 XL |
3403 | let capture_clause = if self.eat_keyword(keywords::Move) { |
3404 | CaptureBy::Value | |
3405 | } else { | |
3406 | CaptureBy::Ref | |
3407 | }; | |
54a0048b | 3408 | let decl = self.parse_fn_block_decl()?; |
cc61c64b | 3409 | let decl_hi = self.prev_span; |
c34b1796 | 3410 | let body = match decl.output { |
ea8adc8c XL |
3411 | FunctionRetTy::Default(_) => { |
3412 | let restrictions = self.restrictions - Restrictions::STMT_EXPR; | |
3413 | self.parse_expr_res(restrictions, None)? | |
3414 | }, | |
c34b1796 AL |
3415 | _ => { |
3416 | // If an explicit return type is given, require a | |
3417 | // block to appear (RFC 968). | |
cc61c64b | 3418 | let body_lo = self.span; |
94b46f34 | 3419 | self.parse_block_expr(None, body_lo, BlockCheckMode::Default, ThinVec::new())? |
c34b1796 AL |
3420 | } |
3421 | }; | |
1a4d82fc | 3422 | |
9346a6ac | 3423 | Ok(self.mk_expr( |
cc61c64b | 3424 | lo.to(body.span), |
8faf50e0 | 3425 | ExprKind::Closure(capture_clause, asyncness, movability, decl, body, lo.to(decl_hi)), |
a7813a04 | 3426 | attrs)) |
223e47cc LB |
3427 | } |
3428 | ||
92a42be0 | 3429 | // `else` token already eaten |
94b46f34 | 3430 | fn parse_else_expr(&mut self) -> PResult<'a, P<Expr>> { |
9cc50fc6 | 3431 | if self.eat_keyword(keywords::If) { |
3157f602 | 3432 | return self.parse_if_expr(ThinVec::new()); |
223e47cc | 3433 | } else { |
54a0048b | 3434 | let blk = self.parse_block()?; |
94b46f34 | 3435 | return Ok(self.mk_expr(blk.span, ExprKind::Block(blk, None), ThinVec::new())); |
223e47cc LB |
3436 | } |
3437 | } | |
3438 | ||
1a4d82fc | 3439 | /// Parse a 'for' .. 'in' expression ('for' token already eaten) |
94b46f34 | 3440 | fn parse_for_expr(&mut self, opt_label: Option<Label>, |
cc61c64b | 3441 | span_lo: Span, |
3157f602 | 3442 | mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { |
1a4d82fc JJ |
3443 | // Parse: `for <src_pat> in <src_expr> <src_loop_block>` |
3444 | ||
0531ce1d | 3445 | let pat = self.parse_top_level_pat()?; |
abe05a73 XL |
3446 | if !self.eat_keyword(keywords::In) { |
3447 | let in_span = self.prev_span.between(self.span); | |
3448 | let mut err = self.sess.span_diagnostic | |
3449 | .struct_span_err(in_span, "missing `in` in `for` loop"); | |
94b46f34 XL |
3450 | err.span_suggestion_short_with_applicability( |
3451 | in_span, "try adding `in` here", " in ".into(), | |
3452 | // has been misleading, at least in the past (closed Issue #48492) | |
3453 | Applicability::MaybeIncorrect | |
3454 | ); | |
abe05a73 XL |
3455 | err.emit(); |
3456 | } | |
0bf4aa26 XL |
3457 | let in_span = self.prev_span; |
3458 | if self.eat_keyword(keywords::In) { | |
3459 | // a common typo: `for _ in in bar {}` | |
3460 | let mut err = self.sess.span_diagnostic.struct_span_err( | |
3461 | self.prev_span, | |
3462 | "expected iterable, found keyword `in`", | |
3463 | ); | |
3464 | err.span_suggestion_short_with_applicability( | |
3465 | in_span.until(self.prev_span), | |
3466 | "remove the duplicated `in`", | |
3467 | String::new(), | |
3468 | Applicability::MachineApplicable, | |
3469 | ); | |
3470 | err.note("if you meant to use emplacement syntax, it is obsolete (for now, anyway)"); | |
3471 | err.note("for more information on the status of emplacement syntax, see <\ | |
3472 | https://github.com/rust-lang/rust/issues/27779#issuecomment-378416911>"); | |
3473 | err.emit(); | |
3474 | } | |
ea8adc8c | 3475 | let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?; |
54a0048b | 3476 | let (iattrs, loop_block) = self.parse_inner_attrs_and_block()?; |
3157f602 | 3477 | attrs.extend(iattrs); |
92a42be0 | 3478 | |
cc61c64b | 3479 | let hi = self.prev_span; |
2c00a5a8 | 3480 | Ok(self.mk_expr(span_lo.to(hi), ExprKind::ForLoop(pat, expr, loop_block, opt_label), attrs)) |
223e47cc LB |
3481 | } |
3482 | ||
1a4d82fc | 3483 | /// Parse a 'while' or 'while let' expression ('while' token already eaten) |
94b46f34 | 3484 | fn parse_while_expr(&mut self, opt_label: Option<Label>, |
cc61c64b | 3485 | span_lo: Span, |
3157f602 | 3486 | mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { |
1a4d82fc | 3487 | if self.token.is_keyword(keywords::Let) { |
2c00a5a8 | 3488 | return self.parse_while_let_expr(opt_label, span_lo, attrs); |
1a4d82fc | 3489 | } |
ea8adc8c | 3490 | let cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?; |
54a0048b | 3491 | let (iattrs, body) = self.parse_inner_attrs_and_block()?; |
3157f602 | 3492 | attrs.extend(iattrs); |
cc61c64b | 3493 | let span = span_lo.to(body.span); |
2c00a5a8 | 3494 | return Ok(self.mk_expr(span, ExprKind::While(cond, body, opt_label), attrs)); |
223e47cc LB |
3495 | } |
3496 | ||
1a4d82fc | 3497 | /// Parse a 'while let' expression ('while' token already eaten) |
94b46f34 | 3498 | fn parse_while_let_expr(&mut self, opt_label: Option<Label>, |
cc61c64b | 3499 | span_lo: Span, |
3157f602 | 3500 | mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { |
54a0048b | 3501 | self.expect_keyword(keywords::Let)?; |
0531ce1d | 3502 | let pats = self.parse_pats()?; |
54a0048b | 3503 | self.expect(&token::Eq)?; |
ea8adc8c | 3504 | let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?; |
54a0048b | 3505 | let (iattrs, body) = self.parse_inner_attrs_and_block()?; |
3157f602 | 3506 | attrs.extend(iattrs); |
cc61c64b | 3507 | let span = span_lo.to(body.span); |
0531ce1d | 3508 | return Ok(self.mk_expr(span, ExprKind::WhileLet(pats, expr, body, opt_label), attrs)); |
1a4d82fc | 3509 | } |
223e47cc | 3510 | |
92a42be0 | 3511 | // parse `loop {...}`, `loop` token already eaten |
94b46f34 | 3512 | fn parse_loop_expr(&mut self, opt_label: Option<Label>, |
cc61c64b | 3513 | span_lo: Span, |
3157f602 | 3514 | mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { |
54a0048b | 3515 | let (iattrs, body) = self.parse_inner_attrs_and_block()?; |
3157f602 | 3516 | attrs.extend(iattrs); |
cc61c64b | 3517 | let span = span_lo.to(body.span); |
2c00a5a8 | 3518 | Ok(self.mk_expr(span, ExprKind::Loop(body, opt_label), attrs)) |
cc61c64b XL |
3519 | } |
3520 | ||
8faf50e0 XL |
3521 | /// Parse an `async move {...}` expression |
3522 | pub fn parse_async_block(&mut self, mut attrs: ThinVec<Attribute>) | |
3523 | -> PResult<'a, P<Expr>> | |
3524 | { | |
3525 | let span_lo = self.span; | |
3526 | self.expect_keyword(keywords::Async)?; | |
3527 | let capture_clause = if self.eat_keyword(keywords::Move) { | |
3528 | CaptureBy::Value | |
3529 | } else { | |
3530 | CaptureBy::Ref | |
3531 | }; | |
3532 | let (iattrs, body) = self.parse_inner_attrs_and_block()?; | |
3533 | attrs.extend(iattrs); | |
3534 | Ok(self.mk_expr( | |
3535 | span_lo.to(body.span), | |
3536 | ExprKind::Async(capture_clause, ast::DUMMY_NODE_ID, body), attrs)) | |
3537 | } | |
3538 | ||
b7449926 XL |
3539 | /// Parse a `try {...}` expression (`try` token already eaten) |
3540 | fn parse_try_block(&mut self, span_lo: Span, mut attrs: ThinVec<Attribute>) | |
cc61c64b XL |
3541 | -> PResult<'a, P<Expr>> |
3542 | { | |
3543 | let (iattrs, body) = self.parse_inner_attrs_and_block()?; | |
3544 | attrs.extend(iattrs); | |
b7449926 | 3545 | Ok(self.mk_expr(span_lo.to(body.span), ExprKind::TryBlock(body), attrs)) |
1a4d82fc | 3546 | } |
223e47cc | 3547 | |
92a42be0 | 3548 | // `match` token already eaten |
3157f602 | 3549 | fn parse_match_expr(&mut self, mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { |
c30ab7b3 | 3550 | let match_span = self.prev_span; |
cc61c64b | 3551 | let lo = self.prev_span; |
ea8adc8c | 3552 | let discriminant = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, |
54a0048b | 3553 | None)?; |
5bcae85e | 3554 | if let Err(mut e) = self.expect(&token::OpenDelim(token::Brace)) { |
92a42be0 | 3555 | if self.token == token::Token::Semi { |
94b46f34 XL |
3556 | e.span_suggestion_short_with_applicability( |
3557 | match_span, | |
3558 | "try removing this `match`", | |
b7449926 | 3559 | String::new(), |
94b46f34 XL |
3560 | Applicability::MaybeIncorrect // speculative |
3561 | ); | |
92a42be0 SL |
3562 | } |
3563 | return Err(e) | |
3564 | } | |
3157f602 XL |
3565 | attrs.extend(self.parse_inner_attributes()?); |
3566 | ||
1a4d82fc JJ |
3567 | let mut arms: Vec<Arm> = Vec::new(); |
3568 | while self.token != token::CloseDelim(token::Brace) { | |
7453a54e SL |
3569 | match self.parse_arm() { |
3570 | Ok(arm) => arms.push(arm), | |
3571 | Err(mut e) => { | |
3572 | // Recover by skipping to the end of the block. | |
3573 | e.emit(); | |
3574 | self.recover_stmt(); | |
cc61c64b | 3575 | let span = lo.to(self.span); |
7453a54e SL |
3576 | if self.token == token::CloseDelim(token::Brace) { |
3577 | self.bump(); | |
3578 | } | |
cc61c64b | 3579 | return Ok(self.mk_expr(span, ExprKind::Match(discriminant, arms), attrs)); |
7453a54e SL |
3580 | } |
3581 | } | |
223e47cc | 3582 | } |
cc61c64b | 3583 | let hi = self.span; |
9cc50fc6 | 3584 | self.bump(); |
cc61c64b | 3585 | return Ok(self.mk_expr(lo.to(hi), ExprKind::Match(discriminant, arms), attrs)); |
223e47cc LB |
3586 | } |
3587 | ||
94b46f34 | 3588 | crate fn parse_arm(&mut self) -> PResult<'a, Arm> { |
c30ab7b3 | 3589 | maybe_whole!(self, NtArm, |x| x); |
d9579d0f | 3590 | |
54a0048b | 3591 | let attrs = self.parse_outer_attributes()?; |
ea8adc8c | 3592 | // Allow a '|' before the pats (RFC 1925) |
2c00a5a8 | 3593 | self.eat(&token::BinOp(token::Or)); |
54a0048b | 3594 | let pats = self.parse_pats()?; |
7cac9316 | 3595 | let guard = if self.eat_keyword(keywords::If) { |
b7449926 | 3596 | Some(Guard::If(self.parse_expr()?)) |
7cac9316 XL |
3597 | } else { |
3598 | None | |
3599 | }; | |
0531ce1d | 3600 | let arrow_span = self.span; |
54a0048b | 3601 | self.expect(&token::FatArrow)?; |
0531ce1d XL |
3602 | let arm_start_span = self.span; |
3603 | ||
3604 | let expr = self.parse_expr_res(Restrictions::STMT_EXPR, None) | |
3605 | .map_err(|mut err| { | |
3606 | err.span_label(arrow_span, "while parsing the `match` arm starting here"); | |
3607 | err | |
3608 | })?; | |
1a4d82fc | 3609 | |
3b2f2976 | 3610 | let require_comma = classify::expr_requires_semi_to_be_stmt(&expr) |
1a4d82fc JJ |
3611 | && self.token != token::CloseDelim(token::Brace); |
3612 | ||
3613 | if require_comma { | |
b7449926 | 3614 | let cm = self.sess.source_map(); |
0531ce1d XL |
3615 | self.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Brace)]) |
3616 | .map_err(|mut err| { | |
3617 | match (cm.span_to_lines(expr.span), cm.span_to_lines(arm_start_span)) { | |
3618 | (Ok(ref expr_lines), Ok(ref arm_start_lines)) | |
3619 | if arm_start_lines.lines[0].end_col == expr_lines.lines[0].end_col | |
3620 | && expr_lines.lines.len() == 2 | |
3621 | && self.token == token::FatArrow => { | |
b7449926 XL |
3622 | // We check whether there's any trailing code in the parse span, |
3623 | // if there isn't, we very likely have the following: | |
0531ce1d XL |
3624 | // |
3625 | // X | &Y => "y" | |
3626 | // | -- - missing comma | |
3627 | // | | | |
3628 | // | arrow_span | |
3629 | // X | &X => "x" | |
3630 | // | - ^^ self.span | |
3631 | // | | | |
3632 | // | parsed until here as `"y" & X` | |
94b46f34 | 3633 | err.span_suggestion_short_with_applicability( |
0531ce1d XL |
3634 | cm.next_point(arm_start_span), |
3635 | "missing a comma here to end this `match` arm", | |
94b46f34 XL |
3636 | ",".to_owned(), |
3637 | Applicability::MachineApplicable | |
0531ce1d XL |
3638 | ); |
3639 | } | |
3640 | _ => { | |
3641 | err.span_label(arrow_span, | |
3642 | "while parsing the `match` arm starting here"); | |
3643 | } | |
3644 | } | |
3645 | err | |
3646 | })?; | |
1a4d82fc | 3647 | } else { |
9cc50fc6 | 3648 | self.eat(&token::Comma); |
1a4d82fc JJ |
3649 | } |
3650 | ||
9346a6ac | 3651 | Ok(ast::Arm { |
3b2f2976 XL |
3652 | attrs, |
3653 | pats, | |
3654 | guard, | |
1a4d82fc | 3655 | body: expr, |
9346a6ac | 3656 | }) |
1a4d82fc JJ |
3657 | } |
3658 | ||
3659 | /// Parse an expression | |
9cc50fc6 | 3660 | pub fn parse_expr(&mut self) -> PResult<'a, P<Expr>> { |
92a42be0 | 3661 | self.parse_expr_res(Restrictions::empty(), None) |
223e47cc LB |
3662 | } |
3663 | ||
92a42be0 SL |
3664 | /// Evaluate the closure with restrictions in place. |
3665 | /// | |
3666 | /// After the closure is evaluated, restrictions are reset. | |
94b46f34 | 3667 | fn with_res<F, T>(&mut self, r: Restrictions, f: F) -> T |
7453a54e | 3668 | where F: FnOnce(&mut Self) -> T |
9cc50fc6 | 3669 | { |
1a4d82fc JJ |
3670 | let old = self.restrictions; |
3671 | self.restrictions = r; | |
92a42be0 | 3672 | let r = f(self); |
1a4d82fc | 3673 | self.restrictions = old; |
92a42be0 SL |
3674 | return r; |
3675 | ||
3676 | } | |
3677 | ||
3678 | /// Parse an expression, subject to the given restrictions | |
94b46f34 | 3679 | fn parse_expr_res(&mut self, r: Restrictions, |
3157f602 | 3680 | already_parsed_attrs: Option<ThinVec<Attribute>>) |
9cc50fc6 | 3681 | -> PResult<'a, P<Expr>> { |
92a42be0 | 3682 | self.with_res(r, |this| this.parse_assoc_expr(already_parsed_attrs)) |
223e47cc LB |
3683 | } |
3684 | ||
1a4d82fc | 3685 | /// Parse the RHS of a local variable declaration (e.g. '= 14;') |
abe05a73 | 3686 | fn parse_initializer(&mut self, skip_eq: bool) -> PResult<'a, Option<P<Expr>>> { |
b7449926 | 3687 | if self.eat(&token::Eq) { |
54a0048b | 3688 | Ok(Some(self.parse_expr()?)) |
abe05a73 XL |
3689 | } else if skip_eq { |
3690 | Ok(Some(self.parse_expr()?)) | |
1a4d82fc | 3691 | } else { |
9346a6ac | 3692 | Ok(None) |
223e47cc LB |
3693 | } |
3694 | } | |
3695 | ||
1a4d82fc | 3696 | /// Parse patterns, separated by '|' s |
9cc50fc6 | 3697 | fn parse_pats(&mut self) -> PResult<'a, Vec<P<Pat>>> { |
1a4d82fc | 3698 | let mut pats = Vec::new(); |
223e47cc | 3699 | loop { |
0531ce1d | 3700 | pats.push(self.parse_top_level_pat()?); |
2c00a5a8 XL |
3701 | |
3702 | if self.token == token::OrOr { | |
3703 | let mut err = self.struct_span_err(self.span, | |
3704 | "unexpected token `||` after pattern"); | |
94b46f34 XL |
3705 | err.span_suggestion_with_applicability( |
3706 | self.span, | |
3707 | "use a single `|` to specify multiple patterns", | |
3708 | "|".to_owned(), | |
3709 | Applicability::MachineApplicable | |
3710 | ); | |
2c00a5a8 XL |
3711 | err.emit(); |
3712 | self.bump(); | |
b7449926 XL |
3713 | } else if self.eat(&token::BinOp(token::Or)) { |
3714 | // No op. | |
2c00a5a8 XL |
3715 | } else { |
3716 | return Ok(pats); | |
3717 | } | |
223e47cc LB |
3718 | }; |
3719 | } | |
3720 | ||
0531ce1d XL |
3721 | // Parses a parenthesized list of patterns like |
3722 | // `()`, `(p)`, `(p,)`, `(p, q)`, or `(p, .., q)`. Returns: | |
3723 | // - a vector of the patterns that were parsed | |
3724 | // - an option indicating the index of the `..` element | |
3725 | // - a boolean indicating whether a trailing comma was present. | |
3726 | // Trailing commas are significant because (p) and (p,) are different patterns. | |
3727 | fn parse_parenthesized_pat_list(&mut self) -> PResult<'a, (Vec<P<Pat>>, Option<usize>, bool)> { | |
3728 | self.expect(&token::OpenDelim(token::Paren))?; | |
3729 | let result = self.parse_pat_list()?; | |
3730 | self.expect(&token::CloseDelim(token::Paren))?; | |
3731 | Ok(result) | |
3732 | } | |
3157f602 | 3733 | |
0531ce1d XL |
3734 | fn parse_pat_list(&mut self) -> PResult<'a, (Vec<P<Pat>>, Option<usize>, bool)> { |
3735 | let mut fields = Vec::new(); | |
3736 | let mut ddpos = None; | |
3737 | let mut trailing_comma = false; | |
3738 | loop { | |
3739 | if self.eat(&token::DotDot) { | |
3740 | if ddpos.is_none() { | |
3741 | ddpos = Some(fields.len()); | |
3742 | } else { | |
3743 | // Emit a friendly error, ignore `..` and continue parsing | |
3744 | self.span_err(self.prev_span, | |
3745 | "`..` can only be used once per tuple or tuple struct pattern"); | |
9346a6ac | 3746 | } |
0531ce1d | 3747 | } else if !self.check(&token::CloseDelim(token::Paren)) { |
3157f602 | 3748 | fields.push(self.parse_pat()?); |
0531ce1d XL |
3749 | } else { |
3750 | break | |
9346a6ac | 3751 | } |
3157f602 | 3752 | |
0531ce1d XL |
3753 | trailing_comma = self.eat(&token::Comma); |
3754 | if !trailing_comma { | |
3755 | break | |
9346a6ac AL |
3756 | } |
3757 | } | |
3157f602 | 3758 | |
0531ce1d XL |
3759 | if ddpos == Some(fields.len()) && trailing_comma { |
3760 | // `..` needs to be followed by `)` or `, pat`, `..,)` is disallowed. | |
3761 | self.span_err(self.prev_span, "trailing comma is not permitted after `..`"); | |
3762 | } | |
3763 | ||
3764 | Ok((fields, ddpos, trailing_comma)) | |
9346a6ac AL |
3765 | } |
3766 | ||
223e47cc | 3767 | fn parse_pat_vec_elements( |
1a4d82fc | 3768 | &mut self, |
9cc50fc6 | 3769 | ) -> PResult<'a, (Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>)> { |
1a4d82fc | 3770 | let mut before = Vec::new(); |
223e47cc | 3771 | let mut slice = None; |
1a4d82fc | 3772 | let mut after = Vec::new(); |
223e47cc LB |
3773 | let mut first = true; |
3774 | let mut before_slice = true; | |
3775 | ||
1a4d82fc JJ |
3776 | while self.token != token::CloseDelim(token::Bracket) { |
3777 | if first { | |
3778 | first = false; | |
3779 | } else { | |
54a0048b | 3780 | self.expect(&token::Comma)?; |
1a4d82fc JJ |
3781 | |
3782 | if self.token == token::CloseDelim(token::Bracket) | |
9346a6ac | 3783 | && (before_slice || !after.is_empty()) { |
1a4d82fc JJ |
3784 | break |
3785 | } | |
3786 | } | |
223e47cc | 3787 | |
223e47cc | 3788 | if before_slice { |
32a655c1 | 3789 | if self.eat(&token::DotDot) { |
1a4d82fc JJ |
3790 | |
3791 | if self.check(&token::Comma) || | |
3792 | self.check(&token::CloseDelim(token::Bracket)) { | |
ff7c6d11 | 3793 | slice = Some(P(Pat { |
1a4d82fc | 3794 | id: ast::DUMMY_NODE_ID, |
7453a54e | 3795 | node: PatKind::Wild, |
0531ce1d | 3796 | span: self.prev_span, |
1a4d82fc JJ |
3797 | })); |
3798 | before_slice = false; | |
1a4d82fc JJ |
3799 | } |
3800 | continue | |
223e47cc LB |
3801 | } |
3802 | } | |
3803 | ||
54a0048b | 3804 | let subpat = self.parse_pat()?; |
32a655c1 | 3805 | if before_slice && self.eat(&token::DotDot) { |
223e47cc | 3806 | slice = Some(subpat); |
1a4d82fc JJ |
3807 | before_slice = false; |
3808 | } else if before_slice { | |
3809 | before.push(subpat); | |
223e47cc | 3810 | } else { |
1a4d82fc | 3811 | after.push(subpat); |
223e47cc LB |
3812 | } |
3813 | } | |
3814 | ||
9346a6ac | 3815 | Ok((before, slice, after)) |
223e47cc LB |
3816 | } |
3817 | ||
94b46f34 XL |
3818 | fn parse_pat_field( |
3819 | &mut self, | |
3820 | lo: Span, | |
3821 | attrs: Vec<Attribute> | |
b7449926 | 3822 | ) -> PResult<'a, source_map::Spanned<ast::FieldPat>> { |
94b46f34 XL |
3823 | // Check if a colon exists one ahead. This means we're parsing a fieldname. |
3824 | let hi; | |
3825 | let (subpat, fieldname, is_shorthand) = if self.look_ahead(1, |t| t == &token::Colon) { | |
3826 | // Parsing a pattern of the form "fieldname: pat" | |
3827 | let fieldname = self.parse_field_name()?; | |
3828 | self.bump(); | |
3829 | let pat = self.parse_pat()?; | |
3830 | hi = pat.span; | |
3831 | (pat, fieldname, false) | |
3832 | } else { | |
3833 | // Parsing a pattern of the form "(box) (ref) (mut) fieldname" | |
3834 | let is_box = self.eat_keyword(keywords::Box); | |
3835 | let boxed_span = self.span; | |
3836 | let is_ref = self.eat_keyword(keywords::Ref); | |
3837 | let is_mut = self.eat_keyword(keywords::Mut); | |
3838 | let fieldname = self.parse_ident()?; | |
3839 | hi = self.prev_span; | |
3840 | ||
3841 | let bind_type = match (is_ref, is_mut) { | |
3842 | (true, true) => BindingMode::ByRef(Mutability::Mutable), | |
3843 | (true, false) => BindingMode::ByRef(Mutability::Immutable), | |
3844 | (false, true) => BindingMode::ByValue(Mutability::Mutable), | |
3845 | (false, false) => BindingMode::ByValue(Mutability::Immutable), | |
3846 | }; | |
3847 | let fieldpat = P(Pat { | |
3848 | id: ast::DUMMY_NODE_ID, | |
3849 | node: PatKind::Ident(bind_type, fieldname, None), | |
3850 | span: boxed_span.to(hi), | |
3851 | }); | |
3852 | ||
3853 | let subpat = if is_box { | |
3854 | P(Pat { | |
3855 | id: ast::DUMMY_NODE_ID, | |
3856 | node: PatKind::Box(fieldpat), | |
3857 | span: lo.to(hi), | |
3858 | }) | |
3859 | } else { | |
3860 | fieldpat | |
3861 | }; | |
3862 | (subpat, fieldname, true) | |
3863 | }; | |
3864 | ||
b7449926 | 3865 | Ok(source_map::Spanned { |
94b46f34 XL |
3866 | span: lo.to(hi), |
3867 | node: ast::FieldPat { | |
3868 | ident: fieldname, | |
3869 | pat: subpat, | |
3870 | is_shorthand, | |
3871 | attrs: attrs.into(), | |
3872 | } | |
3873 | }) | |
3874 | } | |
3875 | ||
1a4d82fc | 3876 | /// Parse the fields of a struct-like pattern |
b7449926 | 3877 | fn parse_pat_fields(&mut self) -> PResult<'a, (Vec<source_map::Spanned<ast::FieldPat>>, bool)> { |
1a4d82fc | 3878 | let mut fields = Vec::new(); |
223e47cc | 3879 | let mut etc = false; |
94b46f34 XL |
3880 | let mut ate_comma = true; |
3881 | let mut delayed_err: Option<DiagnosticBuilder<'a>> = None; | |
3882 | let mut etc_span = None; | |
1a4d82fc | 3883 | |
94b46f34 | 3884 | while self.token != token::CloseDelim(token::Brace) { |
32a655c1 | 3885 | let attrs = self.parse_outer_attributes()?; |
cc61c64b | 3886 | let lo = self.span; |
94b46f34 XL |
3887 | |
3888 | // check that a comma comes after every field | |
3889 | if !ate_comma { | |
3890 | let err = self.struct_span_err(self.prev_span, "expected `,`"); | |
0bf4aa26 XL |
3891 | if let Some(mut delayed) = delayed_err { |
3892 | delayed.emit(); | |
3893 | } | |
94b46f34 XL |
3894 | return Err(err); |
3895 | } | |
3896 | ate_comma = false; | |
223e47cc | 3897 | |
ff7c6d11 | 3898 | if self.check(&token::DotDot) || self.token == token::DotDotDot { |
94b46f34 XL |
3899 | etc = true; |
3900 | let mut etc_sp = self.span; | |
3901 | ||
ff7c6d11 | 3902 | if self.token == token::DotDotDot { // Issue #46718 |
94b46f34 | 3903 | // Accept `...` as if it were `..` to avoid further errors |
ff7c6d11 XL |
3904 | let mut err = self.struct_span_err(self.span, |
3905 | "expected field pattern, found `...`"); | |
94b46f34 XL |
3906 | err.span_suggestion_with_applicability( |
3907 | self.span, | |
3908 | "to omit remaining fields, use one fewer `.`", | |
3909 | "..".to_owned(), | |
3910 | Applicability::MachineApplicable | |
3911 | ); | |
ff7c6d11 XL |
3912 | err.emit(); |
3913 | } | |
94b46f34 | 3914 | self.bump(); // `..` || `...`:w |
ff7c6d11 | 3915 | |
94b46f34 XL |
3916 | if self.token == token::CloseDelim(token::Brace) { |
3917 | etc_span = Some(etc_sp); | |
3918 | break; | |
3919 | } | |
3920 | let token_str = self.this_token_to_string(); | |
3921 | let mut err = self.fatal(&format!("expected `}}`, found `{}`", token_str)); | |
3922 | ||
3923 | err.span_label(self.span, "expected `}`"); | |
3924 | let mut comma_sp = None; | |
3925 | if self.token == token::Comma { // Issue #49257 | |
b7449926 | 3926 | etc_sp = etc_sp.to(self.sess.source_map().span_until_non_whitespace(self.span)); |
94b46f34 XL |
3927 | err.span_label(etc_sp, |
3928 | "`..` must be at the end and cannot have a trailing comma"); | |
3929 | comma_sp = Some(self.span); | |
3930 | self.bump(); | |
3931 | ate_comma = true; | |
3932 | } | |
3933 | ||
3934 | etc_span = Some(etc_sp); | |
3935 | if self.token == token::CloseDelim(token::Brace) { | |
3936 | // If the struct looks otherwise well formed, recover and continue. | |
3937 | if let Some(sp) = comma_sp { | |
0bf4aa26 XL |
3938 | err.span_suggestion_short_with_applicability( |
3939 | sp, | |
3940 | "remove this comma", | |
3941 | String::new(), | |
3942 | Applicability::MachineApplicable, | |
3943 | ); | |
94b46f34 XL |
3944 | } |
3945 | err.emit(); | |
3946 | break; | |
3947 | } else if self.token.is_ident() && ate_comma { | |
3948 | // Accept fields coming after `..,`. | |
3949 | // This way we avoid "pattern missing fields" errors afterwards. | |
3950 | // We delay this error until the end in order to have a span for a | |
3951 | // suggested fix. | |
3952 | if let Some(mut delayed_err) = delayed_err { | |
3953 | delayed_err.emit(); | |
3954 | return Err(err); | |
0531ce1d | 3955 | } else { |
94b46f34 XL |
3956 | delayed_err = Some(err); |
3957 | } | |
3958 | } else { | |
3959 | if let Some(mut err) = delayed_err { | |
3960 | err.emit(); | |
0531ce1d XL |
3961 | } |
3962 | return Err(err); | |
223e47cc | 3963 | } |
223e47cc LB |
3964 | } |
3965 | ||
94b46f34 XL |
3966 | fields.push(match self.parse_pat_field(lo, attrs) { |
3967 | Ok(field) => field, | |
3968 | Err(err) => { | |
3969 | if let Some(mut delayed_err) = delayed_err { | |
3970 | delayed_err.emit(); | |
3971 | } | |
3972 | return Err(err); | |
3973 | } | |
32a655c1 | 3974 | }); |
94b46f34 XL |
3975 | ate_comma = self.eat(&token::Comma); |
3976 | } | |
3977 | ||
3978 | if let Some(mut err) = delayed_err { | |
3979 | if let Some(etc_span) = etc_span { | |
3980 | err.multipart_suggestion( | |
3981 | "move the `..` to the end of the field list", | |
3982 | vec![ | |
b7449926 | 3983 | (etc_span, String::new()), |
94b46f34 XL |
3984 | (self.span, format!("{}.. }}", if ate_comma { "" } else { ", " })), |
3985 | ], | |
3986 | ); | |
3987 | } | |
3988 | err.emit(); | |
223e47cc | 3989 | } |
9346a6ac AL |
3990 | return Ok((fields, etc)); |
3991 | } | |
3992 | ||
9cc50fc6 | 3993 | fn parse_pat_range_end(&mut self) -> PResult<'a, P<Expr>> { |
a7813a04 | 3994 | if self.token.is_path_start() { |
cc61c64b | 3995 | let lo = self.span; |
9cc50fc6 | 3996 | let (qself, path) = if self.eat_lt() { |
d9579d0f | 3997 | // Parse a qualified path |
3b2f2976 | 3998 | let (qself, path) = self.parse_qpath(PathStyle::Expr)?; |
d9579d0f AL |
3999 | (Some(qself), path) |
4000 | } else { | |
4001 | // Parse an unqualified path | |
a7813a04 | 4002 | (None, self.parse_path(PathStyle::Expr)?) |
d9579d0f | 4003 | }; |
cc61c64b XL |
4004 | let hi = self.prev_span; |
4005 | Ok(self.mk_expr(lo.to(hi), ExprKind::Path(qself, path), ThinVec::new())) | |
9346a6ac | 4006 | } else { |
94b46f34 | 4007 | self.parse_literal_maybe_minus() |
9346a6ac AL |
4008 | } |
4009 | } | |
4010 | ||
32a655c1 SL |
4011 | // helper function to decide whether to parse as ident binding or to try to do |
4012 | // something more complex like range patterns | |
4013 | fn parse_as_ident(&mut self) -> bool { | |
4014 | self.look_ahead(1, |t| match *t { | |
4015 | token::OpenDelim(token::Paren) | token::OpenDelim(token::Brace) | | |
ea8adc8c | 4016 | token::DotDotDot | token::DotDotEq | token::ModSep | token::Not => Some(false), |
32a655c1 SL |
4017 | // ensure slice patterns [a, b.., c] and [a, b, c..] don't go into the |
4018 | // range pattern branch | |
4019 | token::DotDot => None, | |
4020 | _ => Some(true), | |
4021 | }).unwrap_or_else(|| self.look_ahead(2, |t| match *t { | |
4022 | token::Comma | token::CloseDelim(token::Bracket) => true, | |
4023 | _ => false, | |
4024 | })) | |
4025 | } | |
4026 | ||
0531ce1d | 4027 | /// A wrapper around `parse_pat` with some special error handling for the |
b7449926 | 4028 | /// "top-level" patterns in a match arm, `for` loop, `let`, &c. (in contrast |
0531ce1d | 4029 | /// to subpatterns within such). |
94b46f34 | 4030 | fn parse_top_level_pat(&mut self) -> PResult<'a, P<Pat>> { |
0531ce1d XL |
4031 | let pat = self.parse_pat()?; |
4032 | if self.token == token::Comma { | |
4033 | // An unexpected comma after a top-level pattern is a clue that the | |
4034 | // user (perhaps more accustomed to some other language) forgot the | |
4035 | // parentheses in what should have been a tuple pattern; return a | |
4036 | // suggestion-enhanced error here rather than choking on the comma | |
4037 | // later. | |
4038 | let comma_span = self.span; | |
4039 | self.bump(); | |
4040 | if let Err(mut err) = self.parse_pat_list() { | |
4041 | // We didn't expect this to work anyway; we just wanted | |
4042 | // to advance to the end of the comma-sequence so we know | |
4043 | // the span to suggest parenthesizing | |
4044 | err.cancel(); | |
4045 | } | |
4046 | let seq_span = pat.span.to(self.prev_span); | |
4047 | let mut err = self.struct_span_err(comma_span, | |
4048 | "unexpected `,` in pattern"); | |
b7449926 | 4049 | if let Ok(seq_snippet) = self.sess.source_map().span_to_snippet(seq_span) { |
94b46f34 XL |
4050 | err.span_suggestion_with_applicability( |
4051 | seq_span, | |
4052 | "try adding parentheses", | |
4053 | format!("({})", seq_snippet), | |
4054 | Applicability::MachineApplicable | |
4055 | ); | |
0531ce1d XL |
4056 | } |
4057 | return Err(err); | |
4058 | } | |
4059 | Ok(pat) | |
4060 | } | |
4061 | ||
1a4d82fc | 4062 | /// Parse a pattern. |
9cc50fc6 | 4063 | pub fn parse_pat(&mut self) -> PResult<'a, P<Pat>> { |
0531ce1d XL |
4064 | self.parse_pat_with_range_pat(true) |
4065 | } | |
4066 | ||
4067 | /// Parse a pattern, with a setting whether modern range patterns e.g. `a..=b`, `a..b` are | |
4068 | /// allowed. | |
4069 | fn parse_pat_with_range_pat(&mut self, allow_range_pat: bool) -> PResult<'a, P<Pat>> { | |
c30ab7b3 | 4070 | maybe_whole!(self, NtPat, |x| x); |
223e47cc | 4071 | |
cc61c64b | 4072 | let lo = self.span; |
970d7e83 | 4073 | let pat; |
1a4d82fc | 4074 | match self.token { |
9e0c209e SL |
4075 | token::BinOp(token::And) | token::AndAnd => { |
4076 | // Parse &pat / &mut pat | |
4077 | self.expect_and()?; | |
cc61c64b | 4078 | let mutbl = self.parse_mutability(); |
9e0c209e | 4079 | if let token::Lifetime(ident) = self.token { |
0531ce1d XL |
4080 | let mut err = self.fatal(&format!("unexpected lifetime `{}` in pattern", |
4081 | ident)); | |
4082 | err.span_label(self.span, "unexpected lifetime"); | |
4083 | return Err(err); | |
9e0c209e | 4084 | } |
0531ce1d | 4085 | let subpat = self.parse_pat_with_range_pat(false)?; |
9e0c209e SL |
4086 | pat = PatKind::Ref(subpat, mutbl); |
4087 | } | |
4088 | token::OpenDelim(token::Paren) => { | |
4089 | // Parse (pat,pat,pat,...) as tuple pattern | |
0531ce1d XL |
4090 | let (fields, ddpos, trailing_comma) = self.parse_parenthesized_pat_list()?; |
4091 | pat = if fields.len() == 1 && ddpos.is_none() && !trailing_comma { | |
4092 | PatKind::Paren(fields.into_iter().nth(0).unwrap()) | |
4093 | } else { | |
4094 | PatKind::Tuple(fields, ddpos) | |
4095 | }; | |
9e0c209e SL |
4096 | } |
4097 | token::OpenDelim(token::Bracket) => { | |
4098 | // Parse [pat,pat,...] as slice pattern | |
4099 | self.bump(); | |
4100 | let (before, slice, after) = self.parse_pat_vec_elements()?; | |
4101 | self.expect(&token::CloseDelim(token::Bracket))?; | |
c30ab7b3 | 4102 | pat = PatKind::Slice(before, slice, after); |
b039eaaf | 4103 | } |
0531ce1d XL |
4104 | // At this point, token != &, &&, (, [ |
4105 | _ => if self.eat_keyword(keywords::Underscore) { | |
4106 | // Parse _ | |
4107 | pat = PatKind::Wild; | |
4108 | } else if self.eat_keyword(keywords::Mut) { | |
3b2f2976 XL |
4109 | // Parse mut ident @ pat / mut ref ident @ pat |
4110 | let mutref_span = self.prev_span.to(self.span); | |
4111 | let binding_mode = if self.eat_keyword(keywords::Ref) { | |
4112 | self.diagnostic() | |
4113 | .struct_span_err(mutref_span, "the order of `mut` and `ref` is incorrect") | |
94b46f34 XL |
4114 | .span_suggestion_with_applicability( |
4115 | mutref_span, | |
4116 | "try switching the order", | |
4117 | "ref mut".into(), | |
4118 | Applicability::MachineApplicable | |
4119 | ).emit(); | |
3b2f2976 XL |
4120 | BindingMode::ByRef(Mutability::Mutable) |
4121 | } else { | |
4122 | BindingMode::ByValue(Mutability::Mutable) | |
4123 | }; | |
4124 | pat = self.parse_pat_ident(binding_mode)?; | |
9cc50fc6 | 4125 | } else if self.eat_keyword(keywords::Ref) { |
9346a6ac | 4126 | // Parse ref ident @ pat / ref mut ident @ pat |
cc61c64b | 4127 | let mutbl = self.parse_mutability(); |
54a0048b | 4128 | pat = self.parse_pat_ident(BindingMode::ByRef(mutbl))?; |
9cc50fc6 | 4129 | } else if self.eat_keyword(keywords::Box) { |
9346a6ac | 4130 | // Parse box pat |
0531ce1d | 4131 | let subpat = self.parse_pat_with_range_pat(false)?; |
7453a54e | 4132 | pat = PatKind::Box(subpat); |
041b39d2 | 4133 | } else if self.token.is_ident() && !self.token.is_reserved_ident() && |
32a655c1 | 4134 | self.parse_as_ident() { |
9e0c209e SL |
4135 | // Parse ident @ pat |
4136 | // This can give false positives and parse nullary enums, | |
4137 | // they are dealt with later in resolve | |
4138 | let binding_mode = BindingMode::ByValue(Mutability::Immutable); | |
4139 | pat = self.parse_pat_ident(binding_mode)?; | |
a7813a04 | 4140 | } else if self.token.is_path_start() { |
9346a6ac | 4141 | // Parse pattern starting with a path |
9e0c209e SL |
4142 | let (qself, path) = if self.eat_lt() { |
4143 | // Parse a qualified path | |
3b2f2976 | 4144 | let (qself, path) = self.parse_qpath(PathStyle::Expr)?; |
9e0c209e SL |
4145 | (Some(qself), path) |
4146 | } else { | |
4147 | // Parse an unqualified path | |
4148 | (None, self.parse_path(PathStyle::Expr)?) | |
4149 | }; | |
4150 | match self.token { | |
4151 | token::Not if qself.is_none() => { | |
9346a6ac | 4152 | // Parse macro invocation |
9cc50fc6 | 4153 | self.bump(); |
94b46f34 XL |
4154 | let (delim, tts) = self.expect_delimited_token_tree()?; |
4155 | let mac = respan(lo.to(self.prev_span), Mac_ { path, tts, delim }); | |
9e0c209e | 4156 | pat = PatKind::Mac(mac); |
970d7e83 | 4157 | } |
ea8adc8c | 4158 | token::DotDotDot | token::DotDotEq | token::DotDot => { |
32a655c1 SL |
4159 | let end_kind = match self.token { |
4160 | token::DotDot => RangeEnd::Excluded, | |
ea8adc8c XL |
4161 | token::DotDotDot => RangeEnd::Included(RangeSyntax::DotDotDot), |
4162 | token::DotDotEq => RangeEnd::Included(RangeSyntax::DotDotEq), | |
4163 | _ => panic!("can only parse `..`/`...`/`..=` for ranges \ | |
4164 | (checked above)"), | |
32a655c1 | 4165 | }; |
8faf50e0 | 4166 | let op_span = self.span; |
9346a6ac | 4167 | // Parse range |
cc61c64b XL |
4168 | let span = lo.to(self.prev_span); |
4169 | let begin = self.mk_expr(span, ExprKind::Path(qself, path), ThinVec::new()); | |
9cc50fc6 | 4170 | self.bump(); |
54a0048b | 4171 | let end = self.parse_pat_range_end()?; |
8faf50e0 XL |
4172 | let op = Spanned { span: op_span, node: end_kind }; |
4173 | pat = PatKind::Range(begin, end, op); | |
9e0c209e SL |
4174 | } |
4175 | token::OpenDelim(token::Brace) => { | |
4176 | if qself.is_some() { | |
0531ce1d XL |
4177 | let msg = "unexpected `{` after qualified path"; |
4178 | let mut err = self.fatal(msg); | |
4179 | err.span_label(self.span, msg); | |
4180 | return Err(err); | |
d9579d0f | 4181 | } |
b039eaaf | 4182 | // Parse struct pattern |
9cc50fc6 | 4183 | self.bump(); |
7453a54e SL |
4184 | let (fields, etc) = self.parse_pat_fields().unwrap_or_else(|mut e| { |
4185 | e.emit(); | |
4186 | self.recover_stmt(); | |
4187 | (vec![], false) | |
4188 | }); | |
9cc50fc6 | 4189 | self.bump(); |
7453a54e | 4190 | pat = PatKind::Struct(path, fields, etc); |
9e0c209e SL |
4191 | } |
4192 | token::OpenDelim(token::Paren) => { | |
d9579d0f | 4193 | if qself.is_some() { |
0531ce1d XL |
4194 | let msg = "unexpected `(` after qualified path"; |
4195 | let mut err = self.fatal(msg); | |
4196 | err.span_label(self.span, msg); | |
4197 | return Err(err); | |
d9579d0f | 4198 | } |
9346a6ac | 4199 | // Parse tuple struct or enum pattern |
0531ce1d | 4200 | let (fields, ddpos, _) = self.parse_parenthesized_pat_list()?; |
3157f602 | 4201 | pat = PatKind::TupleStruct(path, fields, ddpos) |
223e47cc | 4202 | } |
9e0c209e | 4203 | _ => pat = PatKind::Path(qself, path), |
223e47cc | 4204 | } |
9346a6ac AL |
4205 | } else { |
4206 | // Try to parse everything else as literal with optional minus | |
94b46f34 | 4207 | match self.parse_literal_maybe_minus() { |
a7813a04 | 4208 | Ok(begin) => { |
8faf50e0 XL |
4209 | let op_span = self.span; |
4210 | if self.check(&token::DotDot) || self.check(&token::DotDotEq) || | |
4211 | self.check(&token::DotDotDot) { | |
4212 | let end_kind = if self.eat(&token::DotDotDot) { | |
4213 | RangeEnd::Included(RangeSyntax::DotDotDot) | |
4214 | } else if self.eat(&token::DotDotEq) { | |
4215 | RangeEnd::Included(RangeSyntax::DotDotEq) | |
4216 | } else if self.eat(&token::DotDot) { | |
4217 | RangeEnd::Excluded | |
4218 | } else { | |
4219 | panic!("impossible case: we already matched \ | |
4220 | on a range-operator token") | |
4221 | }; | |
ea8adc8c | 4222 | let end = self.parse_pat_range_end()?; |
8faf50e0 XL |
4223 | let op = Spanned { span: op_span, node: end_kind }; |
4224 | pat = PatKind::Range(begin, end, op); | |
a7813a04 XL |
4225 | } else { |
4226 | pat = PatKind::Lit(begin); | |
4227 | } | |
4228 | } | |
4229 | Err(mut err) => { | |
9e0c209e | 4230 | self.cancel(&mut err); |
a7813a04 | 4231 | let msg = format!("expected pattern, found {}", self.this_token_descr()); |
0531ce1d XL |
4232 | let mut err = self.fatal(&msg); |
4233 | err.span_label(self.span, "expected pattern"); | |
4234 | return Err(err); | |
a7813a04 | 4235 | } |
9346a6ac | 4236 | } |
223e47cc | 4237 | } |
223e47cc | 4238 | } |
9346a6ac | 4239 | |
ff7c6d11 XL |
4240 | let pat = Pat { node: pat, span: lo.to(self.prev_span), id: ast::DUMMY_NODE_ID }; |
4241 | let pat = self.maybe_recover_from_bad_qpath(pat, true)?; | |
4242 | ||
0531ce1d XL |
4243 | if !allow_range_pat { |
4244 | match pat.node { | |
8faf50e0 XL |
4245 | PatKind::Range( |
4246 | _, _, Spanned { node: RangeEnd::Included(RangeSyntax::DotDotDot), .. } | |
4247 | ) => {}, | |
0531ce1d XL |
4248 | PatKind::Range(..) => { |
4249 | let mut err = self.struct_span_err( | |
4250 | pat.span, | |
4251 | "the range pattern here has ambiguous interpretation", | |
4252 | ); | |
94b46f34 | 4253 | err.span_suggestion_with_applicability( |
0531ce1d XL |
4254 | pat.span, |
4255 | "add parentheses to clarify the precedence", | |
4256 | format!("({})", pprust::pat_to_string(&pat)), | |
94b46f34 XL |
4257 | // "ambiguous interpretation" implies that we have to be guessing |
4258 | Applicability::MaybeIncorrect | |
0531ce1d XL |
4259 | ); |
4260 | return Err(err); | |
4261 | } | |
4262 | _ => {} | |
4263 | } | |
4264 | } | |
4265 | ||
ff7c6d11 | 4266 | Ok(P(pat)) |
223e47cc LB |
4267 | } |
4268 | ||
1a4d82fc JJ |
4269 | /// Parse ident or ident @ pat |
4270 | /// used by the copy foo and ref foo patterns to give a good | |
4271 | /// error message when parsing mistakes like ref foo(a,b) | |
4272 | fn parse_pat_ident(&mut self, | |
4273 | binding_mode: ast::BindingMode) | |
7453a54e | 4274 | -> PResult<'a, PatKind> { |
54a0048b | 4275 | let ident = self.parse_ident()?; |
9cc50fc6 | 4276 | let sub = if self.eat(&token::At) { |
54a0048b | 4277 | Some(self.parse_pat()?) |
970d7e83 LB |
4278 | } else { |
4279 | None | |
4280 | }; | |
223e47cc LB |
4281 | |
4282 | // just to be friendly, if they write something like | |
4283 | // ref Some(i) | |
4284 | // we end up here with ( as the current token. This shortly | |
4285 | // leads to a parse error. Note that if there is no explicit | |
4286 | // binding mode then we do not end up here, because the lookahead | |
4287 | // will direct us over to parse_enum_variant() | |
1a4d82fc | 4288 | if self.token == token::OpenDelim(token::Paren) { |
9346a6ac | 4289 | return Err(self.span_fatal( |
c30ab7b3 | 4290 | self.prev_span, |
9346a6ac | 4291 | "expected identifier, found enum pattern")) |
223e47cc LB |
4292 | } |
4293 | ||
83c7162d | 4294 | Ok(PatKind::Ident(binding_mode, ident, sub)) |
223e47cc LB |
4295 | } |
4296 | ||
1a4d82fc | 4297 | /// Parse a local variable declaration |
3157f602 | 4298 | fn parse_local(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Local>> { |
3b2f2976 | 4299 | let lo = self.prev_span; |
0531ce1d | 4300 | let pat = self.parse_top_level_pat()?; |
970d7e83 | 4301 | |
abe05a73 XL |
4302 | let (err, ty) = if self.eat(&token::Colon) { |
4303 | // Save the state of the parser before parsing type normally, in case there is a `:` | |
4304 | // instead of an `=` typo. | |
4305 | let parser_snapshot_before_type = self.clone(); | |
4306 | let colon_sp = self.prev_span; | |
4307 | match self.parse_ty() { | |
4308 | Ok(ty) => (None, Some(ty)), | |
4309 | Err(mut err) => { | |
4310 | // Rewind to before attempting to parse the type and continue parsing | |
4311 | let parser_snapshot_after_type = self.clone(); | |
4312 | mem::replace(self, parser_snapshot_before_type); | |
4313 | ||
b7449926 | 4314 | let snippet = self.sess.source_map().span_to_snippet(pat.span).unwrap(); |
abe05a73 XL |
4315 | err.span_label(pat.span, format!("while parsing the type for `{}`", snippet)); |
4316 | (Some((parser_snapshot_after_type, colon_sp, err)), None) | |
4317 | } | |
4318 | } | |
7cac9316 | 4319 | } else { |
abe05a73 XL |
4320 | (None, None) |
4321 | }; | |
4322 | let init = match (self.parse_initializer(err.is_some()), err) { | |
4323 | (Ok(init), None) => { // init parsed, ty parsed | |
4324 | init | |
4325 | } | |
4326 | (Ok(init), Some((_, colon_sp, mut err))) => { // init parsed, ty error | |
4327 | // Could parse the type as if it were the initializer, it is likely there was a | |
4328 | // typo in the code: `:` instead of `=`. Add suggestion and emit the error. | |
94b46f34 XL |
4329 | err.span_suggestion_short_with_applicability( |
4330 | colon_sp, | |
4331 | "use `=` if you meant to assign", | |
4332 | "=".to_string(), | |
4333 | Applicability::MachineApplicable | |
4334 | ); | |
abe05a73 | 4335 | err.emit(); |
0531ce1d | 4336 | // As this was parsed successfully, continue as if the code has been fixed for the |
abe05a73 XL |
4337 | // rest of the file. It will still fail due to the emitted error, but we avoid |
4338 | // extra noise. | |
4339 | init | |
4340 | } | |
4341 | (Err(mut init_err), Some((snapshot, _, ty_err))) => { // init error, ty error | |
4342 | init_err.cancel(); | |
4343 | // Couldn't parse the type nor the initializer, only raise the type error and | |
4344 | // return to the parser state before parsing the type as the initializer. | |
4345 | // let x: <parse_error>; | |
4346 | mem::replace(self, snapshot); | |
4347 | return Err(ty_err); | |
4348 | } | |
4349 | (Err(err), None) => { // init error, ty parsed | |
4350 | // Couldn't parse the initializer and we're not attempting to recover a failed | |
4351 | // parse of the type, return the error. | |
4352 | return Err(err); | |
4353 | } | |
7cac9316 | 4354 | }; |
ea8adc8c XL |
4355 | let hi = if self.token == token::Semi { |
4356 | self.span | |
4357 | } else { | |
4358 | self.prev_span | |
4359 | }; | |
9346a6ac | 4360 | Ok(P(ast::Local { |
3b2f2976 XL |
4361 | ty, |
4362 | pat, | |
4363 | init, | |
1a4d82fc | 4364 | id: ast::DUMMY_NODE_ID, |
ea8adc8c | 4365 | span: lo.to(hi), |
3b2f2976 | 4366 | attrs, |
9346a6ac | 4367 | })) |
223e47cc LB |
4368 | } |
4369 | ||
1a4d82fc | 4370 | /// Parse a structure field |
5bcae85e | 4371 | fn parse_name_and_ty(&mut self, |
cc61c64b | 4372 | lo: Span, |
5bcae85e SL |
4373 | vis: Visibility, |
4374 | attrs: Vec<Attribute>) | |
4375 | -> PResult<'a, StructField> { | |
54a0048b SL |
4376 | let name = self.parse_ident()?; |
4377 | self.expect(&token::Colon)?; | |
32a655c1 | 4378 | let ty = self.parse_ty()?; |
54a0048b | 4379 | Ok(StructField { |
cc61c64b | 4380 | span: lo.to(self.prev_span), |
54a0048b | 4381 | ident: Some(name), |
3b2f2976 | 4382 | vis, |
1a4d82fc | 4383 | id: ast::DUMMY_NODE_ID, |
3b2f2976 XL |
4384 | ty, |
4385 | attrs, | |
54a0048b | 4386 | }) |
223e47cc LB |
4387 | } |
4388 | ||
c34b1796 AL |
4389 | /// Emit an expected item after attributes error. |
4390 | fn expected_item_err(&self, attrs: &[Attribute]) { | |
4391 | let message = match attrs.last() { | |
476ff2be | 4392 | Some(&Attribute { is_sugared_doc: true, .. }) => "expected item after doc comment", |
1a4d82fc | 4393 | _ => "expected item after attributes", |
c34b1796 AL |
4394 | }; |
4395 | ||
c30ab7b3 | 4396 | self.span_err(self.prev_span, message); |
1a4d82fc JJ |
4397 | } |
4398 | ||
5bcae85e SL |
4399 | /// Parse a statement. This stops just before trailing semicolons on everything but items. |
4400 | /// e.g. a `StmtKind::Semi` parses to a `StmtKind::Expr`, leaving the trailing `;` unconsumed. | |
7453a54e | 4401 | pub fn parse_stmt(&mut self) -> PResult<'a, Option<Stmt>> { |
5bcae85e | 4402 | Ok(self.parse_stmt_(true)) |
7453a54e SL |
4403 | } |
4404 | ||
4405 | // Eat tokens until we can be relatively sure we reached the end of the | |
4406 | // statement. This is something of a best-effort heuristic. | |
4407 | // | |
4408 | // We terminate when we find an unmatched `}` (without consuming it). | |
4409 | fn recover_stmt(&mut self) { | |
cc61c64b | 4410 | self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore) |
7453a54e | 4411 | } |
cc61c64b | 4412 | |
7453a54e SL |
4413 | // If `break_on_semi` is `Break`, then we will stop consuming tokens after |
4414 | // finding (and consuming) a `;` outside of `{}` or `[]` (note that this is | |
4415 | // approximate - it can mean we break too early due to macros, but that | |
b7449926 | 4416 | // should only lead to sub-optimal recovery, not inaccurate parsing). |
cc61c64b XL |
4417 | // |
4418 | // If `break_on_block` is `Break`, then we will stop consuming tokens | |
4419 | // after finding (and consuming) a brace-delimited block. | |
4420 | fn recover_stmt_(&mut self, break_on_semi: SemiColonMode, break_on_block: BlockMode) { | |
7453a54e SL |
4421 | let mut brace_depth = 0; |
4422 | let mut bracket_depth = 0; | |
cc61c64b XL |
4423 | let mut in_block = false; |
4424 | debug!("recover_stmt_ enter loop (semi={:?}, block={:?})", | |
4425 | break_on_semi, break_on_block); | |
7453a54e SL |
4426 | loop { |
4427 | debug!("recover_stmt_ loop {:?}", self.token); | |
4428 | match self.token { | |
4429 | token::OpenDelim(token::DelimToken::Brace) => { | |
4430 | brace_depth += 1; | |
4431 | self.bump(); | |
cc61c64b XL |
4432 | if break_on_block == BlockMode::Break && |
4433 | brace_depth == 1 && | |
4434 | bracket_depth == 0 { | |
4435 | in_block = true; | |
4436 | } | |
7453a54e SL |
4437 | } |
4438 | token::OpenDelim(token::DelimToken::Bracket) => { | |
4439 | bracket_depth += 1; | |
4440 | self.bump(); | |
4441 | } | |
4442 | token::CloseDelim(token::DelimToken::Brace) => { | |
4443 | if brace_depth == 0 { | |
4444 | debug!("recover_stmt_ return - close delim {:?}", self.token); | |
4445 | return; | |
4446 | } | |
4447 | brace_depth -= 1; | |
4448 | self.bump(); | |
cc61c64b XL |
4449 | if in_block && bracket_depth == 0 && brace_depth == 0 { |
4450 | debug!("recover_stmt_ return - block end {:?}", self.token); | |
4451 | return; | |
4452 | } | |
7453a54e SL |
4453 | } |
4454 | token::CloseDelim(token::DelimToken::Bracket) => { | |
4455 | bracket_depth -= 1; | |
4456 | if bracket_depth < 0 { | |
4457 | bracket_depth = 0; | |
4458 | } | |
4459 | self.bump(); | |
4460 | } | |
4461 | token::Eof => { | |
4462 | debug!("recover_stmt_ return - Eof"); | |
4463 | return; | |
4464 | } | |
4465 | token::Semi => { | |
4466 | self.bump(); | |
4467 | if break_on_semi == SemiColonMode::Break && | |
4468 | brace_depth == 0 && | |
4469 | bracket_depth == 0 { | |
4470 | debug!("recover_stmt_ return - Semi"); | |
4471 | return; | |
4472 | } | |
4473 | } | |
4474 | _ => { | |
4475 | self.bump() | |
4476 | } | |
4477 | } | |
4478 | } | |
4479 | } | |
4480 | ||
9e0c209e SL |
4481 | fn parse_stmt_(&mut self, macro_legacy_warnings: bool) -> Option<Stmt> { |
4482 | self.parse_stmt_without_recovery(macro_legacy_warnings).unwrap_or_else(|mut e| { | |
7453a54e | 4483 | e.emit(); |
cc61c64b | 4484 | self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); |
7453a54e SL |
4485 | None |
4486 | }) | |
c34b1796 AL |
4487 | } |
4488 | ||
8faf50e0 XL |
4489 | fn is_async_block(&mut self) -> bool { |
4490 | self.token.is_keyword(keywords::Async) && | |
4491 | ( | |
4492 | ( // `async move {` | |
4493 | self.look_ahead(1, |t| t.is_keyword(keywords::Move)) && | |
4494 | self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace)) | |
4495 | ) || ( // `async {` | |
4496 | self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) | |
4497 | ) | |
4498 | ) | |
4499 | } | |
4500 | ||
b7449926 | 4501 | fn is_do_catch_block(&mut self) -> bool { |
cc61c64b XL |
4502 | self.token.is_keyword(keywords::Do) && |
4503 | self.look_ahead(1, |t| t.is_keyword(keywords::Catch)) && | |
4504 | self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace)) && | |
b7449926 XL |
4505 | !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL) |
4506 | } | |
4507 | ||
4508 | fn is_try_block(&mut self) -> bool { | |
4509 | self.token.is_keyword(keywords::Try) && | |
4510 | self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) && | |
cc61c64b | 4511 | |
b7449926 XL |
4512 | self.span.edition() >= Edition::Edition2018 && |
4513 | ||
4514 | // prevent `while try {} {}`, `if try {} {} else {}`, etc. | |
ea8adc8c | 4515 | !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL) |
cc61c64b XL |
4516 | } |
4517 | ||
8bb4bdeb | 4518 | fn is_union_item(&self) -> bool { |
c30ab7b3 | 4519 | self.token.is_keyword(keywords::Union) && |
041b39d2 | 4520 | self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident()) |
c30ab7b3 SL |
4521 | } |
4522 | ||
ff7c6d11 XL |
4523 | fn is_crate_vis(&self) -> bool { |
4524 | self.token.is_keyword(keywords::Crate) && self.look_ahead(1, |t| t != &token::ModSep) | |
4525 | } | |
4526 | ||
2c00a5a8 XL |
4527 | fn is_extern_non_path(&self) -> bool { |
4528 | self.token.is_keyword(keywords::Extern) && self.look_ahead(1, |t| t != &token::ModSep) | |
abe05a73 XL |
4529 | } |
4530 | ||
8faf50e0 XL |
4531 | fn is_existential_type_decl(&self) -> bool { |
4532 | self.token.is_keyword(keywords::Existential) && | |
4533 | self.look_ahead(1, |t| t.is_keyword(keywords::Type)) | |
4534 | } | |
4535 | ||
2c00a5a8 XL |
4536 | fn is_auto_trait_item(&mut self) -> bool { |
4537 | // auto trait | |
4538 | (self.token.is_keyword(keywords::Auto) | |
4539 | && self.look_ahead(1, |t| t.is_keyword(keywords::Trait))) | |
4540 | || // unsafe auto trait | |
4541 | (self.token.is_keyword(keywords::Unsafe) && | |
4542 | self.look_ahead(1, |t| t.is_keyword(keywords::Auto)) && | |
4543 | self.look_ahead(2, |t| t.is_keyword(keywords::Trait))) | |
7cac9316 XL |
4544 | } |
4545 | ||
ea8adc8c | 4546 | fn eat_macro_def(&mut self, attrs: &[Attribute], vis: &Visibility, lo: Span) |
8bb4bdeb | 4547 | -> PResult<'a, Option<P<Item>>> { |
ea8adc8c | 4548 | let token_lo = self.span; |
7cac9316 | 4549 | let (ident, def) = match self.token { |
0531ce1d | 4550 | token::Ident(ident, false) if ident.name == keywords::Macro.name() => { |
7cac9316 XL |
4551 | self.bump(); |
4552 | let ident = self.parse_ident()?; | |
4553 | let tokens = if self.check(&token::OpenDelim(token::Brace)) { | |
4554 | match self.parse_token_tree() { | |
4555 | TokenTree::Delimited(_, ref delimited) => delimited.stream(), | |
4556 | _ => unreachable!(), | |
4557 | } | |
4558 | } else if self.check(&token::OpenDelim(token::Paren)) { | |
4559 | let args = self.parse_token_tree(); | |
4560 | let body = if self.check(&token::OpenDelim(token::Brace)) { | |
4561 | self.parse_token_tree() | |
4562 | } else { | |
4563 | self.unexpected()?; | |
4564 | unreachable!() | |
4565 | }; | |
4566 | TokenStream::concat(vec![ | |
4567 | args.into(), | |
ea8adc8c | 4568 | TokenTree::Token(token_lo.to(self.prev_span), token::FatArrow).into(), |
7cac9316 XL |
4569 | body.into(), |
4570 | ]) | |
4571 | } else { | |
4572 | self.unexpected()?; | |
4573 | unreachable!() | |
4574 | }; | |
4575 | ||
4576 | (ident, ast::MacroDef { tokens: tokens.into(), legacy: false }) | |
4577 | } | |
0531ce1d | 4578 | token::Ident(ident, _) if ident.name == "macro_rules" && |
7cac9316 XL |
4579 | self.look_ahead(1, |t| *t == token::Not) => { |
4580 | let prev_span = self.prev_span; | |
0531ce1d | 4581 | self.complain_if_pub_macro(&vis.node, prev_span); |
7cac9316 XL |
4582 | self.bump(); |
4583 | self.bump(); | |
4584 | ||
4585 | let ident = self.parse_ident()?; | |
4586 | let (delim, tokens) = self.expect_delimited_token_tree()?; | |
94b46f34 | 4587 | if delim != MacDelimiter::Brace { |
7cac9316 XL |
4588 | if !self.eat(&token::Semi) { |
4589 | let msg = "macros that expand to items must either \ | |
4590 | be surrounded with braces or followed by a semicolon"; | |
4591 | self.span_err(self.prev_span, msg); | |
4592 | } | |
8bb4bdeb | 4593 | } |
7cac9316 XL |
4594 | |
4595 | (ident, ast::MacroDef { tokens: tokens, legacy: true }) | |
8bb4bdeb XL |
4596 | } |
4597 | _ => return Ok(None), | |
4598 | }; | |
4599 | ||
cc61c64b | 4600 | let span = lo.to(self.prev_span); |
7cac9316 | 4601 | Ok(Some(self.mk_item(span, ident, ItemKind::MacroDef(def), vis.clone(), attrs.to_vec()))) |
8bb4bdeb XL |
4602 | } |
4603 | ||
9e0c209e SL |
4604 | fn parse_stmt_without_recovery(&mut self, |
4605 | macro_legacy_warnings: bool) | |
4606 | -> PResult<'a, Option<Stmt>> { | |
c30ab7b3 | 4607 | maybe_whole!(self, NtStmt, |x| Some(x)); |
223e47cc | 4608 | |
54a0048b | 4609 | let attrs = self.parse_outer_attributes()?; |
cc61c64b | 4610 | let lo = self.span; |
c34b1796 | 4611 | |
3157f602 XL |
4612 | Ok(Some(if self.eat_keyword(keywords::Let) { |
4613 | Stmt { | |
4614 | id: ast::DUMMY_NODE_ID, | |
4615 | node: StmtKind::Local(self.parse_local(attrs.into())?), | |
cc61c64b | 4616 | span: lo.to(self.prev_span), |
3157f602 | 4617 | } |
0531ce1d XL |
4618 | } else if let Some(macro_def) = self.eat_macro_def( |
4619 | &attrs, | |
b7449926 | 4620 | &source_map::respan(lo, VisibilityKind::Inherited), |
0531ce1d XL |
4621 | lo, |
4622 | )? { | |
8bb4bdeb XL |
4623 | Stmt { |
4624 | id: ast::DUMMY_NODE_ID, | |
4625 | node: StmtKind::Item(macro_def), | |
cc61c64b | 4626 | span: lo.to(self.prev_span), |
8bb4bdeb | 4627 | } |
2c00a5a8 XL |
4628 | // Starts like a simple path, being careful to avoid contextual keywords |
4629 | // such as a union items, item with `crate` visibility or auto trait items. | |
ff7c6d11 XL |
4630 | // Our goal here is to parse an arbitrary path `a::b::c` but not something that starts |
4631 | // like a path (1 token), but it fact not a path. | |
4632 | // `union::b::c` - path, `union U { ... }` - not a path. | |
4633 | // `crate::b::c` - path, `crate struct S;` - not a path. | |
2c00a5a8 | 4634 | // `extern::b::c` - path, `extern crate c;` - not a path. |
c30ab7b3 SL |
4635 | } else if self.token.is_path_start() && |
4636 | !self.token.is_qpath_start() && | |
ff7c6d11 | 4637 | !self.is_union_item() && |
2c00a5a8 XL |
4638 | !self.is_crate_vis() && |
4639 | !self.is_extern_non_path() && | |
8faf50e0 | 4640 | !self.is_existential_type_decl() && |
2c00a5a8 | 4641 | !self.is_auto_trait_item() { |
9e0c209e | 4642 | let pth = self.parse_path(PathStyle::Expr)?; |
1a4d82fc | 4643 | |
9e0c209e SL |
4644 | if !self.eat(&token::Not) { |
4645 | let expr = if self.check(&token::OpenDelim(token::Brace)) { | |
4646 | self.parse_struct_expr(lo, pth, ThinVec::new())? | |
4647 | } else { | |
cc61c64b XL |
4648 | let hi = self.prev_span; |
4649 | self.mk_expr(lo.to(hi), ExprKind::Path(None, pth), ThinVec::new()) | |
9e0c209e SL |
4650 | }; |
4651 | ||
ea8adc8c | 4652 | let expr = self.with_res(Restrictions::STMT_EXPR, |this| { |
9e0c209e SL |
4653 | let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs.into())?; |
4654 | this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr)) | |
4655 | })?; | |
223e47cc | 4656 | |
9e0c209e SL |
4657 | return Ok(Some(Stmt { |
4658 | id: ast::DUMMY_NODE_ID, | |
4659 | node: StmtKind::Expr(expr), | |
cc61c64b | 4660 | span: lo.to(self.prev_span), |
9e0c209e SL |
4661 | })); |
4662 | } | |
4663 | ||
4664 | // it's a macro invocation | |
1a4d82fc | 4665 | let id = match self.token { |
a7813a04 | 4666 | token::OpenDelim(_) => keywords::Invalid.ident(), // no special identifier |
54a0048b | 4667 | _ => self.parse_ident()?, |
1a4d82fc JJ |
4668 | }; |
4669 | ||
4670 | // check that we're pointing at delimiters (need to check | |
4671 | // again after the `if`, because of `parse_ident` | |
4672 | // consuming more tokens). | |
94b46f34 XL |
4673 | match self.token { |
4674 | token::OpenDelim(_) => {} | |
1a4d82fc JJ |
4675 | _ => { |
4676 | // we only expect an ident if we didn't parse one | |
4677 | // above. | |
a7813a04 | 4678 | let ident_str = if id.name == keywords::Invalid.name() { |
1a4d82fc JJ |
4679 | "identifier, " |
4680 | } else { | |
4681 | "" | |
4682 | }; | |
4683 | let tok_str = self.this_token_to_string(); | |
0531ce1d XL |
4684 | let mut err = self.fatal(&format!("expected {}`(` or `{{`, found `{}`", |
4685 | ident_str, | |
4686 | tok_str)); | |
4687 | err.span_label(self.span, format!("expected {}`(` or `{{`", ident_str)); | |
4688 | return Err(err) | |
1a4d82fc | 4689 | }, |
94b46f34 | 4690 | } |
223e47cc | 4691 | |
94b46f34 | 4692 | let (delim, tts) = self.expect_delimited_token_tree()?; |
cc61c64b | 4693 | let hi = self.prev_span; |
223e47cc | 4694 | |
94b46f34 | 4695 | let style = if delim == MacDelimiter::Brace { |
7453a54e | 4696 | MacStmtStyle::Braces |
1a4d82fc | 4697 | } else { |
7453a54e | 4698 | MacStmtStyle::NoBraces |
1a4d82fc JJ |
4699 | }; |
4700 | ||
a7813a04 | 4701 | if id.name == keywords::Invalid.name() { |
94b46f34 XL |
4702 | let mac = respan(lo.to(hi), Mac_ { path: pth, tts, delim }); |
4703 | let node = if delim == MacDelimiter::Brace || | |
5bcae85e SL |
4704 | self.token == token::Semi || self.token == token::Eof { |
4705 | StmtKind::Mac(P((mac, style, attrs.into()))) | |
4706 | } | |
4707 | // We used to incorrectly stop parsing macro-expanded statements here. | |
4708 | // If the next token will be an error anyway but could have parsed with the | |
4709 | // earlier behavior, stop parsing here and emit a warning to avoid breakage. | |
9e0c209e | 4710 | else if macro_legacy_warnings && self.token.can_begin_expr() && match self.token { |
5bcae85e SL |
4711 | // These can continue an expression, so we can't stop parsing and warn. |
4712 | token::OpenDelim(token::Paren) | token::OpenDelim(token::Bracket) | | |
4713 | token::BinOp(token::Minus) | token::BinOp(token::Star) | | |
4714 | token::BinOp(token::And) | token::BinOp(token::Or) | | |
4715 | token::AndAnd | token::OrOr | | |
ea8adc8c | 4716 | token::DotDot | token::DotDotDot | token::DotDotEq => false, |
5bcae85e SL |
4717 | _ => true, |
4718 | } { | |
4719 | self.warn_missing_semicolon(); | |
4720 | StmtKind::Mac(P((mac, style, attrs.into()))) | |
4721 | } else { | |
cc61c64b | 4722 | let e = self.mk_mac_expr(lo.to(hi), mac.node, ThinVec::new()); |
5bcae85e SL |
4723 | let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?; |
4724 | let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?; | |
4725 | StmtKind::Expr(e) | |
4726 | }; | |
3157f602 XL |
4727 | Stmt { |
4728 | id: ast::DUMMY_NODE_ID, | |
cc61c64b | 4729 | span: lo.to(hi), |
3b2f2976 | 4730 | node, |
3157f602 | 4731 | } |
223e47cc LB |
4732 | } else { |
4733 | // if it has a special ident, it's definitely an item | |
1a4d82fc JJ |
4734 | // |
4735 | // Require a semicolon or braces. | |
7453a54e | 4736 | if style != MacStmtStyle::Braces { |
9cc50fc6 | 4737 | if !self.eat(&token::Semi) { |
c30ab7b3 | 4738 | self.span_err(self.prev_span, |
1a4d82fc JJ |
4739 | "macros that expand to items must \ |
4740 | either be surrounded with braces or \ | |
4741 | followed by a semicolon"); | |
4742 | } | |
4743 | } | |
cc61c64b | 4744 | let span = lo.to(hi); |
3157f602 XL |
4745 | Stmt { |
4746 | id: ast::DUMMY_NODE_ID, | |
3b2f2976 | 4747 | span, |
3157f602 | 4748 | node: StmtKind::Item({ |
223e47cc | 4749 | self.mk_item( |
cc61c64b | 4750 | span, id /*id is good here*/, |
94b46f34 | 4751 | ItemKind::Mac(respan(span, Mac_ { path: pth, tts, delim })), |
0531ce1d | 4752 | respan(lo, VisibilityKind::Inherited), |
3157f602 XL |
4753 | attrs) |
4754 | }), | |
4755 | } | |
223e47cc | 4756 | } |
223e47cc | 4757 | } else { |
92a42be0 | 4758 | // FIXME: Bad copy of attrs |
476ff2be SL |
4759 | let old_directory_ownership = |
4760 | mem::replace(&mut self.directory.ownership, DirectoryOwnership::UnownedViaBlock); | |
4761 | let item = self.parse_item_(attrs.clone(), false, true)?; | |
4762 | self.directory.ownership = old_directory_ownership; | |
7cac9316 | 4763 | |
476ff2be | 4764 | match item { |
3157f602 XL |
4765 | Some(i) => Stmt { |
4766 | id: ast::DUMMY_NODE_ID, | |
cc61c64b | 4767 | span: lo.to(i.span), |
3157f602 XL |
4768 | node: StmtKind::Item(i), |
4769 | }, | |
c34b1796 | 4770 | None => { |
abe05a73 | 4771 | let unused_attrs = |attrs: &[Attribute], s: &mut Self| { |
7cac9316 | 4772 | if !attrs.is_empty() { |
c30ab7b3 | 4773 | if s.prev_token_kind == PrevTokenKind::DocComment { |
8bb4bdeb | 4774 | s.span_fatal_err(s.prev_span, Error::UselessDocComment).emit(); |
abe05a73 | 4775 | } else if attrs.iter().any(|a| a.style == AttrStyle::Outer) { |
9e0c209e SL |
4776 | s.span_err(s.span, "expected statement after outer attribute"); |
4777 | } | |
92a42be0 SL |
4778 | } |
4779 | }; | |
4780 | ||
c34b1796 AL |
4781 | // Do not attempt to parse an expression if we're done here. |
4782 | if self.token == token::Semi { | |
92a42be0 | 4783 | unused_attrs(&attrs, self); |
9cc50fc6 | 4784 | self.bump(); |
9346a6ac | 4785 | return Ok(None); |
c34b1796 AL |
4786 | } |
4787 | ||
4788 | if self.token == token::CloseDelim(token::Brace) { | |
92a42be0 | 4789 | unused_attrs(&attrs, self); |
9346a6ac | 4790 | return Ok(None); |
1a4d82fc | 4791 | } |
223e47cc | 4792 | |
1a4d82fc | 4793 | // Remainder are line-expr stmts. |
54a0048b | 4794 | let e = self.parse_expr_res( |
ea8adc8c | 4795 | Restrictions::STMT_EXPR, Some(attrs.into()))?; |
3157f602 XL |
4796 | Stmt { |
4797 | id: ast::DUMMY_NODE_ID, | |
cc61c64b | 4798 | span: lo.to(e.span), |
3157f602 XL |
4799 | node: StmtKind::Expr(e), |
4800 | } | |
1a4d82fc JJ |
4801 | } |
4802 | } | |
9346a6ac | 4803 | })) |
223e47cc LB |
4804 | } |
4805 | ||
1a4d82fc JJ |
4806 | /// Is this expression a successfully-parsed statement? |
4807 | fn expr_is_complete(&mut self, e: &Expr) -> bool { | |
ea8adc8c | 4808 | self.restrictions.contains(Restrictions::STMT_EXPR) && |
1a4d82fc | 4809 | !classify::expr_requires_semi_to_be_stmt(e) |
223e47cc LB |
4810 | } |
4811 | ||
1a4d82fc | 4812 | /// Parse a block. No inner attrs are allowed. |
9cc50fc6 | 4813 | pub fn parse_block(&mut self) -> PResult<'a, P<Block>> { |
c30ab7b3 | 4814 | maybe_whole!(self, NtBlock, |x| x); |
970d7e83 | 4815 | |
cc61c64b | 4816 | let lo = self.span; |
1a4d82fc | 4817 | |
9cc50fc6 | 4818 | if !self.eat(&token::OpenDelim(token::Brace)) { |
1a4d82fc JJ |
4819 | let sp = self.span; |
4820 | let tok = self.this_token_to_string(); | |
9e0c209e | 4821 | let mut e = self.span_fatal(sp, &format!("expected `{{`, found `{}`", tok)); |
0bf4aa26 XL |
4822 | let do_not_suggest_help = |
4823 | self.token.is_keyword(keywords::In) || self.token == token::Colon; | |
b7449926 XL |
4824 | |
4825 | if self.token.is_ident_named("and") { | |
4826 | e.span_suggestion_short_with_applicability( | |
4827 | self.span, | |
4828 | "use `&&` instead of `and` for the boolean operator", | |
4829 | "&&".to_string(), | |
4830 | Applicability::MaybeIncorrect, | |
4831 | ); | |
4832 | } | |
4833 | if self.token.is_ident_named("or") { | |
4834 | e.span_suggestion_short_with_applicability( | |
4835 | self.span, | |
4836 | "use `||` instead of `or` for the boolean operator", | |
4837 | "||".to_string(), | |
4838 | Applicability::MaybeIncorrect, | |
4839 | ); | |
4840 | } | |
9e0c209e SL |
4841 | |
4842 | // Check to see if the user has written something like | |
4843 | // | |
4844 | // if (cond) | |
4845 | // bar; | |
4846 | // | |
4847 | // Which is valid in other languages, but not Rust. | |
4848 | match self.parse_stmt_without_recovery(false) { | |
4849 | Ok(Some(stmt)) => { | |
b7449926 XL |
4850 | if self.look_ahead(1, |t| t == &token::OpenDelim(token::Brace)) |
4851 | || do_not_suggest_help { | |
83c7162d XL |
4852 | // if the next token is an open brace (e.g., `if a b {`), the place- |
4853 | // inside-a-block suggestion would be more likely wrong than right | |
0bf4aa26 | 4854 | e.span_label(sp, "expected `{`"); |
83c7162d XL |
4855 | return Err(e); |
4856 | } | |
9e0c209e SL |
4857 | let mut stmt_span = stmt.span; |
4858 | // expand the span to include the semicolon, if it exists | |
4859 | if self.eat(&token::Semi) { | |
ea8adc8c | 4860 | stmt_span = stmt_span.with_hi(self.prev_span.hi()); |
9e0c209e | 4861 | } |
8bb4bdeb XL |
4862 | let sugg = pprust::to_string(|s| { |
4863 | use print::pprust::{PrintState, INDENT_UNIT}; | |
4864 | s.ibox(INDENT_UNIT)?; | |
4865 | s.bopen()?; | |
4866 | s.print_stmt(&stmt)?; | |
4867 | s.bclose_maybe_open(stmt.span, INDENT_UNIT, false) | |
4868 | }); | |
94b46f34 XL |
4869 | e.span_suggestion_with_applicability( |
4870 | stmt_span, | |
4871 | "try placing this code inside a block", | |
4872 | sugg, | |
4873 | // speculative, has been misleading in the past (closed Issue #46836) | |
4874 | Applicability::MaybeIncorrect | |
4875 | ); | |
9e0c209e SL |
4876 | } |
4877 | Err(mut e) => { | |
cc61c64b | 4878 | self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); |
9e0c209e SL |
4879 | self.cancel(&mut e); |
4880 | } | |
4881 | _ => () | |
4882 | } | |
4883 | return Err(e); | |
970d7e83 | 4884 | } |
970d7e83 | 4885 | |
7453a54e | 4886 | self.parse_block_tail(lo, BlockCheckMode::Default) |
223e47cc LB |
4887 | } |
4888 | ||
1a4d82fc | 4889 | /// Parse a block. Inner attrs are allowed. |
9cc50fc6 | 4890 | fn parse_inner_attrs_and_block(&mut self) -> PResult<'a, (Vec<Attribute>, P<Block>)> { |
c30ab7b3 | 4891 | maybe_whole!(self, NtBlock, |x| (Vec::new(), x)); |
223e47cc | 4892 | |
cc61c64b | 4893 | let lo = self.span; |
54a0048b SL |
4894 | self.expect(&token::OpenDelim(token::Brace))?; |
4895 | Ok((self.parse_inner_attributes()?, | |
4896 | self.parse_block_tail(lo, BlockCheckMode::Default)?)) | |
223e47cc LB |
4897 | } |
4898 | ||
c34b1796 | 4899 | /// Parse the rest of a block expression or function body |
85aaf69f | 4900 | /// Precondition: already parsed the '{'. |
cc61c64b | 4901 | fn parse_block_tail(&mut self, lo: Span, s: BlockCheckMode) -> PResult<'a, P<Block>> { |
85aaf69f | 4902 | let mut stmts = vec![]; |
ff7c6d11 | 4903 | let mut recovered = false; |
223e47cc | 4904 | |
9cc50fc6 | 4905 | while !self.eat(&token::CloseDelim(token::Brace)) { |
ff7c6d11 XL |
4906 | let stmt = match self.parse_full_stmt(false) { |
4907 | Err(mut err) => { | |
4908 | err.emit(); | |
4909 | self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore); | |
4910 | self.eat(&token::CloseDelim(token::Brace)); | |
4911 | recovered = true; | |
4912 | break; | |
4913 | } | |
4914 | Ok(stmt) => stmt, | |
4915 | }; | |
4916 | if let Some(stmt) = stmt { | |
5bcae85e | 4917 | stmts.push(stmt); |
7453a54e SL |
4918 | } else if self.token == token::Eof { |
4919 | break; | |
c34b1796 AL |
4920 | } else { |
4921 | // Found only `;` or `}`. | |
4922 | continue; | |
4923 | }; | |
970d7e83 | 4924 | } |
9346a6ac | 4925 | Ok(P(ast::Block { |
3b2f2976 | 4926 | stmts, |
1a4d82fc | 4927 | id: ast::DUMMY_NODE_ID, |
223e47cc | 4928 | rules: s, |
cc61c64b | 4929 | span: lo.to(self.prev_span), |
ff7c6d11 | 4930 | recovered, |
9346a6ac | 4931 | })) |
223e47cc LB |
4932 | } |
4933 | ||
5bcae85e | 4934 | /// Parse a statement, including the trailing semicolon. |
94b46f34 | 4935 | crate fn parse_full_stmt(&mut self, macro_legacy_warnings: bool) -> PResult<'a, Option<Stmt>> { |
0531ce1d XL |
4936 | // skip looking for a trailing semicolon when we have an interpolated statement |
4937 | maybe_whole!(self, NtStmt, |x| Some(x)); | |
4938 | ||
ff7c6d11 | 4939 | let mut stmt = match self.parse_stmt_without_recovery(macro_legacy_warnings)? { |
5bcae85e SL |
4940 | Some(stmt) => stmt, |
4941 | None => return Ok(None), | |
4942 | }; | |
4943 | ||
4944 | match stmt.node { | |
4945 | StmtKind::Expr(ref expr) if self.token != token::Eof => { | |
4946 | // expression without semicolon | |
4947 | if classify::expr_requires_semi_to_be_stmt(expr) { | |
4948 | // Just check for errors and recover; do not eat semicolon yet. | |
4949 | if let Err(mut e) = | |
4950 | self.expect_one_of(&[], &[token::Semi, token::CloseDelim(token::Brace)]) | |
4951 | { | |
4952 | e.emit(); | |
4953 | self.recover_stmt(); | |
4954 | } | |
3157f602 XL |
4955 | } |
4956 | } | |
5bcae85e SL |
4957 | StmtKind::Local(..) => { |
4958 | // We used to incorrectly allow a macro-expanded let statement to lack a semicolon. | |
9e0c209e | 4959 | if macro_legacy_warnings && self.token != token::Semi { |
5bcae85e SL |
4960 | self.warn_missing_semicolon(); |
4961 | } else { | |
8faf50e0 | 4962 | self.expect_one_of(&[], &[token::Semi])?; |
3157f602 XL |
4963 | } |
4964 | } | |
5bcae85e | 4965 | _ => {} |
3157f602 | 4966 | } |
3157f602 | 4967 | |
5bcae85e SL |
4968 | if self.eat(&token::Semi) { |
4969 | stmt = stmt.add_trailing_semicolon(); | |
223e47cc | 4970 | } |
223e47cc | 4971 | |
ea8adc8c | 4972 | stmt.span = stmt.span.with_hi(self.prev_span.hi()); |
5bcae85e SL |
4973 | Ok(Some(stmt)) |
4974 | } | |
4975 | ||
4976 | fn warn_missing_semicolon(&self) { | |
4977 | self.diagnostic().struct_span_warn(self.span, { | |
4978 | &format!("expected `;`, found `{}`", self.this_token_to_string()) | |
4979 | }).note({ | |
4980 | "This was erroneously allowed and will become a hard error in a future release" | |
4981 | }).emit(); | |
223e47cc LB |
4982 | } |
4983 | ||
abe05a73 XL |
4984 | fn err_dotdotdot_syntax(&self, span: Span) { |
4985 | self.diagnostic().struct_span_err(span, { | |
8faf50e0 XL |
4986 | "unexpected token: `...`" |
4987 | }).span_suggestion_with_applicability( | |
4988 | span, "use `..` for an exclusive range", "..".to_owned(), | |
4989 | Applicability::MaybeIncorrect | |
4990 | ).span_suggestion_with_applicability( | |
4991 | span, "or `..=` for an inclusive range", "..=".to_owned(), | |
4992 | Applicability::MaybeIncorrect | |
4993 | ).emit(); | |
ea8adc8c XL |
4994 | } |
4995 | ||
cc61c64b | 4996 | // Parse bounds of a type parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`. |
32a655c1 SL |
4997 | // BOUND = TY_BOUND | LT_BOUND |
4998 | // LT_BOUND = LIFETIME (e.g. `'a`) | |
cc61c64b XL |
4999 | // TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN) |
5000 | // TY_BOUND_NOPAREN = [?] [for<LT_PARAM_DEFS>] SIMPLE_PATH (e.g. `?for<'a: 'b> m::Trait<'a>`) | |
8faf50e0 | 5001 | fn parse_generic_bounds_common(&mut self, allow_plus: bool) -> PResult<'a, GenericBounds> { |
32a655c1 | 5002 | let mut bounds = Vec::new(); |
223e47cc | 5003 | loop { |
b7449926 | 5004 | // This needs to be synchronized with `Token::can_begin_bound`. |
cc61c64b XL |
5005 | let is_bound_start = self.check_path() || self.check_lifetime() || |
5006 | self.check(&token::Question) || | |
5007 | self.check_keyword(keywords::For) || | |
5008 | self.check(&token::OpenDelim(token::Paren)); | |
5009 | if is_bound_start { | |
94b46f34 | 5010 | let lo = self.span; |
cc61c64b XL |
5011 | let has_parens = self.eat(&token::OpenDelim(token::Paren)); |
5012 | let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None }; | |
5013 | if self.token.is_lifetime() { | |
5014 | if let Some(question_span) = question { | |
5015 | self.span_err(question_span, | |
5016 | "`?` may only modify trait bounds, not lifetime bounds"); | |
5017 | } | |
8faf50e0 | 5018 | bounds.push(GenericBound::Outlives(self.expect_lifetime())); |
94b46f34 XL |
5019 | if has_parens { |
5020 | self.expect(&token::CloseDelim(token::Paren))?; | |
5021 | self.span_err(self.prev_span, | |
5022 | "parenthesized lifetime bounds are not supported"); | |
5023 | } | |
32a655c1 | 5024 | } else { |
cc61c64b XL |
5025 | let lifetime_defs = self.parse_late_bound_lifetime_defs()?; |
5026 | let path = self.parse_path(PathStyle::Type)?; | |
94b46f34 XL |
5027 | if has_parens { |
5028 | self.expect(&token::CloseDelim(token::Paren))?; | |
5029 | } | |
cc61c64b XL |
5030 | let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span)); |
5031 | let modifier = if question.is_some() { | |
5032 | TraitBoundModifier::Maybe | |
5033 | } else { | |
5034 | TraitBoundModifier::None | |
5035 | }; | |
8faf50e0 | 5036 | bounds.push(GenericBound::Trait(poly_trait, modifier)); |
cc61c64b | 5037 | } |
32a655c1 SL |
5038 | } else { |
5039 | break | |
cc61c64b | 5040 | } |
223e47cc | 5041 | |
94b46f34 | 5042 | if !allow_plus || !self.eat_plus() { |
32a655c1 | 5043 | break |
223e47cc LB |
5044 | } |
5045 | } | |
5046 | ||
32a655c1 SL |
5047 | return Ok(bounds); |
5048 | } | |
5049 | ||
8faf50e0 XL |
5050 | fn parse_generic_bounds(&mut self) -> PResult<'a, GenericBounds> { |
5051 | self.parse_generic_bounds_common(true) | |
cc61c64b XL |
5052 | } |
5053 | ||
5054 | // Parse bounds of a lifetime parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`. | |
32a655c1 | 5055 | // BOUND = LT_BOUND (e.g. `'a`) |
8faf50e0 | 5056 | fn parse_lt_param_bounds(&mut self) -> GenericBounds { |
32a655c1 | 5057 | let mut lifetimes = Vec::new(); |
cc61c64b | 5058 | while self.check_lifetime() { |
8faf50e0 | 5059 | lifetimes.push(ast::GenericBound::Outlives(self.expect_lifetime())); |
32a655c1 | 5060 | |
94b46f34 | 5061 | if !self.eat_plus() { |
32a655c1 SL |
5062 | break |
5063 | } | |
5064 | } | |
5065 | lifetimes | |
223e47cc LB |
5066 | } |
5067 | ||
c34b1796 | 5068 | /// Matches typaram = IDENT (`?` unbound)? optbounds ( EQ ty )? |
8faf50e0 XL |
5069 | fn parse_ty_param(&mut self, |
5070 | preceding_attrs: Vec<Attribute>) | |
5071 | -> PResult<'a, GenericParam> { | |
54a0048b | 5072 | let ident = self.parse_ident()?; |
1a4d82fc | 5073 | |
32a655c1 SL |
5074 | // Parse optional colon and param bounds. |
5075 | let bounds = if self.eat(&token::Colon) { | |
8faf50e0 | 5076 | self.parse_generic_bounds()? |
32a655c1 SL |
5077 | } else { |
5078 | Vec::new() | |
5079 | }; | |
1a4d82fc | 5080 | |
32a655c1 SL |
5081 | let default = if self.eat(&token::Eq) { |
5082 | Some(self.parse_ty()?) | |
c34b1796 AL |
5083 | } else { |
5084 | None | |
5085 | }; | |
1a4d82fc | 5086 | |
8faf50e0 | 5087 | Ok(GenericParam { |
3b2f2976 | 5088 | ident, |
1a4d82fc | 5089 | id: ast::DUMMY_NODE_ID, |
8faf50e0 | 5090 | attrs: preceding_attrs.into(), |
3b2f2976 | 5091 | bounds, |
8faf50e0 XL |
5092 | kind: GenericParamKind::Type { |
5093 | default, | |
5094 | } | |
9346a6ac | 5095 | }) |
1a4d82fc JJ |
5096 | } |
5097 | ||
ff7c6d11 | 5098 | /// Parses the following grammar: |
8faf50e0 XL |
5099 | /// TraitItemAssocTy = Ident ["<"...">"] [":" [GenericBounds]] ["where" ...] ["=" Ty] |
5100 | fn parse_trait_item_assoc_ty(&mut self) | |
5101 | -> PResult<'a, (Ident, TraitItemKind, ast::Generics)> { | |
ff7c6d11 XL |
5102 | let ident = self.parse_ident()?; |
5103 | let mut generics = self.parse_generics()?; | |
5104 | ||
5105 | // Parse optional colon and param bounds. | |
5106 | let bounds = if self.eat(&token::Colon) { | |
8faf50e0 | 5107 | self.parse_generic_bounds()? |
ff7c6d11 XL |
5108 | } else { |
5109 | Vec::new() | |
5110 | }; | |
5111 | generics.where_clause = self.parse_where_clause()?; | |
5112 | ||
5113 | let default = if self.eat(&token::Eq) { | |
5114 | Some(self.parse_ty()?) | |
5115 | } else { | |
5116 | None | |
5117 | }; | |
5118 | self.expect(&token::Semi)?; | |
5119 | ||
8faf50e0 | 5120 | Ok((ident, TraitItemKind::Type(bounds, default), generics)) |
ff7c6d11 XL |
5121 | } |
5122 | ||
32a655c1 SL |
5123 | /// Parses (possibly empty) list of lifetime and type parameters, possibly including |
5124 | /// trailing comma and erroneous trailing attributes. | |
94b46f34 | 5125 | crate fn parse_generic_params(&mut self) -> PResult<'a, Vec<ast::GenericParam>> { |
ff7c6d11 | 5126 | let mut params = Vec::new(); |
32a655c1 SL |
5127 | let mut seen_ty_param = false; |
5128 | loop { | |
5129 | let attrs = self.parse_outer_attributes()?; | |
cc61c64b XL |
5130 | if self.check_lifetime() { |
5131 | let lifetime = self.expect_lifetime(); | |
32a655c1 SL |
5132 | // Parse lifetime parameter. |
5133 | let bounds = if self.eat(&token::Colon) { | |
5134 | self.parse_lt_param_bounds() | |
5135 | } else { | |
5136 | Vec::new() | |
5137 | }; | |
8faf50e0 XL |
5138 | params.push(ast::GenericParam { |
5139 | ident: lifetime.ident, | |
5140 | id: lifetime.id, | |
32a655c1 | 5141 | attrs: attrs.into(), |
3b2f2976 | 5142 | bounds, |
8faf50e0 XL |
5143 | kind: ast::GenericParamKind::Lifetime, |
5144 | }); | |
32a655c1 SL |
5145 | if seen_ty_param { |
5146 | self.span_err(self.prev_span, | |
5147 | "lifetime parameters must be declared prior to type parameters"); | |
5148 | } | |
cc61c64b | 5149 | } else if self.check_ident() { |
32a655c1 | 5150 | // Parse type parameter. |
8faf50e0 | 5151 | params.push(self.parse_ty_param(attrs)?); |
32a655c1 SL |
5152 | seen_ty_param = true; |
5153 | } else { | |
5154 | // Check for trailing attributes and stop parsing. | |
5155 | if !attrs.is_empty() { | |
5156 | let param_kind = if seen_ty_param { "type" } else { "lifetime" }; | |
5157 | self.span_err(attrs[0].span, | |
5158 | &format!("trailing attribute after {} parameters", param_kind)); | |
5159 | } | |
5160 | break | |
cc61c64b | 5161 | } |
32a655c1 SL |
5162 | |
5163 | if !self.eat(&token::Comma) { | |
5164 | break | |
5165 | } | |
5166 | } | |
ff7c6d11 | 5167 | Ok(params) |
32a655c1 SL |
5168 | } |
5169 | ||
1a4d82fc JJ |
5170 | /// Parse a set of optional generic type parameter declarations. Where |
5171 | /// clauses are not parsed here, and must be added later via | |
5172 | /// `parse_where_clause()`. | |
5173 | /// | |
5174 | /// matches generics = ( ) | ( < > ) | ( < typaramseq ( , )? > ) | ( < lifetimes ( , )? > ) | |
5175 | /// | ( < lifetimes , typaramseq ( , )? > ) | |
5176 | /// where typaramseq = ( typaram ) | ( typaram , typaramseq ) | |
94b46f34 | 5177 | fn parse_generics(&mut self) -> PResult<'a, ast::Generics> { |
c30ab7b3 | 5178 | maybe_whole!(self, NtGenerics, |x| x); |
d9579d0f | 5179 | |
cc61c64b | 5180 | let span_lo = self.span; |
32a655c1 | 5181 | if self.eat_lt() { |
ff7c6d11 | 5182 | let params = self.parse_generic_params()?; |
32a655c1 | 5183 | self.expect_gt()?; |
9346a6ac | 5184 | Ok(ast::Generics { |
ff7c6d11 | 5185 | params, |
1a4d82fc JJ |
5186 | where_clause: WhereClause { |
5187 | id: ast::DUMMY_NODE_ID, | |
5188 | predicates: Vec::new(), | |
3b2f2976 | 5189 | span: syntax_pos::DUMMY_SP, |
9e0c209e | 5190 | }, |
cc61c64b | 5191 | span: span_lo.to(self.prev_span), |
9346a6ac | 5192 | }) |
223e47cc | 5193 | } else { |
9cc50fc6 | 5194 | Ok(ast::Generics::default()) |
223e47cc LB |
5195 | } |
5196 | } | |
5197 | ||
32a655c1 SL |
5198 | /// Parses (possibly empty) list of lifetime and type arguments and associated type bindings, |
5199 | /// possibly including trailing comma. | |
8faf50e0 XL |
5200 | fn parse_generic_args(&mut self) |
5201 | -> PResult<'a, (Vec<GenericArg>, Vec<TypeBinding>)> { | |
5202 | let mut args = Vec::new(); | |
32a655c1 SL |
5203 | let mut bindings = Vec::new(); |
5204 | let mut seen_type = false; | |
5205 | let mut seen_binding = false; | |
5206 | loop { | |
94b46f34 | 5207 | if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) { |
32a655c1 | 5208 | // Parse lifetime argument. |
8faf50e0 | 5209 | args.push(GenericArg::Lifetime(self.expect_lifetime())); |
32a655c1 SL |
5210 | if seen_type || seen_binding { |
5211 | self.span_err(self.prev_span, | |
5212 | "lifetime parameters must be declared prior to type parameters"); | |
1a4d82fc | 5213 | } |
cc61c64b | 5214 | } else if self.check_ident() && self.look_ahead(1, |t| t == &token::Eq) { |
32a655c1 | 5215 | // Parse associated type binding. |
cc61c64b | 5216 | let lo = self.span; |
32a655c1 SL |
5217 | let ident = self.parse_ident()?; |
5218 | self.bump(); | |
5219 | let ty = self.parse_ty()?; | |
5220 | bindings.push(TypeBinding { | |
5221 | id: ast::DUMMY_NODE_ID, | |
3b2f2976 XL |
5222 | ident, |
5223 | ty, | |
cc61c64b | 5224 | span: lo.to(self.prev_span), |
7453a54e | 5225 | }); |
32a655c1 SL |
5226 | seen_binding = true; |
5227 | } else if self.check_type() { | |
5228 | // Parse type argument. | |
8faf50e0 | 5229 | let ty_param = self.parse_ty()?; |
32a655c1 | 5230 | if seen_binding { |
8faf50e0 | 5231 | self.span_err(ty_param.span, |
32a655c1 SL |
5232 | "type parameters must be declared prior to associated type bindings"); |
5233 | } | |
8faf50e0 | 5234 | args.push(GenericArg::Type(ty_param)); |
32a655c1 SL |
5235 | seen_type = true; |
5236 | } else { | |
5237 | break | |
cc61c64b | 5238 | } |
1a4d82fc | 5239 | |
32a655c1 SL |
5240 | if !self.eat(&token::Comma) { |
5241 | break | |
5242 | } | |
223e47cc | 5243 | } |
8faf50e0 | 5244 | Ok((args, bindings)) |
223e47cc LB |
5245 | } |
5246 | ||
1a4d82fc JJ |
5247 | /// Parses an optional `where` clause and places it in `generics`. |
5248 | /// | |
041b39d2 | 5249 | /// ```ignore (only-for-syntax-highlight) |
1a4d82fc JJ |
5250 | /// where T : Trait<U, V> + 'b, 'a : 'b |
5251 | /// ``` | |
94b46f34 | 5252 | fn parse_where_clause(&mut self) -> PResult<'a, WhereClause> { |
c30ab7b3 | 5253 | maybe_whole!(self, NtWhereClause, |x| x); |
d9579d0f | 5254 | |
c34b1796 AL |
5255 | let mut where_clause = WhereClause { |
5256 | id: ast::DUMMY_NODE_ID, | |
5257 | predicates: Vec::new(), | |
3b2f2976 | 5258 | span: syntax_pos::DUMMY_SP, |
c34b1796 AL |
5259 | }; |
5260 | ||
9cc50fc6 | 5261 | if !self.eat_keyword(keywords::Where) { |
9346a6ac | 5262 | return Ok(where_clause); |
1a4d82fc | 5263 | } |
3b2f2976 | 5264 | let lo = self.prev_span; |
1a4d82fc | 5265 | |
476ff2be SL |
5266 | // We are considering adding generics to the `where` keyword as an alternative higher-rank |
5267 | // parameter syntax (as in `where<'a>` or `where<T>`. To avoid that being a breaking | |
2c00a5a8 XL |
5268 | // change we parse those generics now, but report an error. |
5269 | if self.choose_generics_over_qpath() { | |
5270 | let generics = self.parse_generics()?; | |
5271 | self.span_err(generics.span, | |
5272 | "generic parameters on `where` clauses are reserved for future use"); | |
476ff2be SL |
5273 | } |
5274 | ||
1a4d82fc | 5275 | loop { |
cc61c64b | 5276 | let lo = self.span; |
94b46f34 | 5277 | if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) { |
cc61c64b | 5278 | let lifetime = self.expect_lifetime(); |
32a655c1 SL |
5279 | // Bounds starting with a colon are mandatory, but possibly empty. |
5280 | self.expect(&token::Colon)?; | |
5281 | let bounds = self.parse_lt_param_bounds(); | |
5282 | where_clause.predicates.push(ast::WherePredicate::RegionPredicate( | |
5283 | ast::WhereRegionPredicate { | |
cc61c64b | 5284 | span: lo.to(self.prev_span), |
3b2f2976 XL |
5285 | lifetime, |
5286 | bounds, | |
32a655c1 SL |
5287 | } |
5288 | )); | |
cc61c64b | 5289 | } else if self.check_type() { |
32a655c1 SL |
5290 | // Parse optional `for<'a, 'b>`. |
5291 | // This `for` is parsed greedily and applies to the whole predicate, | |
5292 | // the bounded type can have its own `for` applying only to it. | |
5293 | // Example 1: for<'a> Trait1<'a>: Trait2<'a /*ok*/> | |
5294 | // Example 2: (for<'a> Trait1<'a>): Trait2<'a /*not ok*/> | |
5295 | // Example 3: for<'a> for<'b> Trait1<'a, 'b>: Trait2<'a /*ok*/, 'b /*not ok*/> | |
5296 | let lifetime_defs = self.parse_late_bound_lifetime_defs()?; | |
5297 | ||
5298 | // Parse type with mandatory colon and (possibly empty) bounds, | |
5299 | // or with mandatory equality sign and the second type. | |
5300 | let ty = self.parse_ty()?; | |
5301 | if self.eat(&token::Colon) { | |
8faf50e0 | 5302 | let bounds = self.parse_generic_bounds()?; |
32a655c1 SL |
5303 | where_clause.predicates.push(ast::WherePredicate::BoundPredicate( |
5304 | ast::WhereBoundPredicate { | |
cc61c64b | 5305 | span: lo.to(self.prev_span), |
ff7c6d11 | 5306 | bound_generic_params: lifetime_defs, |
32a655c1 | 5307 | bounded_ty: ty, |
3b2f2976 | 5308 | bounds, |
1a4d82fc JJ |
5309 | } |
5310 | )); | |
32a655c1 | 5311 | // FIXME: Decide what should be used here, `=` or `==`. |
0531ce1d | 5312 | // FIXME: We are just dropping the binders in lifetime_defs on the floor here. |
32a655c1 SL |
5313 | } else if self.eat(&token::Eq) || self.eat(&token::EqEq) { |
5314 | let rhs_ty = self.parse_ty()?; | |
5315 | where_clause.predicates.push(ast::WherePredicate::EqPredicate( | |
5316 | ast::WhereEqPredicate { | |
cc61c64b | 5317 | span: lo.to(self.prev_span), |
32a655c1 | 5318 | lhs_ty: ty, |
3b2f2976 | 5319 | rhs_ty, |
32a655c1 | 5320 | id: ast::DUMMY_NODE_ID, |
1a4d82fc | 5321 | } |
32a655c1 SL |
5322 | )); |
5323 | } else { | |
5324 | return self.unexpected(); | |
1a4d82fc | 5325 | } |
32a655c1 SL |
5326 | } else { |
5327 | break | |
cc61c64b | 5328 | } |
1a4d82fc | 5329 | |
9cc50fc6 | 5330 | if !self.eat(&token::Comma) { |
1a4d82fc JJ |
5331 | break |
5332 | } | |
5333 | } | |
5334 | ||
3b2f2976 | 5335 | where_clause.span = lo.to(self.prev_span); |
9346a6ac | 5336 | Ok(where_clause) |
223e47cc LB |
5337 | } |
5338 | ||
1a4d82fc | 5339 | fn parse_fn_args(&mut self, named_args: bool, allow_variadic: bool) |
9cc50fc6 | 5340 | -> PResult<'a, (Vec<Arg> , bool)> { |
1a4d82fc | 5341 | let sp = self.span; |
7453a54e SL |
5342 | let mut variadic = false; |
5343 | let args: Vec<Option<Arg>> = | |
54a0048b | 5344 | self.parse_unspanned_seq( |
1a4d82fc JJ |
5345 | &token::OpenDelim(token::Paren), |
5346 | &token::CloseDelim(token::Paren), | |
7453a54e | 5347 | SeqSep::trailing_allowed(token::Comma), |
1a4d82fc JJ |
5348 | |p| { |
5349 | if p.token == token::DotDotDot { | |
9cc50fc6 | 5350 | p.bump(); |
0531ce1d | 5351 | variadic = true; |
1a4d82fc JJ |
5352 | if allow_variadic { |
5353 | if p.token != token::CloseDelim(token::Paren) { | |
5354 | let span = p.span; | |
7453a54e SL |
5355 | p.span_err(span, |
5356 | "`...` must be last in argument list for variadic function"); | |
1a4d82fc | 5357 | } |
0531ce1d | 5358 | Ok(None) |
1a4d82fc | 5359 | } else { |
0531ce1d XL |
5360 | let span = p.prev_span; |
5361 | if p.token == token::CloseDelim(token::Paren) { | |
5362 | // continue parsing to present any further errors | |
5363 | p.struct_span_err( | |
5364 | span, | |
5365 | "only foreign functions are allowed to be variadic" | |
5366 | ).emit(); | |
5367 | Ok(Some(dummy_arg(span))) | |
5368 | } else { | |
5369 | // this function definition looks beyond recovery, stop parsing | |
5370 | p.span_err(span, | |
5371 | "only foreign functions are allowed to be variadic"); | |
5372 | Ok(None) | |
5373 | } | |
1a4d82fc | 5374 | } |
1a4d82fc | 5375 | } else { |
7453a54e SL |
5376 | match p.parse_arg_general(named_args) { |
5377 | Ok(arg) => Ok(Some(arg)), | |
5378 | Err(mut e) => { | |
5379 | e.emit(); | |
cc61c64b XL |
5380 | let lo = p.prev_span; |
5381 | // Skip every token until next possible arg or end. | |
7453a54e | 5382 | p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]); |
cc61c64b XL |
5383 | // Create a placeholder argument for proper arg count (#34264). |
5384 | let span = lo.to(p.prev_span); | |
5385 | Ok(Some(dummy_arg(span))) | |
7453a54e SL |
5386 | } |
5387 | } | |
1a4d82fc JJ |
5388 | } |
5389 | } | |
54a0048b | 5390 | )?; |
223e47cc | 5391 | |
7453a54e | 5392 | let args: Vec<_> = args.into_iter().filter_map(|x| x).collect(); |
223e47cc | 5393 | |
1a4d82fc JJ |
5394 | if variadic && args.is_empty() { |
5395 | self.span_err(sp, | |
5396 | "variadic function must be declared with at least one named argument"); | |
223e47cc | 5397 | } |
1a4d82fc | 5398 | |
9346a6ac | 5399 | Ok((args, variadic)) |
223e47cc LB |
5400 | } |
5401 | ||
1a4d82fc | 5402 | /// Parse the argument list and result type of a function declaration |
94b46f34 | 5403 | fn parse_fn_decl(&mut self, allow_variadic: bool) -> PResult<'a, P<FnDecl>> { |
1a4d82fc | 5404 | |
54a0048b | 5405 | let (args, variadic) = self.parse_fn_args(true, allow_variadic)?; |
2c00a5a8 | 5406 | let ret_ty = self.parse_ret_ty(true)?; |
1a4d82fc | 5407 | |
9346a6ac | 5408 | Ok(P(FnDecl { |
1a4d82fc JJ |
5409 | inputs: args, |
5410 | output: ret_ty, | |
3b2f2976 | 5411 | variadic, |
9346a6ac | 5412 | })) |
223e47cc LB |
5413 | } |
5414 | ||
3157f602 XL |
5415 | /// Returns the parsed optional self argument and whether a self shortcut was used. |
5416 | fn parse_self_arg(&mut self) -> PResult<'a, Option<Arg>> { | |
a7813a04 | 5417 | let expect_ident = |this: &mut Self| match this.token { |
3157f602 | 5418 | // Preserve hygienic context. |
83c7162d XL |
5419 | token::Ident(ident, _) => |
5420 | { let span = this.span; this.bump(); Ident::new(ident.name, span) } | |
a7813a04 XL |
5421 | _ => unreachable!() |
5422 | }; | |
c30ab7b3 SL |
5423 | let isolated_self = |this: &mut Self, n| { |
5424 | this.look_ahead(n, |t| t.is_keyword(keywords::SelfValue)) && | |
5425 | this.look_ahead(n + 1, |t| t != &token::ModSep) | |
5426 | }; | |
223e47cc | 5427 | |
a7813a04 XL |
5428 | // Parse optional self parameter of a method. |
5429 | // Only a limited set of initial token sequences is considered self parameters, anything | |
5430 | // else is parsed as a normal function parameter list, so some lookahead is required. | |
cc61c64b | 5431 | let eself_lo = self.span; |
94b46f34 | 5432 | let (eself, eself_ident, eself_hi) = match self.token { |
1a4d82fc | 5433 | token::BinOp(token::And) => { |
a7813a04 XL |
5434 | // &self |
5435 | // &mut self | |
5436 | // &'lt self | |
5437 | // &'lt mut self | |
5438 | // ¬_self | |
94b46f34 | 5439 | (if isolated_self(self, 1) { |
a7813a04 | 5440 | self.bump(); |
94b46f34 | 5441 | SelfKind::Region(None, Mutability::Immutable) |
a7813a04 | 5442 | } else if self.look_ahead(1, |t| t.is_keyword(keywords::Mut)) && |
c30ab7b3 | 5443 | isolated_self(self, 2) { |
a7813a04 XL |
5444 | self.bump(); |
5445 | self.bump(); | |
94b46f34 | 5446 | SelfKind::Region(None, Mutability::Mutable) |
a7813a04 | 5447 | } else if self.look_ahead(1, |t| t.is_lifetime()) && |
c30ab7b3 | 5448 | isolated_self(self, 2) { |
a7813a04 | 5449 | self.bump(); |
cc61c64b | 5450 | let lt = self.expect_lifetime(); |
94b46f34 | 5451 | SelfKind::Region(Some(lt), Mutability::Immutable) |
a7813a04 XL |
5452 | } else if self.look_ahead(1, |t| t.is_lifetime()) && |
5453 | self.look_ahead(2, |t| t.is_keyword(keywords::Mut)) && | |
c30ab7b3 | 5454 | isolated_self(self, 3) { |
a7813a04 | 5455 | self.bump(); |
cc61c64b | 5456 | let lt = self.expect_lifetime(); |
a7813a04 | 5457 | self.bump(); |
94b46f34 | 5458 | SelfKind::Region(Some(lt), Mutability::Mutable) |
a7813a04 | 5459 | } else { |
3157f602 | 5460 | return Ok(None); |
94b46f34 | 5461 | }, expect_ident(self), self.prev_span) |
1a4d82fc | 5462 | } |
1a4d82fc | 5463 | token::BinOp(token::Star) => { |
a7813a04 XL |
5464 | // *self |
5465 | // *const self | |
5466 | // *mut self | |
5467 | // *not_self | |
5468 | // Emit special error for `self` cases. | |
94b46f34 | 5469 | (if isolated_self(self, 1) { |
a7813a04 XL |
5470 | self.bump(); |
5471 | self.span_err(self.span, "cannot pass `self` by raw pointer"); | |
94b46f34 | 5472 | SelfKind::Value(Mutability::Immutable) |
a7813a04 | 5473 | } else if self.look_ahead(1, |t| t.is_mutability()) && |
c30ab7b3 | 5474 | isolated_self(self, 2) { |
9cc50fc6 | 5475 | self.bump(); |
a7813a04 XL |
5476 | self.bump(); |
5477 | self.span_err(self.span, "cannot pass `self` by raw pointer"); | |
94b46f34 | 5478 | SelfKind::Value(Mutability::Immutable) |
a7813a04 | 5479 | } else { |
3157f602 | 5480 | return Ok(None); |
94b46f34 | 5481 | }, expect_ident(self), self.prev_span) |
1a4d82fc JJ |
5482 | } |
5483 | token::Ident(..) => { | |
c30ab7b3 | 5484 | if isolated_self(self, 0) { |
a7813a04 XL |
5485 | // self |
5486 | // self: TYPE | |
5487 | let eself_ident = expect_ident(self); | |
94b46f34 XL |
5488 | let eself_hi = self.prev_span; |
5489 | (if self.eat(&token::Colon) { | |
32a655c1 | 5490 | let ty = self.parse_ty()?; |
94b46f34 | 5491 | SelfKind::Explicit(ty, Mutability::Immutable) |
1a4d82fc | 5492 | } else { |
94b46f34 XL |
5493 | SelfKind::Value(Mutability::Immutable) |
5494 | }, eself_ident, eself_hi) | |
a7813a04 | 5495 | } else if self.token.is_keyword(keywords::Mut) && |
c30ab7b3 | 5496 | isolated_self(self, 1) { |
a7813a04 XL |
5497 | // mut self |
5498 | // mut self: TYPE | |
a7813a04 XL |
5499 | self.bump(); |
5500 | let eself_ident = expect_ident(self); | |
94b46f34 XL |
5501 | let eself_hi = self.prev_span; |
5502 | (if self.eat(&token::Colon) { | |
32a655c1 | 5503 | let ty = self.parse_ty()?; |
94b46f34 | 5504 | SelfKind::Explicit(ty, Mutability::Mutable) |
1a4d82fc | 5505 | } else { |
94b46f34 XL |
5506 | SelfKind::Value(Mutability::Mutable) |
5507 | }, eself_ident, eself_hi) | |
1a4d82fc | 5508 | } else { |
3157f602 | 5509 | return Ok(None); |
1a4d82fc JJ |
5510 | } |
5511 | } | |
3157f602 | 5512 | _ => return Ok(None), |
223e47cc | 5513 | }; |
3157f602 | 5514 | |
b7449926 | 5515 | let eself = source_map::respan(eself_lo.to(eself_hi), eself); |
3157f602 XL |
5516 | Ok(Some(Arg::from_self(eself, eself_ident))) |
5517 | } | |
5518 | ||
5519 | /// Parse the parameter list and result type of a function that may have a `self` parameter. | |
5520 | fn parse_fn_decl_with_self<F>(&mut self, parse_arg_fn: F) -> PResult<'a, P<FnDecl>> | |
5521 | where F: FnMut(&mut Parser<'a>) -> PResult<'a, Arg>, | |
5522 | { | |
5523 | self.expect(&token::OpenDelim(token::Paren))?; | |
5524 | ||
5525 | // Parse optional self argument | |
5526 | let self_arg = self.parse_self_arg()?; | |
223e47cc | 5527 | |
a7813a04 XL |
5528 | // Parse the rest of the function parameter list. |
5529 | let sep = SeqSep::trailing_allowed(token::Comma); | |
3157f602 XL |
5530 | let fn_inputs = if let Some(self_arg) = self_arg { |
5531 | if self.check(&token::CloseDelim(token::Paren)) { | |
5532 | vec![self_arg] | |
5533 | } else if self.eat(&token::Comma) { | |
5534 | let mut fn_inputs = vec![self_arg]; | |
5535 | fn_inputs.append(&mut self.parse_seq_to_before_end( | |
abe05a73 | 5536 | &token::CloseDelim(token::Paren), sep, parse_arg_fn)? |
3157f602 XL |
5537 | ); |
5538 | fn_inputs | |
5539 | } else { | |
5540 | return self.unexpected(); | |
7453a54e | 5541 | } |
3157f602 | 5542 | } else { |
abe05a73 | 5543 | self.parse_seq_to_before_end(&token::CloseDelim(token::Paren), sep, parse_arg_fn)? |
1a4d82fc JJ |
5544 | }; |
5545 | ||
a7813a04 | 5546 | // Parse closing paren and return type. |
54a0048b | 5547 | self.expect(&token::CloseDelim(token::Paren))?; |
3157f602 | 5548 | Ok(P(FnDecl { |
1a4d82fc | 5549 | inputs: fn_inputs, |
2c00a5a8 | 5550 | output: self.parse_ret_ty(true)?, |
1a4d82fc | 5551 | variadic: false |
3157f602 | 5552 | })) |
223e47cc LB |
5553 | } |
5554 | ||
970d7e83 | 5555 | // parse the |arg, arg| header on a lambda |
9cc50fc6 | 5556 | fn parse_fn_block_decl(&mut self) -> PResult<'a, P<FnDecl>> { |
85aaf69f | 5557 | let inputs_captures = { |
9cc50fc6 | 5558 | if self.eat(&token::OrOr) { |
85aaf69f | 5559 | Vec::new() |
223e47cc | 5560 | } else { |
54a0048b | 5561 | self.expect(&token::BinOp(token::Or))?; |
ea8adc8c XL |
5562 | let args = self.parse_seq_to_before_tokens( |
5563 | &[&token::BinOp(token::Or), &token::OrOr], | |
7453a54e | 5564 | SeqSep::trailing_allowed(token::Comma), |
ea8adc8c | 5565 | TokenExpectType::NoExpect, |
abe05a73 XL |
5566 | |p| p.parse_fn_block_arg() |
5567 | )?; | |
ea8adc8c | 5568 | self.expect_or()?; |
85aaf69f | 5569 | args |
223e47cc LB |
5570 | } |
5571 | }; | |
2c00a5a8 | 5572 | let output = self.parse_ret_ty(true)?; |
223e47cc | 5573 | |
9346a6ac | 5574 | Ok(P(FnDecl { |
1a4d82fc | 5575 | inputs: inputs_captures, |
3b2f2976 | 5576 | output, |
1a4d82fc | 5577 | variadic: false |
9346a6ac | 5578 | })) |
1a4d82fc JJ |
5579 | } |
5580 | ||
1a4d82fc | 5581 | /// Parse the name and optional generic types of a function header. |
9cc50fc6 | 5582 | fn parse_fn_header(&mut self) -> PResult<'a, (Ident, ast::Generics)> { |
54a0048b SL |
5583 | let id = self.parse_ident()?; |
5584 | let generics = self.parse_generics()?; | |
9346a6ac | 5585 | Ok((id, generics)) |
223e47cc LB |
5586 | } |
5587 | ||
cc61c64b | 5588 | fn mk_item(&mut self, span: Span, ident: Ident, node: ItemKind, vis: Visibility, |
1a4d82fc JJ |
5589 | attrs: Vec<Attribute>) -> P<Item> { |
5590 | P(Item { | |
3b2f2976 XL |
5591 | ident, |
5592 | attrs, | |
1a4d82fc | 5593 | id: ast::DUMMY_NODE_ID, |
3b2f2976 XL |
5594 | node, |
5595 | vis, | |
5596 | span, | |
5597 | tokens: None, | |
1a4d82fc | 5598 | }) |
223e47cc LB |
5599 | } |
5600 | ||
1a4d82fc | 5601 | /// Parse an item-position function declaration. |
62682a34 SL |
5602 | fn parse_item_fn(&mut self, |
5603 | unsafety: Unsafety, | |
8faf50e0 | 5604 | asyncness: IsAsync, |
9e0c209e | 5605 | constness: Spanned<Constness>, |
2c00a5a8 | 5606 | abi: Abi) |
9cc50fc6 | 5607 | -> PResult<'a, ItemInfo> { |
54a0048b SL |
5608 | let (ident, mut generics) = self.parse_fn_header()?; |
5609 | let decl = self.parse_fn_decl(false)?; | |
5610 | generics.where_clause = self.parse_where_clause()?; | |
5611 | let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; | |
8faf50e0 XL |
5612 | let header = FnHeader { unsafety, asyncness, constness, abi }; |
5613 | Ok((ident, ItemKind::Fn(decl, header, generics, body), Some(inner_attrs))) | |
62682a34 SL |
5614 | } |
5615 | ||
5616 | /// true if we are looking at `const ID`, false for things like `const fn` etc | |
94b46f34 | 5617 | fn is_const_item(&mut self) -> bool { |
62682a34 | 5618 | self.token.is_keyword(keywords::Const) && |
b039eaaf SL |
5619 | !self.look_ahead(1, |t| t.is_keyword(keywords::Fn)) && |
5620 | !self.look_ahead(1, |t| t.is_keyword(keywords::Unsafe)) | |
62682a34 SL |
5621 | } |
5622 | ||
5623 | /// parses all the "front matter" for a `fn` declaration, up to | |
5624 | /// and including the `fn` keyword: | |
5625 | /// | |
5626 | /// - `const fn` | |
5627 | /// - `unsafe fn` | |
b039eaaf | 5628 | /// - `const unsafe fn` |
62682a34 SL |
5629 | /// - `extern fn` |
5630 | /// - etc | |
8faf50e0 XL |
5631 | fn parse_fn_front_matter(&mut self) |
5632 | -> PResult<'a, ( | |
5633 | Spanned<Constness>, | |
5634 | Unsafety, | |
5635 | IsAsync, | |
5636 | Abi | |
5637 | )> | |
5638 | { | |
9cc50fc6 | 5639 | let is_const_fn = self.eat_keyword(keywords::Const); |
c30ab7b3 | 5640 | let const_span = self.prev_span; |
2c00a5a8 | 5641 | let unsafety = self.parse_unsafety(); |
8faf50e0 | 5642 | let asyncness = self.parse_asyncness(); |
62682a34 | 5643 | let (constness, unsafety, abi) = if is_const_fn { |
9e0c209e | 5644 | (respan(const_span, Constness::Const), unsafety, Abi::Rust) |
62682a34 | 5645 | } else { |
9cc50fc6 | 5646 | let abi = if self.eat_keyword(keywords::Extern) { |
54a0048b | 5647 | self.parse_opt_abi()?.unwrap_or(Abi::C) |
62682a34 | 5648 | } else { |
7453a54e | 5649 | Abi::Rust |
62682a34 | 5650 | }; |
c30ab7b3 | 5651 | (respan(self.prev_span, Constness::NotConst), unsafety, abi) |
62682a34 | 5652 | }; |
54a0048b | 5653 | self.expect_keyword(keywords::Fn)?; |
8faf50e0 | 5654 | Ok((constness, unsafety, asyncness, abi)) |
223e47cc LB |
5655 | } |
5656 | ||
c34b1796 | 5657 | /// Parse an impl item. |
8faf50e0 | 5658 | pub fn parse_impl_item(&mut self, at_end: &mut bool) -> PResult<'a, ImplItem> { |
c30ab7b3 | 5659 | maybe_whole!(self, NtImplItem, |x| x); |
3b2f2976 XL |
5660 | let attrs = self.parse_outer_attributes()?; |
5661 | let (mut item, tokens) = self.collect_tokens(|this| { | |
5662 | this.parse_impl_item_(at_end, attrs) | |
5663 | })?; | |
5664 | ||
5665 | // See `parse_item` for why this clause is here. | |
5666 | if !item.attrs.iter().any(|attr| attr.style == AttrStyle::Inner) { | |
5667 | item.tokens = Some(tokens); | |
5668 | } | |
5669 | Ok(item) | |
5670 | } | |
d9579d0f | 5671 | |
3b2f2976 XL |
5672 | fn parse_impl_item_(&mut self, |
5673 | at_end: &mut bool, | |
5674 | mut attrs: Vec<Attribute>) -> PResult<'a, ImplItem> { | |
cc61c64b XL |
5675 | let lo = self.span; |
5676 | let vis = self.parse_visibility(false)?; | |
2c00a5a8 | 5677 | let defaultness = self.parse_defaultness(); |
8faf50e0 XL |
5678 | let (name, node, generics) = if let Some(type_) = self.eat_type() { |
5679 | let (name, alias, generics) = type_?; | |
5680 | let kind = match alias { | |
5681 | AliasKind::Weak(typ) => ast::ImplItemKind::Type(typ), | |
5682 | AliasKind::Existential(bounds) => ast::ImplItemKind::Existential(bounds), | |
5683 | }; | |
5684 | (name, kind, generics) | |
62682a34 | 5685 | } else if self.is_const_item() { |
ff7c6d11 XL |
5686 | // This parses the grammar: |
5687 | // ImplItemConst = "const" Ident ":" Ty "=" Expr ";" | |
54a0048b SL |
5688 | self.expect_keyword(keywords::Const)?; |
5689 | let name = self.parse_ident()?; | |
5690 | self.expect(&token::Colon)?; | |
32a655c1 | 5691 | let typ = self.parse_ty()?; |
54a0048b SL |
5692 | self.expect(&token::Eq)?; |
5693 | let expr = self.parse_expr()?; | |
5bcae85e | 5694 | self.expect(&token::Semi)?; |
abe05a73 | 5695 | (name, ast::ImplItemKind::Const(typ, expr), ast::Generics::default()) |
c34b1796 | 5696 | } else { |
abe05a73 | 5697 | let (name, inner_attrs, generics, node) = self.parse_impl_method(&vis, at_end)?; |
62682a34 | 5698 | attrs.extend(inner_attrs); |
abe05a73 | 5699 | (name, node, generics) |
c34b1796 AL |
5700 | }; |
5701 | ||
7453a54e | 5702 | Ok(ImplItem { |
c34b1796 | 5703 | id: ast::DUMMY_NODE_ID, |
cc61c64b | 5704 | span: lo.to(self.prev_span), |
c34b1796 | 5705 | ident: name, |
3b2f2976 XL |
5706 | vis, |
5707 | defaultness, | |
5708 | attrs, | |
abe05a73 | 5709 | generics, |
3b2f2976 XL |
5710 | node, |
5711 | tokens: None, | |
7453a54e | 5712 | }) |
1a4d82fc JJ |
5713 | } |
5714 | ||
0531ce1d | 5715 | fn complain_if_pub_macro(&mut self, vis: &VisibilityKind, sp: Span) { |
cc61c64b XL |
5716 | if let Err(mut err) = self.complain_if_pub_macro_diag(vis, sp) { |
5717 | err.emit(); | |
5718 | } | |
5719 | } | |
5720 | ||
0531ce1d | 5721 | fn complain_if_pub_macro_diag(&mut self, vis: &VisibilityKind, sp: Span) -> PResult<'a, ()> { |
cc61c64b | 5722 | match *vis { |
0531ce1d | 5723 | VisibilityKind::Inherited => Ok(()), |
54a0048b | 5724 | _ => { |
9cc50fc6 | 5725 | let is_macro_rules: bool = match self.token { |
0531ce1d | 5726 | token::Ident(sid, _) => sid.name == Symbol::intern("macro_rules"), |
9cc50fc6 SL |
5727 | _ => false, |
5728 | }; | |
5729 | if is_macro_rules { | |
cc61c64b XL |
5730 | let mut err = self.diagnostic() |
5731 | .struct_span_err(sp, "can't qualify macro_rules invocation with `pub`"); | |
94b46f34 XL |
5732 | err.span_suggestion_with_applicability( |
5733 | sp, | |
5734 | "try exporting the macro", | |
5735 | "#[macro_export]".to_owned(), | |
5736 | Applicability::MaybeIncorrect // speculative | |
5737 | ); | |
cc61c64b | 5738 | Err(err) |
9cc50fc6 | 5739 | } else { |
cc61c64b XL |
5740 | let mut err = self.diagnostic() |
5741 | .struct_span_err(sp, "can't qualify macro invocation with `pub`"); | |
5742 | err.help("try adjusting the macro to put `pub` inside the invocation"); | |
5743 | Err(err) | |
9cc50fc6 | 5744 | } |
85aaf69f | 5745 | } |
85aaf69f SL |
5746 | } |
5747 | } | |
5748 | ||
cc61c64b XL |
5749 | fn missing_assoc_item_kind_err(&mut self, item_type: &str, prev_span: Span) |
5750 | -> DiagnosticBuilder<'a> | |
5751 | { | |
83c7162d XL |
5752 | let expected_kinds = if item_type == "extern" { |
5753 | "missing `fn`, `type`, or `static`" | |
5754 | } else { | |
5755 | "missing `fn`, `type`, or `const`" | |
5756 | }; | |
5757 | ||
cc61c64b XL |
5758 | // Given this code `path(`, it seems like this is not |
5759 | // setting the visibility of a macro invocation, but rather | |
5760 | // a mistyped method declaration. | |
5761 | // Create a diagnostic pointing out that `fn` is missing. | |
5762 | // | |
5763 | // x | pub path(&self) { | |
5764 | // | ^ missing `fn`, `type`, or `const` | |
5765 | // pub path( | |
5766 | // ^^ `sp` below will point to this | |
5767 | let sp = prev_span.between(self.prev_span); | |
5768 | let mut err = self.diagnostic().struct_span_err( | |
5769 | sp, | |
83c7162d XL |
5770 | &format!("{} for {}-item declaration", |
5771 | expected_kinds, item_type)); | |
5772 | err.span_label(sp, expected_kinds); | |
cc61c64b XL |
5773 | err |
5774 | } | |
5775 | ||
c34b1796 | 5776 | /// Parse a method or a macro invocation in a trait impl. |
cc61c64b | 5777 | fn parse_impl_method(&mut self, vis: &Visibility, at_end: &mut bool) |
2c00a5a8 | 5778 | -> PResult<'a, (Ident, Vec<Attribute>, ast::Generics, |
abe05a73 | 5779 | ast::ImplItemKind)> { |
1a4d82fc | 5780 | // code copied from parse_macro_use_or_failure... abstraction! |
83c7162d | 5781 | if let Some(mac) = self.parse_assoc_macro_invoc("impl", Some(vis), at_end)? { |
cc61c64b | 5782 | // Method macro. |
abe05a73 XL |
5783 | Ok((keywords::Invalid.ident(), vec![], ast::Generics::default(), |
5784 | ast::ImplItemKind::Macro(mac))) | |
c34b1796 | 5785 | } else { |
8faf50e0 | 5786 | let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?; |
54a0048b SL |
5787 | let ident = self.parse_ident()?; |
5788 | let mut generics = self.parse_generics()?; | |
3157f602 | 5789 | let decl = self.parse_fn_decl_with_self(|p| p.parse_arg())?; |
54a0048b | 5790 | generics.where_clause = self.parse_where_clause()?; |
cc61c64b | 5791 | *at_end = true; |
54a0048b | 5792 | let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; |
8faf50e0 XL |
5793 | let header = ast::FnHeader { abi, unsafety, constness, asyncness }; |
5794 | Ok((ident, inner_attrs, generics, ast::ImplItemKind::Method( | |
5795 | ast::MethodSig { header, decl }, | |
5796 | body | |
5797 | ))) | |
c34b1796 | 5798 | } |
223e47cc LB |
5799 | } |
5800 | ||
ff7c6d11 | 5801 | /// Parse `trait Foo { ... }` or `trait Foo = Bar;` |
abe05a73 | 5802 | fn parse_item_trait(&mut self, is_auto: IsAuto, unsafety: Unsafety) -> PResult<'a, ItemInfo> { |
54a0048b SL |
5803 | let ident = self.parse_ident()?; |
5804 | let mut tps = self.parse_generics()?; | |
1a4d82fc | 5805 | |
32a655c1 SL |
5806 | // Parse optional colon and supertrait bounds. |
5807 | let bounds = if self.eat(&token::Colon) { | |
8faf50e0 | 5808 | self.parse_generic_bounds()? |
32a655c1 SL |
5809 | } else { |
5810 | Vec::new() | |
5811 | }; | |
223e47cc | 5812 | |
ff7c6d11 XL |
5813 | if self.eat(&token::Eq) { |
5814 | // it's a trait alias | |
8faf50e0 | 5815 | let bounds = self.parse_generic_bounds()?; |
ff7c6d11 XL |
5816 | tps.where_clause = self.parse_where_clause()?; |
5817 | self.expect(&token::Semi)?; | |
5818 | if unsafety != Unsafety::Normal { | |
5819 | self.span_err(self.prev_span, "trait aliases cannot be unsafe"); | |
5820 | } | |
5821 | Ok((ident, ItemKind::TraitAlias(tps, bounds), None)) | |
5822 | } else { | |
5823 | // it's a normal trait | |
5824 | tps.where_clause = self.parse_where_clause()?; | |
5825 | self.expect(&token::OpenDelim(token::Brace))?; | |
5826 | let mut trait_items = vec![]; | |
5827 | while !self.eat(&token::CloseDelim(token::Brace)) { | |
5828 | let mut at_end = false; | |
5829 | match self.parse_trait_item(&mut at_end) { | |
5830 | Ok(item) => trait_items.push(item), | |
5831 | Err(mut e) => { | |
5832 | e.emit(); | |
5833 | if !at_end { | |
5834 | self.recover_stmt_(SemiColonMode::Break, BlockMode::Break); | |
5835 | } | |
cc61c64b XL |
5836 | } |
5837 | } | |
5838 | } | |
ff7c6d11 | 5839 | Ok((ident, ItemKind::Trait(is_auto, unsafety, tps, bounds, trait_items), None)) |
cc61c64b | 5840 | } |
223e47cc LB |
5841 | } |
5842 | ||
2c00a5a8 XL |
5843 | fn choose_generics_over_qpath(&self) -> bool { |
5844 | // There's an ambiguity between generic parameters and qualified paths in impls. | |
5845 | // If we see `<` it may start both, so we have to inspect some following tokens. | |
5846 | // The following combinations can only start generics, | |
5847 | // but not qualified paths (with one exception): | |
5848 | // `<` `>` - empty generic parameters | |
5849 | // `<` `#` - generic parameters with attributes | |
5850 | // `<` (LIFETIME|IDENT) `>` - single generic parameter | |
5851 | // `<` (LIFETIME|IDENT) `,` - first generic parameter in a list | |
5852 | // `<` (LIFETIME|IDENT) `:` - generic parameter with bounds | |
5853 | // `<` (LIFETIME|IDENT) `=` - generic parameter with a default | |
5854 | // The only truly ambiguous case is | |
5855 | // `<` IDENT `>` `::` IDENT ... | |
5856 | // we disambiguate it in favor of generics (`impl<T> ::absolute::Path<T> { ... }`) | |
5857 | // because this is what almost always expected in practice, qualified paths in impls | |
5858 | // (`impl <Type>::AssocTy { ... }`) aren't even allowed by type checker at the moment. | |
5859 | self.token == token::Lt && | |
5860 | (self.look_ahead(1, |t| t == &token::Pound || t == &token::Gt) || | |
5861 | self.look_ahead(1, |t| t.is_lifetime() || t.is_ident()) && | |
5862 | self.look_ahead(2, |t| t == &token::Gt || t == &token::Comma || | |
5863 | t == &token::Colon || t == &token::Eq)) | |
5864 | } | |
5865 | ||
5866 | fn parse_impl_body(&mut self) -> PResult<'a, (Vec<ImplItem>, Vec<Attribute>)> { | |
5867 | self.expect(&token::OpenDelim(token::Brace))?; | |
5868 | let attrs = self.parse_inner_attributes()?; | |
c34b1796 | 5869 | |
2c00a5a8 XL |
5870 | let mut impl_items = Vec::new(); |
5871 | while !self.eat(&token::CloseDelim(token::Brace)) { | |
5872 | let mut at_end = false; | |
5873 | match self.parse_impl_item(&mut at_end) { | |
5874 | Ok(impl_item) => impl_items.push(impl_item), | |
5875 | Err(mut err) => { | |
5876 | err.emit(); | |
5877 | if !at_end { | |
5878 | self.recover_stmt_(SemiColonMode::Break, BlockMode::Break); | |
5879 | } | |
5880 | } | |
5881 | } | |
5882 | } | |
5883 | Ok((impl_items, attrs)) | |
5884 | } | |
223e47cc | 5885 | |
2c00a5a8 XL |
5886 | /// Parses an implementation item, `impl` keyword is already parsed. |
5887 | /// impl<'a, T> TYPE { /* impl items */ } | |
5888 | /// impl<'a, T> TRAIT for TYPE { /* impl items */ } | |
5889 | /// impl<'a, T> !TRAIT for TYPE { /* impl items */ } | |
5890 | /// We actually parse slightly more relaxed grammar for better error reporting and recovery. | |
5891 | /// `impl` GENERICS `!`? TYPE `for`? (TYPE | `..`) (`where` PREDICATES)? `{` BODY `}` | |
5892 | /// `impl` GENERICS `!`? TYPE (`where` PREDICATES)? `{` BODY `}` | |
5893 | fn parse_item_impl(&mut self, unsafety: Unsafety, defaultness: Defaultness) | |
5894 | -> PResult<'a, ItemInfo> { | |
5895 | // First, parse generic parameters if necessary. | |
5896 | let mut generics = if self.choose_generics_over_qpath() { | |
5897 | self.parse_generics()? | |
5898 | } else { | |
5899 | ast::Generics::default() | |
5900 | }; | |
1a4d82fc | 5901 | |
2c00a5a8 XL |
5902 | // Disambiguate `impl !Trait for Type { ... }` and `impl ! { ... }` for the never type. |
5903 | let polarity = if self.check(&token::Not) && self.look_ahead(1, |t| t.can_begin_type()) { | |
5904 | self.bump(); // `!` | |
1a4d82fc JJ |
5905 | ast::ImplPolarity::Negative |
5906 | } else { | |
5907 | ast::ImplPolarity::Positive | |
5908 | }; | |
223e47cc | 5909 | |
2c00a5a8 XL |
5910 | // Parse both types and traits as a type, then reinterpret if necessary. |
5911 | let ty_first = self.parse_ty()?; | |
5912 | ||
5913 | // If `for` is missing we try to recover. | |
5914 | let has_for = self.eat_keyword(keywords::For); | |
5915 | let missing_for_span = self.prev_span.between(self.span); | |
5916 | ||
5917 | let ty_second = if self.token == token::DotDot { | |
5918 | // We need to report this error after `cfg` expansion for compatibility reasons | |
5919 | self.bump(); // `..`, do not add it to expected tokens | |
5920 | Some(P(Ty { node: TyKind::Err, span: self.prev_span, id: ast::DUMMY_NODE_ID })) | |
5921 | } else if has_for || self.token.can_begin_type() { | |
5922 | Some(self.parse_ty()?) | |
223e47cc LB |
5923 | } else { |
5924 | None | |
5925 | }; | |
5926 | ||
2c00a5a8 | 5927 | generics.where_clause = self.parse_where_clause()?; |
7cac9316 | 5928 | |
2c00a5a8 | 5929 | let (impl_items, attrs) = self.parse_impl_body()?; |
223e47cc | 5930 | |
2c00a5a8 XL |
5931 | let item_kind = match ty_second { |
5932 | Some(ty_second) => { | |
5933 | // impl Trait for Type | |
5934 | if !has_for { | |
5935 | self.span_err(missing_for_span, "missing `for` in a trait impl"); | |
5936 | } | |
c34b1796 | 5937 | |
2c00a5a8 XL |
5938 | let ty_first = ty_first.into_inner(); |
5939 | let path = match ty_first.node { | |
5940 | // This notably includes paths passed through `ty` macro fragments (#46438). | |
5941 | TyKind::Path(None, path) => path, | |
5942 | _ => { | |
5943 | self.span_err(ty_first.span, "expected a trait, found type"); | |
83c7162d | 5944 | ast::Path::from_ident(Ident::new(keywords::Invalid.name(), ty_first.span)) |
cc61c64b | 5945 | } |
2c00a5a8 XL |
5946 | }; |
5947 | let trait_ref = TraitRef { path, ref_id: ty_first.id }; | |
5948 | ||
5949 | ItemKind::Impl(unsafety, polarity, defaultness, | |
5950 | generics, Some(trait_ref), ty_second, impl_items) | |
c34b1796 | 5951 | } |
2c00a5a8 XL |
5952 | None => { |
5953 | // impl Type | |
5954 | ItemKind::Impl(unsafety, polarity, defaultness, | |
5955 | generics, None, ty_first, impl_items) | |
5956 | } | |
5957 | }; | |
c34b1796 | 5958 | |
2c00a5a8 | 5959 | Ok((keywords::Invalid.ident(), item_kind, Some(attrs))) |
1a4d82fc JJ |
5960 | } |
5961 | ||
ff7c6d11 | 5962 | fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec<GenericParam>> { |
9cc50fc6 | 5963 | if self.eat_keyword(keywords::For) { |
32a655c1 | 5964 | self.expect_lt()?; |
ff7c6d11 | 5965 | let params = self.parse_generic_params()?; |
54a0048b | 5966 | self.expect_gt()?; |
0531ce1d XL |
5967 | // We rely on AST validation to rule out invalid cases: There must not be type |
5968 | // parameters, and the lifetime parameters must not have bounds. | |
ff7c6d11 | 5969 | Ok(params) |
1a4d82fc | 5970 | } else { |
9346a6ac | 5971 | Ok(Vec::new()) |
223e47cc LB |
5972 | } |
5973 | } | |
5974 | ||
1a4d82fc | 5975 | /// Parse struct Foo { ... } |
9cc50fc6 | 5976 | fn parse_item_struct(&mut self) -> PResult<'a, ItemInfo> { |
54a0048b | 5977 | let class_name = self.parse_ident()?; |
cc61c64b | 5978 | |
54a0048b | 5979 | let mut generics = self.parse_generics()?; |
1a4d82fc | 5980 | |
1a4d82fc JJ |
5981 | // There is a special case worth noting here, as reported in issue #17904. |
5982 | // If we are parsing a tuple struct it is the case that the where clause | |
5983 | // should follow the field list. Like so: | |
5984 | // | |
5985 | // struct Foo<T>(T) where T: Copy; | |
5986 | // | |
5987 | // If we are parsing a normal record-style struct it is the case | |
5988 | // that the where clause comes before the body, and after the generics. | |
5989 | // So if we look ahead and see a brace or a where-clause we begin | |
5990 | // parsing a record style struct. | |
5991 | // | |
5992 | // Otherwise if we look ahead and see a paren we parse a tuple-style | |
5993 | // struct. | |
5994 | ||
b039eaaf | 5995 | let vdata = if self.token.is_keyword(keywords::Where) { |
54a0048b | 5996 | generics.where_clause = self.parse_where_clause()?; |
9cc50fc6 | 5997 | if self.eat(&token::Semi) { |
1a4d82fc | 5998 | // If we see a: `struct Foo<T> where T: Copy;` style decl. |
b039eaaf | 5999 | VariantData::Unit(ast::DUMMY_NODE_ID) |
1a4d82fc JJ |
6000 | } else { |
6001 | // If we see: `struct Foo<T> where T: Copy { ... }` | |
54a0048b | 6002 | VariantData::Struct(self.parse_record_struct_body()?, ast::DUMMY_NODE_ID) |
223e47cc | 6003 | } |
1a4d82fc | 6004 | // No `where` so: `struct Foo<T>;` |
9cc50fc6 | 6005 | } else if self.eat(&token::Semi) { |
b039eaaf | 6006 | VariantData::Unit(ast::DUMMY_NODE_ID) |
1a4d82fc JJ |
6007 | // Record-style struct definition |
6008 | } else if self.token == token::OpenDelim(token::Brace) { | |
54a0048b | 6009 | VariantData::Struct(self.parse_record_struct_body()?, ast::DUMMY_NODE_ID) |
1a4d82fc | 6010 | // Tuple-style struct definition with optional where-clause. |
e9174d1e | 6011 | } else if self.token == token::OpenDelim(token::Paren) { |
54a0048b SL |
6012 | let body = VariantData::Tuple(self.parse_tuple_struct_body()?, ast::DUMMY_NODE_ID); |
6013 | generics.where_clause = self.parse_where_clause()?; | |
6014 | self.expect(&token::Semi)?; | |
92a42be0 | 6015 | body |
e9174d1e SL |
6016 | } else { |
6017 | let token_str = self.this_token_to_string(); | |
0531ce1d XL |
6018 | let mut err = self.fatal(&format!( |
6019 | "expected `where`, `{{`, `(`, or `;` after struct name, found `{}`", | |
6020 | token_str | |
6021 | )); | |
6022 | err.span_label(self.span, "expected `where`, `{`, `(`, or `;` after struct name"); | |
6023 | return Err(err); | |
1a4d82fc | 6024 | }; |
223e47cc | 6025 | |
7453a54e | 6026 | Ok((class_name, ItemKind::Struct(vdata, generics), None)) |
223e47cc LB |
6027 | } |
6028 | ||
9e0c209e SL |
6029 | /// Parse union Foo { ... } |
6030 | fn parse_item_union(&mut self) -> PResult<'a, ItemInfo> { | |
6031 | let class_name = self.parse_ident()?; | |
cc61c64b | 6032 | |
9e0c209e SL |
6033 | let mut generics = self.parse_generics()?; |
6034 | ||
6035 | let vdata = if self.token.is_keyword(keywords::Where) { | |
6036 | generics.where_clause = self.parse_where_clause()?; | |
6037 | VariantData::Struct(self.parse_record_struct_body()?, ast::DUMMY_NODE_ID) | |
6038 | } else if self.token == token::OpenDelim(token::Brace) { | |
6039 | VariantData::Struct(self.parse_record_struct_body()?, ast::DUMMY_NODE_ID) | |
6040 | } else { | |
6041 | let token_str = self.this_token_to_string(); | |
0531ce1d XL |
6042 | let mut err = self.fatal(&format!( |
6043 | "expected `where` or `{{` after union name, found `{}`", token_str)); | |
6044 | err.span_label(self.span, "expected `where` or `{` after union name"); | |
6045 | return Err(err); | |
9e0c209e SL |
6046 | }; |
6047 | ||
6048 | Ok((class_name, ItemKind::Union(vdata, generics), None)) | |
6049 | } | |
6050 | ||
ff7c6d11 XL |
6051 | fn consume_block(&mut self, delim: token::DelimToken) { |
6052 | let mut brace_depth = 0; | |
6053 | if !self.eat(&token::OpenDelim(delim)) { | |
6054 | return; | |
6055 | } | |
6056 | loop { | |
6057 | if self.eat(&token::OpenDelim(delim)) { | |
6058 | brace_depth += 1; | |
6059 | } else if self.eat(&token::CloseDelim(delim)) { | |
6060 | if brace_depth == 0 { | |
6061 | return; | |
6062 | } else { | |
6063 | brace_depth -= 1; | |
6064 | continue; | |
6065 | } | |
6066 | } else if self.eat(&token::Eof) || self.eat(&token::CloseDelim(token::NoDelim)) { | |
6067 | return; | |
6068 | } else { | |
6069 | self.bump(); | |
6070 | } | |
6071 | } | |
6072 | } | |
6073 | ||
94b46f34 | 6074 | fn parse_record_struct_body(&mut self) -> PResult<'a, Vec<StructField>> { |
1a4d82fc | 6075 | let mut fields = Vec::new(); |
9cc50fc6 | 6076 | if self.eat(&token::OpenDelim(token::Brace)) { |
1a4d82fc | 6077 | while self.token != token::CloseDelim(token::Brace) { |
ff7c6d11 | 6078 | let field = self.parse_struct_decl_field().map_err(|e| { |
c30ab7b3 | 6079 | self.recover_stmt(); |
c30ab7b3 | 6080 | e |
ff7c6d11 XL |
6081 | }); |
6082 | match field { | |
6083 | Ok(field) => fields.push(field), | |
6084 | Err(mut err) => { | |
6085 | err.emit(); | |
6086 | } | |
6087 | } | |
1a4d82fc | 6088 | } |
ff7c6d11 | 6089 | self.eat(&token::CloseDelim(token::Brace)); |
1a4d82fc JJ |
6090 | } else { |
6091 | let token_str = self.this_token_to_string(); | |
0531ce1d XL |
6092 | let mut err = self.fatal(&format!( |
6093 | "expected `where`, or `{{` after struct name, found `{}`", token_str)); | |
6094 | err.span_label(self.span, "expected `where`, or `{` after struct name"); | |
6095 | return Err(err); | |
1a4d82fc JJ |
6096 | } |
6097 | ||
9346a6ac | 6098 | Ok(fields) |
1a4d82fc JJ |
6099 | } |
6100 | ||
94b46f34 | 6101 | fn parse_tuple_struct_body(&mut self) -> PResult<'a, Vec<StructField>> { |
1a4d82fc | 6102 | // This is the case where we find `struct Foo<T>(T) where T: Copy;` |
e9174d1e | 6103 | // Unit like structs are handled in parse_item_struct function |
54a0048b | 6104 | let fields = self.parse_unspanned_seq( |
e9174d1e SL |
6105 | &token::OpenDelim(token::Paren), |
6106 | &token::CloseDelim(token::Paren), | |
7453a54e | 6107 | SeqSep::trailing_allowed(token::Comma), |
e9174d1e | 6108 | |p| { |
54a0048b | 6109 | let attrs = p.parse_outer_attributes()?; |
cc61c64b XL |
6110 | let lo = p.span; |
6111 | let vis = p.parse_visibility(true)?; | |
6112 | let ty = p.parse_ty()?; | |
54a0048b | 6113 | Ok(StructField { |
94b46f34 | 6114 | span: lo.to(ty.span), |
3b2f2976 | 6115 | vis, |
54a0048b | 6116 | ident: None, |
e9174d1e | 6117 | id: ast::DUMMY_NODE_ID, |
3b2f2976 XL |
6118 | ty, |
6119 | attrs, | |
54a0048b SL |
6120 | }) |
6121 | })?; | |
223e47cc | 6122 | |
e9174d1e | 6123 | Ok(fields) |
1a4d82fc | 6124 | } |
223e47cc | 6125 | |
1a4d82fc | 6126 | /// Parse a structure field declaration |
94b46f34 | 6127 | fn parse_single_struct_field(&mut self, |
cc61c64b | 6128 | lo: Span, |
1a4d82fc JJ |
6129 | vis: Visibility, |
6130 | attrs: Vec<Attribute> ) | |
9cc50fc6 | 6131 | -> PResult<'a, StructField> { |
83c7162d | 6132 | let mut seen_comma: bool = false; |
5bcae85e | 6133 | let a_var = self.parse_name_and_ty(lo, vis, attrs)?; |
83c7162d XL |
6134 | if self.token == token::Comma { |
6135 | seen_comma = true; | |
6136 | } | |
1a4d82fc JJ |
6137 | match self.token { |
6138 | token::Comma => { | |
9cc50fc6 | 6139 | self.bump(); |
223e47cc | 6140 | } |
1a4d82fc | 6141 | token::CloseDelim(token::Brace) => {} |
ff7c6d11 | 6142 | token::DocComment(_) => { |
83c7162d | 6143 | let previous_span = self.prev_span; |
ff7c6d11 XL |
6144 | let mut err = self.span_fatal_err(self.span, Error::UselessDocComment); |
6145 | self.bump(); // consume the doc comment | |
83c7162d XL |
6146 | let comma_after_doc_seen = self.eat(&token::Comma); |
6147 | // `seen_comma` is always false, because we are inside doc block | |
6148 | // condition is here to make code more readable | |
6149 | if seen_comma == false && comma_after_doc_seen == true { | |
6150 | seen_comma = true; | |
6151 | } | |
6152 | if comma_after_doc_seen || self.token == token::CloseDelim(token::Brace) { | |
ff7c6d11 XL |
6153 | err.emit(); |
6154 | } else { | |
83c7162d | 6155 | if seen_comma == false { |
b7449926 | 6156 | let sp = self.sess.source_map().next_point(previous_span); |
94b46f34 XL |
6157 | err.span_suggestion_with_applicability( |
6158 | sp, | |
6159 | "missing comma here", | |
6160 | ",".into(), | |
6161 | Applicability::MachineApplicable | |
6162 | ); | |
83c7162d | 6163 | } |
ff7c6d11 XL |
6164 | return Err(err); |
6165 | } | |
6166 | } | |
94b46f34 | 6167 | _ => { |
b7449926 | 6168 | let sp = self.sess.source_map().next_point(self.prev_span); |
94b46f34 XL |
6169 | let mut err = self.struct_span_err(sp, &format!("expected `,`, or `}}`, found `{}`", |
6170 | self.this_token_to_string())); | |
6171 | if self.token.is_ident() { | |
6172 | // This is likely another field; emit the diagnostic and keep going | |
b7449926 XL |
6173 | err.span_suggestion_with_applicability( |
6174 | sp, | |
6175 | "try adding a comma", | |
6176 | ",".into(), | |
6177 | Applicability::MachineApplicable, | |
6178 | ); | |
94b46f34 XL |
6179 | err.emit(); |
6180 | } else { | |
6181 | return Err(err) | |
6182 | } | |
6183 | } | |
223e47cc | 6184 | } |
9346a6ac | 6185 | Ok(a_var) |
223e47cc LB |
6186 | } |
6187 | ||
1a4d82fc | 6188 | /// Parse an element of a struct definition |
54a0048b | 6189 | fn parse_struct_decl_field(&mut self) -> PResult<'a, StructField> { |
54a0048b | 6190 | let attrs = self.parse_outer_attributes()?; |
cc61c64b XL |
6191 | let lo = self.span; |
6192 | let vis = self.parse_visibility(false)?; | |
5bcae85e | 6193 | self.parse_single_struct_field(lo, vis, attrs) |
223e47cc LB |
6194 | } |
6195 | ||
cc61c64b XL |
6196 | /// Parse `pub`, `pub(crate)` and `pub(in path)` plus shortcuts `pub(self)` for `pub(in self)` |
6197 | /// and `pub(super)` for `pub(in super)`. If the following element can't be a tuple (i.e. it's | |
6198 | /// a function definition, it's not a tuple struct field) and the contents within the parens | |
6199 | /// isn't valid, emit a proper diagnostic. | |
6200 | pub fn parse_visibility(&mut self, can_take_tuple: bool) -> PResult<'a, Visibility> { | |
6201 | maybe_whole!(self, NtVis, |x| x); | |
6202 | ||
ff7c6d11 XL |
6203 | self.expected_tokens.push(TokenType::Keyword(keywords::Crate)); |
6204 | if self.is_crate_vis() { | |
6205 | self.bump(); // `crate` | |
0531ce1d | 6206 | return Ok(respan(self.prev_span, VisibilityKind::Crate(CrateSugar::JustCrate))); |
abe05a73 XL |
6207 | } |
6208 | ||
a7813a04 | 6209 | if !self.eat_keyword(keywords::Pub) { |
8faf50e0 XL |
6210 | // We need a span for our `Spanned<VisibilityKind>`, but there's inherently no |
6211 | // keyword to grab a span from for inherited visibility; an empty span at the | |
6212 | // beginning of the current token would seem to be the "Schelling span". | |
6213 | return Ok(respan(self.span.shrink_to_lo(), VisibilityKind::Inherited)) | |
8bb4bdeb | 6214 | } |
0531ce1d | 6215 | let lo = self.prev_span; |
8bb4bdeb XL |
6216 | |
6217 | if self.check(&token::OpenDelim(token::Paren)) { | |
cc61c64b XL |
6218 | // We don't `self.bump()` the `(` yet because this might be a struct definition where |
6219 | // `()` or a tuple might be allowed. For example, `struct Struct(pub (), pub (usize));`. | |
6220 | // Because of this, we only `bump` the `(` if we're assured it is appropriate to do so | |
6221 | // by the following tokens. | |
8bb4bdeb XL |
6222 | if self.look_ahead(1, |t| t.is_keyword(keywords::Crate)) { |
6223 | // `pub(crate)` | |
6224 | self.bump(); // `(` | |
6225 | self.bump(); // `crate` | |
8bb4bdeb | 6226 | self.expect(&token::CloseDelim(token::Paren))?; // `)` |
0531ce1d XL |
6227 | let vis = respan( |
6228 | lo.to(self.prev_span), | |
6229 | VisibilityKind::Crate(CrateSugar::PubCrate), | |
6230 | ); | |
8bb4bdeb XL |
6231 | return Ok(vis) |
6232 | } else if self.look_ahead(1, |t| t.is_keyword(keywords::In)) { | |
6233 | // `pub(in path)` | |
6234 | self.bump(); // `(` | |
6235 | self.bump(); // `in` | |
0531ce1d | 6236 | let path = self.parse_path(PathStyle::Mod)?; // `path` |
8bb4bdeb | 6237 | self.expect(&token::CloseDelim(token::Paren))?; // `)` |
0531ce1d XL |
6238 | let vis = respan(lo.to(self.prev_span), VisibilityKind::Restricted { |
6239 | path: P(path), | |
6240 | id: ast::DUMMY_NODE_ID, | |
6241 | }); | |
8bb4bdeb XL |
6242 | return Ok(vis) |
6243 | } else if self.look_ahead(2, |t| t == &token::CloseDelim(token::Paren)) && | |
6244 | self.look_ahead(1, |t| t.is_keyword(keywords::Super) || | |
0531ce1d XL |
6245 | t.is_keyword(keywords::SelfValue)) |
6246 | { | |
8bb4bdeb XL |
6247 | // `pub(self)` or `pub(super)` |
6248 | self.bump(); // `(` | |
0531ce1d | 6249 | let path = self.parse_path(PathStyle::Mod)?; // `super`/`self` |
8bb4bdeb | 6250 | self.expect(&token::CloseDelim(token::Paren))?; // `)` |
0531ce1d XL |
6251 | let vis = respan(lo.to(self.prev_span), VisibilityKind::Restricted { |
6252 | path: P(path), | |
6253 | id: ast::DUMMY_NODE_ID, | |
6254 | }); | |
8bb4bdeb | 6255 | return Ok(vis) |
cc61c64b XL |
6256 | } else if !can_take_tuple { // Provide this diagnostic if this is not a tuple struct |
6257 | // `pub(something) fn ...` or `struct X { pub(something) y: Z }` | |
6258 | self.bump(); // `(` | |
6259 | let msg = "incorrect visibility restriction"; | |
6260 | let suggestion = r##"some possible visibility restrictions are: | |
6261 | `pub(crate)`: visible only on the current crate | |
6262 | `pub(super)`: visible only in the current module's parent | |
6263 | `pub(in path::to::module)`: visible only on the specified path"##; | |
6264 | let path = self.parse_path(PathStyle::Mod)?; | |
8faf50e0 | 6265 | let sp = self.prev_span; |
041b39d2 | 6266 | let help_msg = format!("make this visible only to module `{}` with `in`", path); |
cc61c64b | 6267 | self.expect(&token::CloseDelim(token::Paren))?; // `)` |
8faf50e0 XL |
6268 | let mut err = struct_span_err!(self.sess.span_diagnostic, sp, E0704, "{}", msg); |
6269 | err.help(suggestion); | |
94b46f34 | 6270 | err.span_suggestion_with_applicability( |
8faf50e0 | 6271 | sp, &help_msg, format!("in {}", path), Applicability::MachineApplicable |
94b46f34 | 6272 | ); |
cc61c64b | 6273 | err.emit(); // emit diagnostic, but continue with public visibility |
8bb4bdeb XL |
6274 | } |
6275 | } | |
6276 | ||
0531ce1d | 6277 | Ok(respan(lo, VisibilityKind::Public)) |
223e47cc LB |
6278 | } |
6279 | ||
2c00a5a8 XL |
6280 | /// Parse defaultness: `default` or nothing. |
6281 | fn parse_defaultness(&mut self) -> Defaultness { | |
6282 | // `pub` is included for better error messages | |
6283 | if self.check_keyword(keywords::Default) && | |
6284 | self.look_ahead(1, |t| t.is_keyword(keywords::Impl) || | |
6285 | t.is_keyword(keywords::Const) || | |
6286 | t.is_keyword(keywords::Fn) || | |
6287 | t.is_keyword(keywords::Unsafe) || | |
6288 | t.is_keyword(keywords::Extern) || | |
6289 | t.is_keyword(keywords::Type) || | |
6290 | t.is_keyword(keywords::Pub)) { | |
6291 | self.bump(); // `default` | |
6292 | Defaultness::Default | |
54a0048b | 6293 | } else { |
2c00a5a8 | 6294 | Defaultness::Final |
54a0048b SL |
6295 | } |
6296 | } | |
6297 | ||
c34b1796 | 6298 | /// Given a termination token, parse all of the items in a module |
cc61c64b | 6299 | fn parse_mod_items(&mut self, term: &token::Token, inner_lo: Span) -> PResult<'a, Mod> { |
85aaf69f | 6300 | let mut items = vec![]; |
54a0048b | 6301 | while let Some(item) = self.parse_item()? { |
c34b1796 | 6302 | items.push(item); |
85aaf69f | 6303 | } |
223e47cc | 6304 | |
9cc50fc6 | 6305 | if !self.eat(term) { |
c34b1796 | 6306 | let token_str = self.this_token_to_string(); |
ff7c6d11 | 6307 | let mut err = self.fatal(&format!("expected item, found `{}`", token_str)); |
ff7c6d11 | 6308 | if token_str == ";" { |
0531ce1d | 6309 | let msg = "consider removing this semicolon"; |
94b46f34 | 6310 | err.span_suggestion_short_with_applicability( |
b7449926 | 6311 | self.span, msg, String::new(), Applicability::MachineApplicable |
94b46f34 | 6312 | ); |
8faf50e0 XL |
6313 | if !items.is_empty() { // Issue #51603 |
6314 | let previous_item = &items[items.len()-1]; | |
6315 | let previous_item_kind_name = match previous_item.node { | |
6316 | // say "braced struct" because tuple-structs and | |
6317 | // braceless-empty-struct declarations do take a semicolon | |
6318 | ItemKind::Struct(..) => Some("braced struct"), | |
6319 | ItemKind::Enum(..) => Some("enum"), | |
6320 | ItemKind::Trait(..) => Some("trait"), | |
6321 | ItemKind::Union(..) => Some("union"), | |
6322 | _ => None, | |
6323 | }; | |
6324 | if let Some(name) = previous_item_kind_name { | |
6325 | err.help(&format!("{} declarations are not followed by a semicolon", | |
6326 | name)); | |
6327 | } | |
6328 | } | |
0531ce1d XL |
6329 | } else { |
6330 | err.span_label(self.span, "expected item"); | |
ff7c6d11 XL |
6331 | } |
6332 | return Err(err); | |
223e47cc LB |
6333 | } |
6334 | ||
8faf50e0 | 6335 | let hi = if self.span.is_dummy() { |
c1a9b12d SL |
6336 | inner_lo |
6337 | } else { | |
cc61c64b | 6338 | self.prev_span |
c1a9b12d SL |
6339 | }; |
6340 | ||
9346a6ac | 6341 | Ok(ast::Mod { |
cc61c64b | 6342 | inner: inner_lo.to(hi), |
3b2f2976 | 6343 | items, |
0bf4aa26 | 6344 | inline: true |
9346a6ac | 6345 | }) |
223e47cc LB |
6346 | } |
6347 | ||
9cc50fc6 | 6348 | fn parse_item_const(&mut self, m: Option<Mutability>) -> PResult<'a, ItemInfo> { |
0bf4aa26 XL |
6349 | let id = match self.token { |
6350 | token::Ident(ident, false) if ident.name == keywords::Underscore.name() => { | |
6351 | self.bump(); // `_` | |
6352 | ident.gensym() | |
6353 | }, | |
6354 | _ => self.parse_ident()?, | |
6355 | }; | |
54a0048b | 6356 | self.expect(&token::Colon)?; |
32a655c1 | 6357 | let ty = self.parse_ty()?; |
54a0048b SL |
6358 | self.expect(&token::Eq)?; |
6359 | let e = self.parse_expr()?; | |
5bcae85e | 6360 | self.expect(&token::Semi)?; |
1a4d82fc | 6361 | let item = match m { |
7453a54e SL |
6362 | Some(m) => ItemKind::Static(ty, m, e), |
6363 | None => ItemKind::Const(ty, e), | |
1a4d82fc | 6364 | }; |
9346a6ac | 6365 | Ok((id, item, None)) |
223e47cc LB |
6366 | } |
6367 | ||
1a4d82fc | 6368 | /// Parse a `mod <foo> { ... }` or `mod <foo>;` item |
9cc50fc6 | 6369 | fn parse_item_mod(&mut self, outer_attrs: &[Attribute]) -> PResult<'a, ItemInfo> { |
9e0c209e SL |
6370 | let (in_cfg, outer_attrs) = { |
6371 | let mut strip_unconfigured = ::config::StripUnconfigured { | |
9e0c209e | 6372 | sess: self.sess, |
9e0c209e SL |
6373 | features: None, // don't perform gated feature checking |
6374 | }; | |
6375 | let outer_attrs = strip_unconfigured.process_cfg_attrs(outer_attrs.to_owned()); | |
32a655c1 | 6376 | (!self.cfg_mods || strip_unconfigured.in_cfg(&outer_attrs), outer_attrs) |
9e0c209e | 6377 | }; |
5bcae85e | 6378 | |
1a4d82fc | 6379 | let id_span = self.span; |
54a0048b | 6380 | let id = self.parse_ident()?; |
b7449926 | 6381 | if self.eat(&token::Semi) { |
7cac9316 | 6382 | if in_cfg && self.recurse_into_file_modules { |
9e0c209e | 6383 | // This mod is in an external file. Let's go get it! |
476ff2be SL |
6384 | let ModulePathSuccess { path, directory_ownership, warn } = |
6385 | self.submod_path(id, &outer_attrs, id_span)?; | |
6386 | let (module, mut attrs) = | |
6387 | self.eval_src_mod(path, directory_ownership, id.to_string(), id_span)?; | |
0bf4aa26 | 6388 | // Record that we fetched the mod from an external file |
476ff2be | 6389 | if warn { |
2c00a5a8 | 6390 | let attr = Attribute { |
476ff2be SL |
6391 | id: attr::mk_attr_id(), |
6392 | style: ast::AttrStyle::Outer, | |
83c7162d | 6393 | path: ast::Path::from_ident(Ident::from_str("warn_directory_ownership")), |
cc61c64b | 6394 | tokens: TokenStream::empty(), |
476ff2be SL |
6395 | is_sugared_doc: false, |
6396 | span: syntax_pos::DUMMY_SP, | |
6397 | }; | |
6398 | attr::mark_known(&attr); | |
6399 | attrs.push(attr); | |
6400 | } | |
0bf4aa26 | 6401 | Ok((id, ItemKind::Mod(module), Some(attrs))) |
9e0c209e | 6402 | } else { |
0bf4aa26 XL |
6403 | let placeholder = ast::Mod { |
6404 | inner: syntax_pos::DUMMY_SP, | |
6405 | items: Vec::new(), | |
6406 | inline: false | |
6407 | }; | |
9e0c209e SL |
6408 | Ok((id, ItemKind::Mod(placeholder), None)) |
6409 | } | |
223e47cc | 6410 | } else { |
476ff2be SL |
6411 | let old_directory = self.directory.clone(); |
6412 | self.push_directory(id, &outer_attrs); | |
7cac9316 | 6413 | |
54a0048b | 6414 | self.expect(&token::OpenDelim(token::Brace))?; |
cc61c64b | 6415 | let mod_inner_lo = self.span; |
54a0048b | 6416 | let attrs = self.parse_inner_attributes()?; |
476ff2be | 6417 | let module = self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)?; |
7cac9316 | 6418 | |
476ff2be SL |
6419 | self.directory = old_directory; |
6420 | Ok((id, ItemKind::Mod(module), Some(attrs))) | |
223e47cc LB |
6421 | } |
6422 | } | |
6423 | ||
476ff2be SL |
6424 | fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) { |
6425 | if let Some(path) = attr::first_attr_value_str_by_name(attrs, "path") { | |
94b46f34 | 6426 | self.directory.path.to_mut().push(&path.as_str()); |
ff7c6d11 | 6427 | self.directory.ownership = DirectoryOwnership::Owned { relative: None }; |
c30ab7b3 | 6428 | } else { |
0bf4aa26 XL |
6429 | // We have to push on the current module name in the case of relative |
6430 | // paths in order to ensure that any additional module paths from inline | |
6431 | // `mod x { ... }` come after the relative extension. | |
6432 | // | |
6433 | // For example, a `mod z { ... }` inside `x/y.rs` should set the current | |
6434 | // directory path to `/x/y/z`, not `/x/z` with a relative offset of `y`. | |
6435 | if let DirectoryOwnership::Owned { relative } = &mut self.directory.ownership { | |
6436 | if let Some(ident) = relative.take() { // remove the relative offset | |
6437 | self.directory.path.to_mut().push(ident.as_str()); | |
6438 | } | |
6439 | } | |
94b46f34 | 6440 | self.directory.path.to_mut().push(&id.as_str()); |
c30ab7b3 | 6441 | } |
1a4d82fc JJ |
6442 | } |
6443 | ||
2c00a5a8 | 6444 | pub fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option<PathBuf> { |
94b46f34 XL |
6445 | if let Some(s) = attr::first_attr_value_str_by_name(attrs, "path") { |
6446 | let s = s.as_str(); | |
6447 | ||
6448 | // On windows, the base path might have the form | |
6449 | // `\\?\foo\bar` in which case it does not tolerate | |
6450 | // mixed `/` and `\` separators, so canonicalize | |
6451 | // `/` to `\`. | |
6452 | #[cfg(windows)] | |
6453 | let s = s.replace("/", "\\"); | |
6454 | Some(dir_path.join(s)) | |
6455 | } else { | |
6456 | None | |
6457 | } | |
c1a9b12d SL |
6458 | } |
6459 | ||
6460 | /// Returns either a path to a module, or . | |
ff7c6d11 XL |
6461 | pub fn default_submod_path( |
6462 | id: ast::Ident, | |
6463 | relative: Option<ast::Ident>, | |
6464 | dir_path: &Path, | |
b7449926 | 6465 | source_map: &SourceMap) -> ModulePath |
ff7c6d11 XL |
6466 | { |
6467 | // If we're in a foo.rs file instead of a mod.rs file, | |
6468 | // we need to look for submodules in | |
6469 | // `./foo/<id>.rs` and `./foo/<id>/mod.rs` rather than | |
6470 | // `./<id>.rs` and `./<id>/mod.rs`. | |
6471 | let relative_prefix_string; | |
6472 | let relative_prefix = if let Some(ident) = relative { | |
94b46f34 | 6473 | relative_prefix_string = format!("{}{}", ident.as_str(), path::MAIN_SEPARATOR); |
ff7c6d11 XL |
6474 | &relative_prefix_string |
6475 | } else { | |
6476 | "" | |
6477 | }; | |
6478 | ||
c1a9b12d | 6479 | let mod_name = id.to_string(); |
ff7c6d11 XL |
6480 | let default_path_str = format!("{}{}.rs", relative_prefix, mod_name); |
6481 | let secondary_path_str = format!("{}{}{}mod.rs", | |
6482 | relative_prefix, mod_name, path::MAIN_SEPARATOR); | |
c1a9b12d SL |
6483 | let default_path = dir_path.join(&default_path_str); |
6484 | let secondary_path = dir_path.join(&secondary_path_str); | |
b7449926 XL |
6485 | let default_exists = source_map.file_exists(&default_path); |
6486 | let secondary_exists = source_map.file_exists(&secondary_path); | |
c1a9b12d SL |
6487 | |
6488 | let result = match (default_exists, secondary_exists) { | |
476ff2be SL |
6489 | (true, false) => Ok(ModulePathSuccess { |
6490 | path: default_path, | |
ff7c6d11 XL |
6491 | directory_ownership: DirectoryOwnership::Owned { |
6492 | relative: Some(id), | |
6493 | }, | |
476ff2be SL |
6494 | warn: false, |
6495 | }), | |
6496 | (false, true) => Ok(ModulePathSuccess { | |
6497 | path: secondary_path, | |
ff7c6d11 XL |
6498 | directory_ownership: DirectoryOwnership::Owned { |
6499 | relative: None, | |
6500 | }, | |
476ff2be SL |
6501 | warn: false, |
6502 | }), | |
8bb4bdeb XL |
6503 | (false, false) => Err(Error::FileNotFoundForModule { |
6504 | mod_name: mod_name.clone(), | |
6505 | default_path: default_path_str, | |
6506 | secondary_path: secondary_path_str, | |
8faf50e0 | 6507 | dir_path: dir_path.display().to_string(), |
c1a9b12d | 6508 | }), |
8bb4bdeb XL |
6509 | (true, true) => Err(Error::DuplicatePaths { |
6510 | mod_name: mod_name.clone(), | |
6511 | default_path: default_path_str, | |
6512 | secondary_path: secondary_path_str, | |
c1a9b12d SL |
6513 | }), |
6514 | }; | |
6515 | ||
6516 | ModulePath { | |
6517 | name: mod_name, | |
6518 | path_exists: default_exists || secondary_exists, | |
3b2f2976 | 6519 | result, |
c1a9b12d SL |
6520 | } |
6521 | } | |
6522 | ||
6523 | fn submod_path(&mut self, | |
6524 | id: ast::Ident, | |
2c00a5a8 | 6525 | outer_attrs: &[Attribute], |
7cac9316 XL |
6526 | id_sp: Span) |
6527 | -> PResult<'a, ModulePathSuccess> { | |
476ff2be SL |
6528 | if let Some(path) = Parser::submod_path_from_attr(outer_attrs, &self.directory.path) { |
6529 | return Ok(ModulePathSuccess { | |
6530 | directory_ownership: match path.file_name().and_then(|s| s.to_str()) { | |
ff7c6d11 XL |
6531 | // All `#[path]` files are treated as though they are a `mod.rs` file. |
6532 | // This means that `mod foo;` declarations inside `#[path]`-included | |
6533 | // files are siblings, | |
6534 | // | |
6535 | // Note that this will produce weirdness when a file named `foo.rs` is | |
6536 | // `#[path]` included and contains a `mod foo;` declaration. | |
6537 | // If you encounter this, it's your own darn fault :P | |
6538 | Some(_) => DirectoryOwnership::Owned { relative: None }, | |
476ff2be SL |
6539 | _ => DirectoryOwnership::UnownedViaMod(true), |
6540 | }, | |
3b2f2976 | 6541 | path, |
476ff2be SL |
6542 | warn: false, |
6543 | }); | |
c1a9b12d SL |
6544 | } |
6545 | ||
ff7c6d11 XL |
6546 | let relative = match self.directory.ownership { |
6547 | DirectoryOwnership::Owned { relative } => { | |
6548 | // Push the usage onto the list of non-mod.rs mod uses. | |
6549 | // This is used later for feature-gate error reporting. | |
6550 | if let Some(cur_file_ident) = relative { | |
6551 | self.sess | |
6552 | .non_modrs_mods.borrow_mut() | |
6553 | .push((cur_file_ident, id_sp)); | |
6554 | } | |
6555 | relative | |
6556 | }, | |
6557 | DirectoryOwnership::UnownedViaBlock | | |
6558 | DirectoryOwnership::UnownedViaMod(_) => None, | |
6559 | }; | |
6560 | let paths = Parser::default_submod_path( | |
b7449926 | 6561 | id, relative, &self.directory.path, self.sess.source_map()); |
c1a9b12d | 6562 | |
ff7c6d11 XL |
6563 | match self.directory.ownership { |
6564 | DirectoryOwnership::Owned { .. } => { | |
6565 | paths.result.map_err(|err| self.span_fatal_err(id_sp, err)) | |
6566 | }, | |
6567 | DirectoryOwnership::UnownedViaBlock => { | |
6568 | let msg = | |
6569 | "Cannot declare a non-inline module inside a block \ | |
6570 | unless it has a path attribute"; | |
6571 | let mut err = self.diagnostic().struct_span_err(id_sp, msg); | |
6572 | if paths.path_exists { | |
6573 | let msg = format!("Maybe `use` the module `{}` instead of redeclaring it", | |
6574 | paths.name); | |
6575 | err.span_note(id_sp, &msg); | |
476ff2be | 6576 | } |
ff7c6d11 | 6577 | Err(err) |
476ff2be | 6578 | } |
ff7c6d11 XL |
6579 | DirectoryOwnership::UnownedViaMod(warn) => { |
6580 | if warn { | |
6581 | if let Ok(result) = paths.result { | |
6582 | return Ok(ModulePathSuccess { warn: true, ..result }); | |
6583 | } | |
6584 | } | |
6585 | let mut err = self.diagnostic().struct_span_err(id_sp, | |
6586 | "cannot declare a new module at this location"); | |
8faf50e0 | 6587 | if !id_sp.is_dummy() { |
b7449926 | 6588 | let src_path = self.sess.source_map().span_to_filename(id_sp); |
ff7c6d11 XL |
6589 | if let FileName::Real(src_path) = src_path { |
6590 | if let Some(stem) = src_path.file_stem() { | |
6591 | let mut dest_path = src_path.clone(); | |
6592 | dest_path.set_file_name(stem); | |
6593 | dest_path.push("mod.rs"); | |
6594 | err.span_note(id_sp, | |
6595 | &format!("maybe move this module `{}` to its own \ | |
6596 | directory via `{}`", src_path.display(), | |
6597 | dest_path.display())); | |
6598 | } | |
6599 | } | |
6600 | } | |
6601 | if paths.path_exists { | |
7cac9316 | 6602 | err.span_note(id_sp, |
ff7c6d11 XL |
6603 | &format!("... or maybe `use` the module `{}` instead \ |
6604 | of possibly redeclaring it", | |
6605 | paths.name)); | |
7cac9316 | 6606 | } |
ff7c6d11 | 6607 | Err(err) |
7cac9316 | 6608 | } |
c1a9b12d SL |
6609 | } |
6610 | } | |
6611 | ||
6612 | /// Read a module from a source file. | |
6613 | fn eval_src_mod(&mut self, | |
476ff2be SL |
6614 | path: PathBuf, |
6615 | directory_ownership: DirectoryOwnership, | |
6616 | name: String, | |
c1a9b12d | 6617 | id_sp: Span) |
0bf4aa26 | 6618 | -> PResult<'a, (ast::Mod, Vec<Attribute> )> { |
1a4d82fc | 6619 | let mut included_mod_stack = self.sess.included_mod_stack.borrow_mut(); |
3157f602 XL |
6620 | if let Some(i) = included_mod_stack.iter().position(|p| *p == path) { |
6621 | let mut err = String::from("circular modules: "); | |
6622 | let len = included_mod_stack.len(); | |
6623 | for p in &included_mod_stack[i.. len] { | |
6624 | err.push_str(&p.to_string_lossy()); | |
6625 | err.push_str(" -> "); | |
223e47cc | 6626 | } |
3157f602 XL |
6627 | err.push_str(&path.to_string_lossy()); |
6628 | return Err(self.span_fatal(id_sp, &err[..])); | |
1a4d82fc JJ |
6629 | } |
6630 | included_mod_stack.push(path.clone()); | |
6631 | drop(included_mod_stack); | |
6632 | ||
476ff2be SL |
6633 | let mut p0 = |
6634 | new_sub_parser_from_file(self.sess, &path, directory_ownership, Some(name), id_sp); | |
32a655c1 | 6635 | p0.cfg_mods = self.cfg_mods; |
cc61c64b | 6636 | let mod_inner_lo = p0.span; |
54a0048b | 6637 | let mod_attrs = p0.parse_inner_attributes()?; |
0bf4aa26 XL |
6638 | let mut m0 = p0.parse_mod_items(&token::Eof, mod_inner_lo)?; |
6639 | m0.inline = false; | |
1a4d82fc | 6640 | self.sess.included_mod_stack.borrow_mut().pop(); |
0bf4aa26 | 6641 | Ok((m0, mod_attrs)) |
223e47cc LB |
6642 | } |
6643 | ||
1a4d82fc | 6644 | /// Parse a function declaration from a foreign module |
cc61c64b XL |
6645 | fn parse_item_foreign_fn(&mut self, vis: ast::Visibility, lo: Span, attrs: Vec<Attribute>) |
6646 | -> PResult<'a, ForeignItem> { | |
54a0048b | 6647 | self.expect_keyword(keywords::Fn)?; |
1a4d82fc | 6648 | |
54a0048b SL |
6649 | let (ident, mut generics) = self.parse_fn_header()?; |
6650 | let decl = self.parse_fn_decl(true)?; | |
6651 | generics.where_clause = self.parse_where_clause()?; | |
cc61c64b | 6652 | let hi = self.span; |
54a0048b | 6653 | self.expect(&token::Semi)?; |
7453a54e | 6654 | Ok(ast::ForeignItem { |
3b2f2976 XL |
6655 | ident, |
6656 | attrs, | |
7453a54e | 6657 | node: ForeignItemKind::Fn(decl, generics), |
1a4d82fc | 6658 | id: ast::DUMMY_NODE_ID, |
cc61c64b | 6659 | span: lo.to(hi), |
3b2f2976 | 6660 | vis, |
7453a54e | 6661 | }) |
1a4d82fc JJ |
6662 | } |
6663 | ||
3b2f2976 XL |
6664 | /// Parse a static item from a foreign module. |
6665 | /// Assumes that the `static` keyword is already parsed. | |
cc61c64b XL |
6666 | fn parse_item_foreign_static(&mut self, vis: ast::Visibility, lo: Span, attrs: Vec<Attribute>) |
6667 | -> PResult<'a, ForeignItem> { | |
9cc50fc6 | 6668 | let mutbl = self.eat_keyword(keywords::Mut); |
54a0048b SL |
6669 | let ident = self.parse_ident()?; |
6670 | self.expect(&token::Colon)?; | |
32a655c1 | 6671 | let ty = self.parse_ty()?; |
cc61c64b | 6672 | let hi = self.span; |
54a0048b | 6673 | self.expect(&token::Semi)?; |
7453a54e | 6674 | Ok(ForeignItem { |
3b2f2976 XL |
6675 | ident, |
6676 | attrs, | |
7453a54e | 6677 | node: ForeignItemKind::Static(ty, mutbl), |
1a4d82fc | 6678 | id: ast::DUMMY_NODE_ID, |
cc61c64b | 6679 | span: lo.to(hi), |
3b2f2976 | 6680 | vis, |
7453a54e | 6681 | }) |
223e47cc LB |
6682 | } |
6683 | ||
abe05a73 XL |
6684 | /// Parse a type from a foreign module |
6685 | fn parse_item_foreign_type(&mut self, vis: ast::Visibility, lo: Span, attrs: Vec<Attribute>) | |
6686 | -> PResult<'a, ForeignItem> { | |
6687 | self.expect_keyword(keywords::Type)?; | |
6688 | ||
6689 | let ident = self.parse_ident()?; | |
6690 | let hi = self.span; | |
6691 | self.expect(&token::Semi)?; | |
6692 | Ok(ast::ForeignItem { | |
6693 | ident: ident, | |
6694 | attrs: attrs, | |
6695 | node: ForeignItemKind::Ty, | |
6696 | id: ast::DUMMY_NODE_ID, | |
6697 | span: lo.to(hi), | |
6698 | vis: vis | |
6699 | }) | |
6700 | } | |
6701 | ||
8faf50e0 XL |
6702 | fn parse_crate_name_with_dashes(&mut self) -> PResult<'a, ast::Ident> { |
6703 | let error_msg = "crate name using dashes are not valid in `extern crate` statements"; | |
6704 | let suggestion_msg = "if the original crate name uses dashes you need to use underscores \ | |
6705 | in the code"; | |
6706 | let mut ident = self.parse_ident()?; | |
6707 | let mut idents = vec![]; | |
6708 | let mut replacement = vec![]; | |
6709 | let mut fixed_crate_name = false; | |
6710 | // Accept `extern crate name-like-this` for better diagnostics | |
6711 | let dash = token::Token::BinOp(token::BinOpToken::Minus); | |
6712 | if self.token == dash { // Do not include `-` as part of the expected tokens list | |
6713 | while self.eat(&dash) { | |
6714 | fixed_crate_name = true; | |
6715 | replacement.push((self.prev_span, "_".to_string())); | |
6716 | idents.push(self.parse_ident()?); | |
6717 | } | |
6718 | } | |
6719 | if fixed_crate_name { | |
6720 | let fixed_name_sp = ident.span.to(idents.last().unwrap().span); | |
6721 | let mut fixed_name = format!("{}", ident.name); | |
6722 | for part in idents { | |
6723 | fixed_name.push_str(&format!("_{}", part.name)); | |
6724 | } | |
6725 | ident = Ident::from_str(&fixed_name).with_span_pos(fixed_name_sp); | |
6726 | ||
6727 | let mut err = self.struct_span_err(fixed_name_sp, error_msg); | |
6728 | err.span_label(fixed_name_sp, "dash-separated idents are not valid"); | |
6729 | err.multipart_suggestion(suggestion_msg, replacement); | |
6730 | err.emit(); | |
6731 | } | |
6732 | Ok(ident) | |
6733 | } | |
6734 | ||
1a4d82fc JJ |
6735 | /// Parse extern crate links |
6736 | /// | |
c34b1796 | 6737 | /// # Examples |
1a4d82fc | 6738 | /// |
c34b1796 AL |
6739 | /// extern crate foo; |
6740 | /// extern crate bar as foo; | |
1a4d82fc | 6741 | fn parse_item_extern_crate(&mut self, |
cc61c64b | 6742 | lo: Span, |
c34b1796 AL |
6743 | visibility: Visibility, |
6744 | attrs: Vec<Attribute>) | |
0531ce1d | 6745 | -> PResult<'a, P<Item>> { |
8faf50e0 XL |
6746 | // Accept `extern crate name-like-this` for better diagnostics |
6747 | let orig_name = self.parse_crate_name_with_dashes()?; | |
0531ce1d XL |
6748 | let (item_name, orig_name) = if let Some(rename) = self.parse_rename()? { |
6749 | (rename, Some(orig_name.name)) | |
c34b1796 | 6750 | } else { |
0531ce1d | 6751 | (orig_name, None) |
223e47cc | 6752 | }; |
54a0048b | 6753 | self.expect(&token::Semi)?; |
223e47cc | 6754 | |
0531ce1d XL |
6755 | let span = lo.to(self.prev_span); |
6756 | Ok(self.mk_item(span, item_name, ItemKind::ExternCrate(orig_name), visibility, attrs)) | |
1a4d82fc | 6757 | } |
970d7e83 | 6758 | |
1a4d82fc JJ |
6759 | /// Parse `extern` for foreign ABIs |
6760 | /// modules. | |
6761 | /// | |
6762 | /// `extern` is expected to have been | |
6763 | /// consumed before calling this method | |
6764 | /// | |
6765 | /// # Examples: | |
6766 | /// | |
6767 | /// extern "C" {} | |
6768 | /// extern {} | |
6769 | fn parse_item_foreign_mod(&mut self, | |
cc61c64b | 6770 | lo: Span, |
2c00a5a8 | 6771 | opt_abi: Option<Abi>, |
1a4d82fc | 6772 | visibility: Visibility, |
c34b1796 | 6773 | mut attrs: Vec<Attribute>) |
9cc50fc6 | 6774 | -> PResult<'a, P<Item>> { |
54a0048b | 6775 | self.expect(&token::OpenDelim(token::Brace))?; |
223e47cc | 6776 | |
7453a54e | 6777 | let abi = opt_abi.unwrap_or(Abi::C); |
223e47cc | 6778 | |
54a0048b | 6779 | attrs.extend(self.parse_inner_attributes()?); |
c34b1796 AL |
6780 | |
6781 | let mut foreign_items = vec![]; | |
0bf4aa26 XL |
6782 | while !self.eat(&token::CloseDelim(token::Brace)) { |
6783 | foreign_items.push(self.parse_foreign_item()?); | |
c34b1796 | 6784 | } |
223e47cc | 6785 | |
c30ab7b3 | 6786 | let prev_span = self.prev_span; |
c34b1796 | 6787 | let m = ast::ForeignMod { |
3b2f2976 | 6788 | abi, |
c34b1796 AL |
6789 | items: foreign_items |
6790 | }; | |
cc61c64b XL |
6791 | let invalid = keywords::Invalid.ident(); |
6792 | Ok(self.mk_item(lo.to(prev_span), invalid, ItemKind::ForeignMod(m), visibility, attrs)) | |
223e47cc LB |
6793 | } |
6794 | ||
1a4d82fc | 6795 | /// Parse type Foo = Bar; |
8faf50e0 XL |
6796 | /// or |
6797 | /// existential type Foo: Bar; | |
6798 | /// or | |
6799 | /// return None without modifying the parser state | |
6800 | fn eat_type(&mut self) -> Option<PResult<'a, (Ident, AliasKind, ast::Generics)>> { | |
6801 | // This parses the grammar: | |
6802 | // Ident ["<"...">"] ["where" ...] ("=" | ":") Ty ";" | |
6803 | if self.check_keyword(keywords::Type) || | |
6804 | self.check_keyword(keywords::Existential) && | |
6805 | self.look_ahead(1, |t| t.is_keyword(keywords::Type)) { | |
6806 | let existential = self.eat_keyword(keywords::Existential); | |
6807 | assert!(self.eat_keyword(keywords::Type)); | |
6808 | Some(self.parse_existential_or_alias(existential)) | |
6809 | } else { | |
6810 | None | |
6811 | } | |
6812 | } | |
6813 | ||
6814 | /// Parse type alias or existential type | |
6815 | fn parse_existential_or_alias( | |
6816 | &mut self, | |
6817 | existential: bool, | |
6818 | ) -> PResult<'a, (Ident, AliasKind, ast::Generics)> { | |
54a0048b SL |
6819 | let ident = self.parse_ident()?; |
6820 | let mut tps = self.parse_generics()?; | |
6821 | tps.where_clause = self.parse_where_clause()?; | |
8faf50e0 XL |
6822 | let alias = if existential { |
6823 | self.expect(&token::Colon)?; | |
6824 | let bounds = self.parse_generic_bounds()?; | |
6825 | AliasKind::Existential(bounds) | |
6826 | } else { | |
6827 | self.expect(&token::Eq)?; | |
6828 | let ty = self.parse_ty()?; | |
6829 | AliasKind::Weak(ty) | |
6830 | }; | |
54a0048b | 6831 | self.expect(&token::Semi)?; |
8faf50e0 | 6832 | Ok((ident, alias, tps)) |
223e47cc LB |
6833 | } |
6834 | ||
1a4d82fc | 6835 | /// Parse the part of an "enum" decl following the '{' |
9cc50fc6 | 6836 | fn parse_enum_def(&mut self, _generics: &ast::Generics) -> PResult<'a, EnumDef> { |
1a4d82fc | 6837 | let mut variants = Vec::new(); |
970d7e83 | 6838 | let mut all_nullary = true; |
1a4d82fc JJ |
6839 | let mut any_disr = None; |
6840 | while self.token != token::CloseDelim(token::Brace) { | |
54a0048b | 6841 | let variant_attrs = self.parse_outer_attributes()?; |
cc61c64b | 6842 | let vlo = self.span; |
223e47cc | 6843 | |
b039eaaf | 6844 | let struct_def; |
970d7e83 | 6845 | let mut disr_expr = None; |
54a0048b | 6846 | let ident = self.parse_ident()?; |
92a42be0 | 6847 | if self.check(&token::OpenDelim(token::Brace)) { |
223e47cc LB |
6848 | // Parse a struct variant. |
6849 | all_nullary = false; | |
54a0048b | 6850 | struct_def = VariantData::Struct(self.parse_record_struct_body()?, |
92a42be0 | 6851 | ast::DUMMY_NODE_ID); |
1a4d82fc | 6852 | } else if self.check(&token::OpenDelim(token::Paren)) { |
223e47cc | 6853 | all_nullary = false; |
54a0048b | 6854 | struct_def = VariantData::Tuple(self.parse_tuple_struct_body()?, |
92a42be0 | 6855 | ast::DUMMY_NODE_ID); |
9cc50fc6 | 6856 | } else if self.eat(&token::Eq) { |
94b46f34 XL |
6857 | disr_expr = Some(AnonConst { |
6858 | id: ast::DUMMY_NODE_ID, | |
6859 | value: self.parse_expr()?, | |
6860 | }); | |
6861 | any_disr = disr_expr.as_ref().map(|c| c.value.span); | |
92a42be0 | 6862 | struct_def = VariantData::Unit(ast::DUMMY_NODE_ID); |
223e47cc | 6863 | } else { |
92a42be0 | 6864 | struct_def = VariantData::Unit(ast::DUMMY_NODE_ID); |
223e47cc | 6865 | } |
223e47cc | 6866 | |
1a4d82fc | 6867 | let vr = ast::Variant_ { |
83c7162d | 6868 | ident, |
223e47cc | 6869 | attrs: variant_attrs, |
b039eaaf | 6870 | data: struct_def, |
3b2f2976 | 6871 | disr_expr, |
223e47cc | 6872 | }; |
cc61c64b | 6873 | variants.push(respan(vlo.to(self.prev_span), vr)); |
223e47cc | 6874 | |
9cc50fc6 | 6875 | if !self.eat(&token::Comma) { break; } |
223e47cc | 6876 | } |
54a0048b | 6877 | self.expect(&token::CloseDelim(token::Brace))?; |
1a4d82fc JJ |
6878 | match any_disr { |
6879 | Some(disr_span) if !all_nullary => | |
6880 | self.span_err(disr_span, | |
ff7c6d11 | 6881 | "discriminator values can only be used with a field-less enum"), |
1a4d82fc | 6882 | _ => () |
223e47cc LB |
6883 | } |
6884 | ||
9346a6ac | 6885 | Ok(ast::EnumDef { variants: variants }) |
223e47cc LB |
6886 | } |
6887 | ||
1a4d82fc | 6888 | /// Parse an "enum" declaration |
9cc50fc6 | 6889 | fn parse_item_enum(&mut self) -> PResult<'a, ItemInfo> { |
54a0048b SL |
6890 | let id = self.parse_ident()?; |
6891 | let mut generics = self.parse_generics()?; | |
6892 | generics.where_clause = self.parse_where_clause()?; | |
6893 | self.expect(&token::OpenDelim(token::Brace))?; | |
223e47cc | 6894 | |
c30ab7b3 SL |
6895 | let enum_definition = self.parse_enum_def(&generics).map_err(|e| { |
6896 | self.recover_stmt(); | |
6897 | self.eat(&token::CloseDelim(token::Brace)); | |
6898 | e | |
6899 | })?; | |
7453a54e | 6900 | Ok((id, ItemKind::Enum(enum_definition, generics), None)) |
223e47cc LB |
6901 | } |
6902 | ||
1a4d82fc JJ |
6903 | /// Parses a string as an ABI spec on an extern type or module. Consumes |
6904 | /// the `extern` keyword, if one is found. | |
2c00a5a8 | 6905 | fn parse_opt_abi(&mut self) -> PResult<'a, Option<Abi>> { |
1a4d82fc JJ |
6906 | match self.token { |
6907 | token::Literal(token::Str_(s), suf) | token::Literal(token::StrRaw(s, _), suf) => { | |
6908 | let sp = self.span; | |
6909 | self.expect_no_suffix(sp, "ABI spec", suf); | |
9cc50fc6 | 6910 | self.bump(); |
c1a9b12d | 6911 | match abi::lookup(&s.as_str()) { |
9346a6ac | 6912 | Some(abi) => Ok(Some(abi)), |
1a4d82fc | 6913 | None => { |
c30ab7b3 | 6914 | let prev_span = self.prev_span; |
8faf50e0 XL |
6915 | let mut err = struct_span_err!( |
6916 | self.sess.span_diagnostic, | |
c30ab7b3 | 6917 | prev_span, |
8faf50e0 XL |
6918 | E0703, |
6919 | "invalid ABI: found `{}`", | |
6920 | s); | |
6921 | err.span_label(prev_span, "invalid ABI"); | |
6922 | err.help(&format!("valid ABIs: {}", abi::all_names().join(", "))); | |
6923 | err.emit(); | |
9346a6ac | 6924 | Ok(None) |
223e47cc LB |
6925 | } |
6926 | } | |
223e47cc LB |
6927 | } |
6928 | ||
9346a6ac | 6929 | _ => Ok(None), |
223e47cc LB |
6930 | } |
6931 | } | |
6932 | ||
2c00a5a8 XL |
6933 | fn is_static_global(&mut self) -> bool { |
6934 | if self.check_keyword(keywords::Static) { | |
6935 | // Check if this could be a closure | |
6936 | !self.look_ahead(1, |token| { | |
6937 | if token.is_keyword(keywords::Move) { | |
6938 | return true; | |
6939 | } | |
6940 | match *token { | |
6941 | token::BinOp(token::Or) | token::OrOr => true, | |
6942 | _ => false, | |
6943 | } | |
6944 | }) | |
6945 | } else { | |
6946 | false | |
6947 | } | |
6948 | } | |
6949 | ||
8faf50e0 XL |
6950 | fn parse_item_( |
6951 | &mut self, | |
6952 | attrs: Vec<Attribute>, | |
6953 | macros_allowed: bool, | |
6954 | attributes_allowed: bool, | |
6955 | ) -> PResult<'a, Option<P<Item>>> { | |
6956 | let (ret, tokens) = self.collect_tokens(|this| { | |
6957 | this.parse_item_implementation(attrs, macros_allowed, attributes_allowed) | |
6958 | })?; | |
6959 | ||
6960 | // Once we've parsed an item and recorded the tokens we got while | |
6961 | // parsing we may want to store `tokens` into the item we're about to | |
6962 | // return. Note, though, that we specifically didn't capture tokens | |
6963 | // related to outer attributes. The `tokens` field here may later be | |
6964 | // used with procedural macros to convert this item back into a token | |
6965 | // stream, but during expansion we may be removing attributes as we go | |
6966 | // along. | |
6967 | // | |
6968 | // If we've got inner attributes then the `tokens` we've got above holds | |
6969 | // these inner attributes. If an inner attribute is expanded we won't | |
6970 | // actually remove it from the token stream, so we'll just keep yielding | |
6971 | // it (bad!). To work around this case for now we just avoid recording | |
6972 | // `tokens` if we detect any inner attributes. This should help keep | |
6973 | // expansion correct, but we should fix this bug one day! | |
6974 | Ok(ret.map(|item| { | |
6975 | item.map(|mut i| { | |
6976 | if !i.attrs.iter().any(|attr| attr.style == AttrStyle::Inner) { | |
6977 | i.tokens = Some(tokens); | |
6978 | } | |
6979 | i | |
6980 | }) | |
6981 | })) | |
6982 | } | |
6983 | ||
c34b1796 | 6984 | /// Parse one of the items allowed by the flags. |
8faf50e0 XL |
6985 | fn parse_item_implementation( |
6986 | &mut self, | |
6987 | attrs: Vec<Attribute>, | |
6988 | macros_allowed: bool, | |
6989 | attributes_allowed: bool, | |
6990 | ) -> PResult<'a, Option<P<Item>>> { | |
c30ab7b3 | 6991 | maybe_whole!(self, NtItem, |item| { |
ff7c6d11 | 6992 | let mut item = item.into_inner(); |
3157f602 XL |
6993 | let mut attrs = attrs; |
6994 | mem::swap(&mut item.attrs, &mut attrs); | |
6995 | item.attrs.extend(attrs); | |
c30ab7b3 SL |
6996 | Some(P(item)) |
6997 | }); | |
1a4d82fc | 6998 | |
cc61c64b | 6999 | let lo = self.span; |
223e47cc | 7000 | |
cc61c64b | 7001 | let visibility = self.parse_visibility(false)?; |
970d7e83 | 7002 | |
9cc50fc6 | 7003 | if self.eat_keyword(keywords::Use) { |
85aaf69f | 7004 | // USE ITEM |
0531ce1d | 7005 | let item_ = ItemKind::Use(P(self.parse_use_tree()?)); |
54a0048b | 7006 | self.expect(&token::Semi)?; |
85aaf69f | 7007 | |
0531ce1d XL |
7008 | let span = lo.to(self.prev_span); |
7009 | let item = self.mk_item(span, keywords::Invalid.ident(), item_, visibility, attrs); | |
9346a6ac | 7010 | return Ok(Some(item)); |
223e47cc | 7011 | } |
1a4d82fc | 7012 | |
2c00a5a8 XL |
7013 | if self.check_keyword(keywords::Extern) && self.is_extern_non_path() { |
7014 | self.bump(); // `extern` | |
9cc50fc6 | 7015 | if self.eat_keyword(keywords::Crate) { |
54a0048b | 7016 | return Ok(Some(self.parse_item_extern_crate(lo, visibility, attrs)?)); |
1a4d82fc JJ |
7017 | } |
7018 | ||
54a0048b | 7019 | let opt_abi = self.parse_opt_abi()?; |
223e47cc | 7020 | |
9cc50fc6 | 7021 | if self.eat_keyword(keywords::Fn) { |
970d7e83 | 7022 | // EXTERN FUNCTION ITEM |
c30ab7b3 | 7023 | let fn_span = self.prev_span; |
7453a54e | 7024 | let abi = opt_abi.unwrap_or(Abi::C); |
970d7e83 | 7025 | let (ident, item_, extra_attrs) = |
9e0c209e | 7026 | self.parse_item_fn(Unsafety::Normal, |
8faf50e0 | 7027 | IsAsync::NotAsync, |
9e0c209e SL |
7028 | respan(fn_span, Constness::NotConst), |
7029 | abi)?; | |
c30ab7b3 | 7030 | let prev_span = self.prev_span; |
cc61c64b | 7031 | let item = self.mk_item(lo.to(prev_span), |
1a4d82fc JJ |
7032 | ident, |
7033 | item_, | |
7034 | visibility, | |
7035 | maybe_append(attrs, extra_attrs)); | |
9346a6ac | 7036 | return Ok(Some(item)); |
1a4d82fc | 7037 | } else if self.check(&token::OpenDelim(token::Brace)) { |
54a0048b | 7038 | return Ok(Some(self.parse_item_foreign_mod(lo, opt_abi, visibility, attrs)?)); |
970d7e83 | 7039 | } |
1a4d82fc | 7040 | |
54a0048b | 7041 | self.unexpected()?; |
1a4d82fc JJ |
7042 | } |
7043 | ||
2c00a5a8 XL |
7044 | if self.is_static_global() { |
7045 | self.bump(); | |
1a4d82fc | 7046 | // STATIC ITEM |
7453a54e SL |
7047 | let m = if self.eat_keyword(keywords::Mut) { |
7048 | Mutability::Mutable | |
7049 | } else { | |
7050 | Mutability::Immutable | |
7051 | }; | |
54a0048b | 7052 | let (ident, item_, extra_attrs) = self.parse_item_const(Some(m))?; |
c30ab7b3 | 7053 | let prev_span = self.prev_span; |
cc61c64b | 7054 | let item = self.mk_item(lo.to(prev_span), |
1a4d82fc JJ |
7055 | ident, |
7056 | item_, | |
7057 | visibility, | |
7058 | maybe_append(attrs, extra_attrs)); | |
9346a6ac | 7059 | return Ok(Some(item)); |
1a4d82fc | 7060 | } |
9cc50fc6 | 7061 | if self.eat_keyword(keywords::Const) { |
c30ab7b3 | 7062 | let const_span = self.prev_span; |
b039eaaf SL |
7063 | if self.check_keyword(keywords::Fn) |
7064 | || (self.check_keyword(keywords::Unsafe) | |
7065 | && self.look_ahead(1, |t| t.is_keyword(keywords::Fn))) { | |
62682a34 | 7066 | // CONST FUNCTION ITEM |
2c00a5a8 | 7067 | let unsafety = self.parse_unsafety(); |
9cc50fc6 | 7068 | self.bump(); |
62682a34 | 7069 | let (ident, item_, extra_attrs) = |
9e0c209e | 7070 | self.parse_item_fn(unsafety, |
8faf50e0 | 7071 | IsAsync::NotAsync, |
9e0c209e SL |
7072 | respan(const_span, Constness::Const), |
7073 | Abi::Rust)?; | |
c30ab7b3 | 7074 | let prev_span = self.prev_span; |
cc61c64b | 7075 | let item = self.mk_item(lo.to(prev_span), |
62682a34 SL |
7076 | ident, |
7077 | item_, | |
7078 | visibility, | |
7079 | maybe_append(attrs, extra_attrs)); | |
7080 | return Ok(Some(item)); | |
7081 | } | |
7082 | ||
1a4d82fc | 7083 | // CONST ITEM |
9cc50fc6 | 7084 | if self.eat_keyword(keywords::Mut) { |
c30ab7b3 SL |
7085 | let prev_span = self.prev_span; |
7086 | self.diagnostic().struct_span_err(prev_span, "const globals cannot be mutable") | |
a7813a04 | 7087 | .help("did you mean to declare a static?") |
9cc50fc6 | 7088 | .emit(); |
1a4d82fc | 7089 | } |
54a0048b | 7090 | let (ident, item_, extra_attrs) = self.parse_item_const(None)?; |
c30ab7b3 | 7091 | let prev_span = self.prev_span; |
cc61c64b | 7092 | let item = self.mk_item(lo.to(prev_span), |
1a4d82fc JJ |
7093 | ident, |
7094 | item_, | |
7095 | visibility, | |
7096 | maybe_append(attrs, extra_attrs)); | |
9346a6ac | 7097 | return Ok(Some(item)); |
1a4d82fc | 7098 | } |
8faf50e0 XL |
7099 | |
7100 | // `unsafe async fn` or `async fn` | |
7101 | if ( | |
7102 | self.check_keyword(keywords::Unsafe) && | |
7103 | self.look_ahead(1, |t| t.is_keyword(keywords::Async)) | |
7104 | ) || ( | |
7105 | self.check_keyword(keywords::Async) && | |
7106 | self.look_ahead(1, |t| t.is_keyword(keywords::Fn)) | |
7107 | ) | |
7108 | { | |
7109 | // ASYNC FUNCTION ITEM | |
7110 | let unsafety = self.parse_unsafety(); | |
7111 | self.expect_keyword(keywords::Async)?; | |
7112 | self.expect_keyword(keywords::Fn)?; | |
7113 | let fn_span = self.prev_span; | |
7114 | let (ident, item_, extra_attrs) = | |
7115 | self.parse_item_fn(unsafety, | |
7116 | IsAsync::Async { | |
7117 | closure_id: ast::DUMMY_NODE_ID, | |
7118 | return_impl_trait_id: ast::DUMMY_NODE_ID, | |
7119 | }, | |
7120 | respan(fn_span, Constness::NotConst), | |
7121 | Abi::Rust)?; | |
7122 | let prev_span = self.prev_span; | |
7123 | let item = self.mk_item(lo.to(prev_span), | |
7124 | ident, | |
7125 | item_, | |
7126 | visibility, | |
7127 | maybe_append(attrs, extra_attrs)); | |
7128 | return Ok(Some(item)); | |
7129 | } | |
85aaf69f | 7130 | if self.check_keyword(keywords::Unsafe) && |
abe05a73 XL |
7131 | (self.look_ahead(1, |t| t.is_keyword(keywords::Trait)) || |
7132 | self.look_ahead(1, |t| t.is_keyword(keywords::Auto))) | |
1a4d82fc JJ |
7133 | { |
7134 | // UNSAFE TRAIT ITEM | |
2c00a5a8 | 7135 | self.bump(); // `unsafe` |
abe05a73 XL |
7136 | let is_auto = if self.eat_keyword(keywords::Trait) { |
7137 | IsAuto::No | |
7138 | } else { | |
2c00a5a8 XL |
7139 | self.expect_keyword(keywords::Auto)?; |
7140 | self.expect_keyword(keywords::Trait)?; | |
abe05a73 XL |
7141 | IsAuto::Yes |
7142 | }; | |
223e47cc | 7143 | let (ident, item_, extra_attrs) = |
2c00a5a8 | 7144 | self.parse_item_trait(is_auto, Unsafety::Unsafe)?; |
c30ab7b3 | 7145 | let prev_span = self.prev_span; |
cc61c64b | 7146 | let item = self.mk_item(lo.to(prev_span), |
1a4d82fc JJ |
7147 | ident, |
7148 | item_, | |
7149 | visibility, | |
7150 | maybe_append(attrs, extra_attrs)); | |
9346a6ac | 7151 | return Ok(Some(item)); |
1a4d82fc | 7152 | } |
2c00a5a8 XL |
7153 | if self.check_keyword(keywords::Impl) || |
7154 | self.check_keyword(keywords::Unsafe) && | |
7155 | self.look_ahead(1, |t| t.is_keyword(keywords::Impl)) || | |
7156 | self.check_keyword(keywords::Default) && | |
7157 | self.look_ahead(1, |t| t.is_keyword(keywords::Impl)) || | |
7158 | self.check_keyword(keywords::Default) && | |
7159 | self.look_ahead(1, |t| t.is_keyword(keywords::Unsafe)) { | |
1a4d82fc | 7160 | // IMPL ITEM |
2c00a5a8 XL |
7161 | let defaultness = self.parse_defaultness(); |
7162 | let unsafety = self.parse_unsafety(); | |
54a0048b | 7163 | self.expect_keyword(keywords::Impl)?; |
2c00a5a8 XL |
7164 | let (ident, item, extra_attrs) = self.parse_item_impl(unsafety, defaultness)?; |
7165 | let span = lo.to(self.prev_span); | |
7166 | return Ok(Some(self.mk_item(span, ident, item, visibility, | |
7167 | maybe_append(attrs, extra_attrs)))); | |
1a4d82fc | 7168 | } |
85aaf69f | 7169 | if self.check_keyword(keywords::Fn) { |
1a4d82fc | 7170 | // FUNCTION ITEM |
9cc50fc6 | 7171 | self.bump(); |
c30ab7b3 | 7172 | let fn_span = self.prev_span; |
223e47cc | 7173 | let (ident, item_, extra_attrs) = |
9e0c209e | 7174 | self.parse_item_fn(Unsafety::Normal, |
8faf50e0 | 7175 | IsAsync::NotAsync, |
9e0c209e SL |
7176 | respan(fn_span, Constness::NotConst), |
7177 | Abi::Rust)?; | |
c30ab7b3 | 7178 | let prev_span = self.prev_span; |
cc61c64b | 7179 | let item = self.mk_item(lo.to(prev_span), |
1a4d82fc JJ |
7180 | ident, |
7181 | item_, | |
7182 | visibility, | |
7183 | maybe_append(attrs, extra_attrs)); | |
9346a6ac | 7184 | return Ok(Some(item)); |
1a4d82fc | 7185 | } |
85aaf69f SL |
7186 | if self.check_keyword(keywords::Unsafe) |
7187 | && self.look_ahead(1, |t| *t != token::OpenDelim(token::Brace)) { | |
970d7e83 | 7188 | // UNSAFE FUNCTION ITEM |
2c00a5a8 | 7189 | self.bump(); // `unsafe` |
0531ce1d XL |
7190 | // `{` is also expected after `unsafe`, in case of error, include it in the diagnostic |
7191 | self.check(&token::OpenDelim(token::Brace)); | |
9cc50fc6 | 7192 | let abi = if self.eat_keyword(keywords::Extern) { |
54a0048b | 7193 | self.parse_opt_abi()?.unwrap_or(Abi::C) |
1a4d82fc | 7194 | } else { |
7453a54e | 7195 | Abi::Rust |
1a4d82fc | 7196 | }; |
54a0048b | 7197 | self.expect_keyword(keywords::Fn)?; |
c30ab7b3 | 7198 | let fn_span = self.prev_span; |
223e47cc | 7199 | let (ident, item_, extra_attrs) = |
9e0c209e | 7200 | self.parse_item_fn(Unsafety::Unsafe, |
8faf50e0 | 7201 | IsAsync::NotAsync, |
9e0c209e SL |
7202 | respan(fn_span, Constness::NotConst), |
7203 | abi)?; | |
c30ab7b3 | 7204 | let prev_span = self.prev_span; |
cc61c64b | 7205 | let item = self.mk_item(lo.to(prev_span), |
1a4d82fc JJ |
7206 | ident, |
7207 | item_, | |
7208 | visibility, | |
7209 | maybe_append(attrs, extra_attrs)); | |
9346a6ac | 7210 | return Ok(Some(item)); |
223e47cc | 7211 | } |
9cc50fc6 | 7212 | if self.eat_keyword(keywords::Mod) { |
223e47cc | 7213 | // MODULE ITEM |
970d7e83 | 7214 | let (ident, item_, extra_attrs) = |
54a0048b | 7215 | self.parse_item_mod(&attrs[..])?; |
c30ab7b3 | 7216 | let prev_span = self.prev_span; |
cc61c64b | 7217 | let item = self.mk_item(lo.to(prev_span), |
1a4d82fc JJ |
7218 | ident, |
7219 | item_, | |
7220 | visibility, | |
7221 | maybe_append(attrs, extra_attrs)); | |
9346a6ac | 7222 | return Ok(Some(item)); |
223e47cc | 7223 | } |
8faf50e0 XL |
7224 | if let Some(type_) = self.eat_type() { |
7225 | let (ident, alias, generics) = type_?; | |
223e47cc | 7226 | // TYPE ITEM |
8faf50e0 XL |
7227 | let item_ = match alias { |
7228 | AliasKind::Weak(ty) => ItemKind::Ty(ty, generics), | |
7229 | AliasKind::Existential(bounds) => ItemKind::Existential(bounds, generics), | |
7230 | }; | |
c30ab7b3 | 7231 | let prev_span = self.prev_span; |
cc61c64b | 7232 | let item = self.mk_item(lo.to(prev_span), |
1a4d82fc JJ |
7233 | ident, |
7234 | item_, | |
7235 | visibility, | |
8faf50e0 | 7236 | attrs); |
9346a6ac | 7237 | return Ok(Some(item)); |
223e47cc | 7238 | } |
9cc50fc6 | 7239 | if self.eat_keyword(keywords::Enum) { |
223e47cc | 7240 | // ENUM ITEM |
54a0048b | 7241 | let (ident, item_, extra_attrs) = self.parse_item_enum()?; |
c30ab7b3 | 7242 | let prev_span = self.prev_span; |
cc61c64b | 7243 | let item = self.mk_item(lo.to(prev_span), |
1a4d82fc JJ |
7244 | ident, |
7245 | item_, | |
7246 | visibility, | |
7247 | maybe_append(attrs, extra_attrs)); | |
9346a6ac | 7248 | return Ok(Some(item)); |
223e47cc | 7249 | } |
abe05a73 XL |
7250 | if self.check_keyword(keywords::Trait) |
7251 | || (self.check_keyword(keywords::Auto) | |
7252 | && self.look_ahead(1, |t| t.is_keyword(keywords::Trait))) | |
7253 | { | |
7254 | let is_auto = if self.eat_keyword(keywords::Trait) { | |
7255 | IsAuto::No | |
7256 | } else { | |
2c00a5a8 XL |
7257 | self.expect_keyword(keywords::Auto)?; |
7258 | self.expect_keyword(keywords::Trait)?; | |
abe05a73 XL |
7259 | IsAuto::Yes |
7260 | }; | |
223e47cc | 7261 | // TRAIT ITEM |
1a4d82fc | 7262 | let (ident, item_, extra_attrs) = |
2c00a5a8 | 7263 | self.parse_item_trait(is_auto, Unsafety::Normal)?; |
c30ab7b3 | 7264 | let prev_span = self.prev_span; |
cc61c64b | 7265 | let item = self.mk_item(lo.to(prev_span), |
1a4d82fc JJ |
7266 | ident, |
7267 | item_, | |
7268 | visibility, | |
7269 | maybe_append(attrs, extra_attrs)); | |
9346a6ac | 7270 | return Ok(Some(item)); |
223e47cc | 7271 | } |
9cc50fc6 | 7272 | if self.eat_keyword(keywords::Struct) { |
223e47cc | 7273 | // STRUCT ITEM |
54a0048b | 7274 | let (ident, item_, extra_attrs) = self.parse_item_struct()?; |
c30ab7b3 | 7275 | let prev_span = self.prev_span; |
cc61c64b | 7276 | let item = self.mk_item(lo.to(prev_span), |
1a4d82fc JJ |
7277 | ident, |
7278 | item_, | |
7279 | visibility, | |
7280 | maybe_append(attrs, extra_attrs)); | |
9346a6ac | 7281 | return Ok(Some(item)); |
223e47cc | 7282 | } |
c30ab7b3 | 7283 | if self.is_union_item() { |
9e0c209e SL |
7284 | // UNION ITEM |
7285 | self.bump(); | |
7286 | let (ident, item_, extra_attrs) = self.parse_item_union()?; | |
c30ab7b3 | 7287 | let prev_span = self.prev_span; |
cc61c64b | 7288 | let item = self.mk_item(lo.to(prev_span), |
9e0c209e SL |
7289 | ident, |
7290 | item_, | |
7291 | visibility, | |
7292 | maybe_append(attrs, extra_attrs)); | |
7293 | return Ok(Some(item)); | |
7294 | } | |
ea8adc8c | 7295 | if let Some(macro_def) = self.eat_macro_def(&attrs, &visibility, lo)? { |
8bb4bdeb XL |
7296 | return Ok(Some(macro_def)); |
7297 | } | |
7298 | ||
0531ce1d | 7299 | // Verify whether we have encountered a struct or method definition where the user forgot to |
ff7c6d11 | 7300 | // add the `struct` or `fn` keyword after writing `pub`: `pub S {}` |
8faf50e0 | 7301 | if visibility.node.is_pub() && |
ff7c6d11 XL |
7302 | self.check_ident() && |
7303 | self.look_ahead(1, |t| *t != token::Not) | |
7304 | { | |
7305 | // Space between `pub` keyword and the identifier | |
7306 | // | |
7307 | // pub S {} | |
7308 | // ^^^ `sp` points here | |
7309 | let sp = self.prev_span.between(self.span); | |
7310 | let full_sp = self.prev_span.to(self.span); | |
7311 | let ident_sp = self.span; | |
7312 | if self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) { | |
7313 | // possible public struct definition where `struct` was forgotten | |
7314 | let ident = self.parse_ident().unwrap(); | |
7315 | let msg = format!("add `struct` here to parse `{}` as a public struct", | |
7316 | ident); | |
7317 | let mut err = self.diagnostic() | |
7318 | .struct_span_err(sp, "missing `struct` for struct definition"); | |
94b46f34 XL |
7319 | err.span_suggestion_short_with_applicability( |
7320 | sp, &msg, " struct ".into(), Applicability::MaybeIncorrect // speculative | |
7321 | ); | |
ff7c6d11 XL |
7322 | return Err(err); |
7323 | } else if self.look_ahead(1, |t| *t == token::OpenDelim(token::Paren)) { | |
7324 | let ident = self.parse_ident().unwrap(); | |
7325 | self.consume_block(token::Paren); | |
7326 | let (kw, kw_name, ambiguous) = if self.check(&token::RArrow) || | |
7327 | self.check(&token::OpenDelim(token::Brace)) | |
7328 | { | |
7329 | ("fn", "method", false) | |
7330 | } else if self.check(&token::Colon) { | |
7331 | let kw = "struct"; | |
7332 | (kw, kw, false) | |
7333 | } else { | |
7334 | ("fn` or `struct", "method or struct", true) | |
7335 | }; | |
7336 | ||
7337 | let msg = format!("missing `{}` for {} definition", kw, kw_name); | |
7338 | let mut err = self.diagnostic().struct_span_err(sp, &msg); | |
7339 | if !ambiguous { | |
7340 | let suggestion = format!("add `{}` here to parse `{}` as a public {}", | |
7341 | kw, | |
7342 | ident, | |
7343 | kw_name); | |
94b46f34 XL |
7344 | err.span_suggestion_short_with_applicability( |
7345 | sp, &suggestion, format!(" {} ", kw), Applicability::MachineApplicable | |
7346 | ); | |
ff7c6d11 | 7347 | } else { |
b7449926 | 7348 | if let Ok(snippet) = self.sess.source_map().span_to_snippet(ident_sp) { |
94b46f34 | 7349 | err.span_suggestion_with_applicability( |
ff7c6d11 | 7350 | full_sp, |
94b46f34 XL |
7351 | "if you meant to call a macro, try", |
7352 | format!("{}!", snippet), | |
7353 | // this is the `ambiguous` conditional branch | |
7354 | Applicability::MaybeIncorrect | |
7355 | ); | |
ff7c6d11 XL |
7356 | } else { |
7357 | err.help("if you meant to call a macro, remove the `pub` \ | |
7358 | and add a trailing `!` after the identifier"); | |
7359 | } | |
7360 | } | |
7361 | return Err(err); | |
7362 | } | |
7363 | } | |
7364 | self.parse_macro_use_or_failure(attrs, macros_allowed, attributes_allowed, lo, visibility) | |
970d7e83 LB |
7365 | } |
7366 | ||
c34b1796 | 7367 | /// Parse a foreign item. |
0bf4aa26 XL |
7368 | crate fn parse_foreign_item(&mut self) -> PResult<'a, ForeignItem> { |
7369 | maybe_whole!(self, NtForeignItem, |ni| ni); | |
83c7162d | 7370 | |
54a0048b | 7371 | let attrs = self.parse_outer_attributes()?; |
cc61c64b XL |
7372 | let lo = self.span; |
7373 | let visibility = self.parse_visibility(false)?; | |
970d7e83 | 7374 | |
3b2f2976 XL |
7375 | // FOREIGN STATIC ITEM |
7376 | // Treat `const` as `static` for error recovery, but don't add it to expected tokens. | |
7377 | if self.check_keyword(keywords::Static) || self.token.is_keyword(keywords::Const) { | |
7378 | if self.token.is_keyword(keywords::Const) { | |
7379 | self.diagnostic() | |
7380 | .struct_span_err(self.span, "extern items cannot be `const`") | |
94b46f34 XL |
7381 | .span_suggestion_with_applicability( |
7382 | self.span, | |
7383 | "try using a static value", | |
7384 | "static".to_owned(), | |
7385 | Applicability::MachineApplicable | |
7386 | ).emit(); | |
3b2f2976 XL |
7387 | } |
7388 | self.bump(); // `static` or `const` | |
0bf4aa26 | 7389 | return Ok(self.parse_item_foreign_static(visibility, lo, attrs)?); |
970d7e83 | 7390 | } |
3b2f2976 | 7391 | // FOREIGN FUNCTION ITEM |
a7813a04 | 7392 | if self.check_keyword(keywords::Fn) { |
0bf4aa26 | 7393 | return Ok(self.parse_item_foreign_fn(visibility, lo, attrs)?); |
223e47cc | 7394 | } |
abe05a73 XL |
7395 | // FOREIGN TYPE ITEM |
7396 | if self.check_keyword(keywords::Type) { | |
0bf4aa26 | 7397 | return Ok(self.parse_item_foreign_type(visibility, lo, attrs)?); |
abe05a73 | 7398 | } |
85aaf69f | 7399 | |
83c7162d XL |
7400 | match self.parse_assoc_macro_invoc("extern", Some(&visibility), &mut false)? { |
7401 | Some(mac) => { | |
0bf4aa26 | 7402 | Ok( |
83c7162d XL |
7403 | ForeignItem { |
7404 | ident: keywords::Invalid.ident(), | |
7405 | span: lo.to(self.prev_span), | |
7406 | id: ast::DUMMY_NODE_ID, | |
7407 | attrs, | |
7408 | vis: visibility, | |
7409 | node: ForeignItemKind::Macro(mac), | |
7410 | } | |
0bf4aa26 | 7411 | ) |
83c7162d XL |
7412 | } |
7413 | None => { | |
0bf4aa26 | 7414 | if !attrs.is_empty() { |
83c7162d XL |
7415 | self.expected_item_err(&attrs); |
7416 | } | |
7417 | ||
0bf4aa26 | 7418 | self.unexpected() |
c34b1796 | 7419 | } |
c34b1796 | 7420 | } |
970d7e83 LB |
7421 | } |
7422 | ||
1a4d82fc | 7423 | /// This is the fall-through for parsing items. |
970d7e83 | 7424 | fn parse_macro_use_or_failure( |
1a4d82fc JJ |
7425 | &mut self, |
7426 | attrs: Vec<Attribute> , | |
970d7e83 | 7427 | macros_allowed: bool, |
92a42be0 | 7428 | attributes_allowed: bool, |
cc61c64b | 7429 | lo: Span, |
1a4d82fc | 7430 | visibility: Visibility |
9cc50fc6 | 7431 | ) -> PResult<'a, Option<P<Item>>> { |
9e0c209e | 7432 | if macros_allowed && self.token.is_path_start() { |
223e47cc | 7433 | // MACRO INVOCATION ITEM |
223e47cc | 7434 | |
c30ab7b3 | 7435 | let prev_span = self.prev_span; |
0531ce1d | 7436 | self.complain_if_pub_macro(&visibility.node, prev_span); |
85aaf69f | 7437 | |
cc61c64b | 7438 | let mac_lo = self.span; |
92a42be0 | 7439 | |
223e47cc | 7440 | // item macro. |
9e0c209e | 7441 | let pth = self.parse_path(PathStyle::Mod)?; |
54a0048b | 7442 | self.expect(&token::Not)?; |
223e47cc LB |
7443 | |
7444 | // a 'special' identifier (like what `macro_rules!` uses) | |
7445 | // is optional. We should eventually unify invoc syntax | |
7446 | // and remove this. | |
a7813a04 | 7447 | let id = if self.token.is_ident() { |
54a0048b | 7448 | self.parse_ident()? |
223e47cc | 7449 | } else { |
a7813a04 | 7450 | keywords::Invalid.ident() // no special identifier |
223e47cc LB |
7451 | }; |
7452 | // eat a matched-delimiter token tree: | |
8bb4bdeb | 7453 | let (delim, tts) = self.expect_delimited_token_tree()?; |
94b46f34 | 7454 | if delim != MacDelimiter::Brace { |
9cc50fc6 | 7455 | if !self.eat(&token::Semi) { |
3b2f2976 | 7456 | self.span_err(self.prev_span, |
1a4d82fc JJ |
7457 | "macros that expand to items must either \ |
7458 | be surrounded with braces or followed by \ | |
7459 | a semicolon"); | |
7460 | } | |
7461 | } | |
7462 | ||
cc61c64b | 7463 | let hi = self.prev_span; |
94b46f34 | 7464 | let mac = respan(mac_lo.to(hi), Mac_ { path: pth, tts, delim }); |
cc61c64b | 7465 | let item = self.mk_item(lo.to(hi), id, ItemKind::Mac(mac), visibility, attrs); |
9346a6ac | 7466 | return Ok(Some(item)); |
223e47cc LB |
7467 | } |
7468 | ||
7469 | // FAILURE TO PARSE ITEM | |
0531ce1d XL |
7470 | match visibility.node { |
7471 | VisibilityKind::Inherited => {} | |
54a0048b | 7472 | _ => { |
3b2f2976 | 7473 | return Err(self.span_fatal(self.prev_span, "unmatched visibility `pub`")); |
970d7e83 | 7474 | } |
223e47cc | 7475 | } |
223e47cc | 7476 | |
92a42be0 | 7477 | if !attributes_allowed && !attrs.is_empty() { |
c34b1796 AL |
7478 | self.expected_item_err(&attrs); |
7479 | } | |
9346a6ac | 7480 | Ok(None) |
1a4d82fc JJ |
7481 | } |
7482 | ||
83c7162d XL |
7483 | /// Parse a macro invocation inside a `trait`, `impl` or `extern` block |
7484 | fn parse_assoc_macro_invoc(&mut self, item_kind: &str, vis: Option<&Visibility>, | |
7485 | at_end: &mut bool) -> PResult<'a, Option<Mac>> | |
7486 | { | |
7487 | if self.token.is_path_start() && !self.is_extern_non_path() { | |
7488 | let prev_span = self.prev_span; | |
7489 | let lo = self.span; | |
7490 | let pth = self.parse_path(PathStyle::Mod)?; | |
7491 | ||
7492 | if pth.segments.len() == 1 { | |
7493 | if !self.eat(&token::Not) { | |
7494 | return Err(self.missing_assoc_item_kind_err(item_kind, prev_span)); | |
7495 | } | |
7496 | } else { | |
7497 | self.expect(&token::Not)?; | |
7498 | } | |
7499 | ||
7500 | if let Some(vis) = vis { | |
7501 | self.complain_if_pub_macro(&vis.node, prev_span); | |
7502 | } | |
7503 | ||
7504 | *at_end = true; | |
7505 | ||
7506 | // eat a matched-delimiter token tree: | |
7507 | let (delim, tts) = self.expect_delimited_token_tree()?; | |
94b46f34 | 7508 | if delim != MacDelimiter::Brace { |
83c7162d XL |
7509 | self.expect(&token::Semi)? |
7510 | } | |
7511 | ||
94b46f34 | 7512 | Ok(Some(respan(lo.to(self.prev_span), Mac_ { path: pth, tts, delim }))) |
83c7162d XL |
7513 | } else { |
7514 | Ok(None) | |
7515 | } | |
7516 | } | |
7517 | ||
3b2f2976 XL |
7518 | fn collect_tokens<F, R>(&mut self, f: F) -> PResult<'a, (R, TokenStream)> |
7519 | where F: FnOnce(&mut Self) -> PResult<'a, R> | |
7520 | { | |
7521 | // Record all tokens we parse when parsing this item. | |
7522 | let mut tokens = Vec::new(); | |
8faf50e0 XL |
7523 | let prev_collecting = match self.token_cursor.frame.last_token { |
7524 | LastToken::Collecting(ref mut list) => { | |
7525 | Some(mem::replace(list, Vec::new())) | |
3b2f2976 | 7526 | } |
8faf50e0 XL |
7527 | LastToken::Was(ref mut last) => { |
7528 | tokens.extend(last.take()); | |
7529 | None | |
7530 | } | |
7531 | }; | |
3b2f2976 XL |
7532 | self.token_cursor.frame.last_token = LastToken::Collecting(tokens); |
7533 | let prev = self.token_cursor.stack.len(); | |
7534 | let ret = f(self); | |
7535 | let last_token = if self.token_cursor.stack.len() == prev { | |
7536 | &mut self.token_cursor.frame.last_token | |
7537 | } else { | |
7538 | &mut self.token_cursor.stack[prev].last_token | |
7539 | }; | |
8faf50e0 XL |
7540 | |
7541 | // Pull our the toekns that we've collected from the call to `f` above | |
7542 | let mut collected_tokens = match *last_token { | |
3b2f2976 XL |
7543 | LastToken::Collecting(ref mut v) => mem::replace(v, Vec::new()), |
7544 | LastToken::Was(_) => panic!("our vector went away?"), | |
7545 | }; | |
7546 | ||
7547 | // If we're not at EOF our current token wasn't actually consumed by | |
7548 | // `f`, but it'll still be in our list that we pulled out. In that case | |
7549 | // put it back. | |
8faf50e0 XL |
7550 | let extra_token = if self.token != token::Eof { |
7551 | collected_tokens.pop() | |
3b2f2976 | 7552 | } else { |
8faf50e0 XL |
7553 | None |
7554 | }; | |
7555 | ||
7556 | // If we were previously collecting tokens, then this was a recursive | |
7557 | // call. In that case we need to record all the tokens we collected in | |
7558 | // our parent list as well. To do that we push a clone of our stream | |
7559 | // onto the previous list. | |
7560 | let stream = collected_tokens.into_iter().collect::<TokenStream>(); | |
7561 | match prev_collecting { | |
7562 | Some(mut list) => { | |
7563 | list.push(stream.clone()); | |
7564 | list.extend(extra_token); | |
7565 | *last_token = LastToken::Collecting(list); | |
7566 | } | |
7567 | None => { | |
7568 | *last_token = LastToken::Was(extra_token); | |
7569 | } | |
3b2f2976 XL |
7570 | } |
7571 | ||
8faf50e0 | 7572 | Ok((ret?, stream)) |
3b2f2976 XL |
7573 | } |
7574 | ||
9cc50fc6 | 7575 | pub fn parse_item(&mut self) -> PResult<'a, Option<P<Item>>> { |
54a0048b | 7576 | let attrs = self.parse_outer_attributes()?; |
8faf50e0 | 7577 | self.parse_item_(attrs, true, false) |
223e47cc LB |
7578 | } |
7579 | ||
0531ce1d XL |
7580 | /// `::{` or `::*` |
7581 | fn is_import_coupler(&mut self) -> bool { | |
7582 | self.check(&token::ModSep) && | |
7583 | self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace) || | |
7584 | *t == token::BinOp(token::Star)) | |
a7813a04 XL |
7585 | } |
7586 | ||
ff7c6d11 XL |
7587 | /// Parse UseTree |
7588 | /// | |
0531ce1d XL |
7589 | /// USE_TREE = [`::`] `*` | |
7590 | /// [`::`] `{` USE_TREE_LIST `}` | | |
ff7c6d11 XL |
7591 | /// PATH `::` `*` | |
7592 | /// PATH `::` `{` USE_TREE_LIST `}` | | |
7593 | /// PATH [`as` IDENT] | |
0531ce1d | 7594 | fn parse_use_tree(&mut self) -> PResult<'a, UseTree> { |
cc61c64b | 7595 | let lo = self.span; |
ff7c6d11 | 7596 | |
0531ce1d XL |
7597 | let mut prefix = ast::Path { segments: Vec::new(), span: lo.shrink_to_lo() }; |
7598 | let kind = if self.check(&token::OpenDelim(token::Brace)) || | |
7599 | self.check(&token::BinOp(token::Star)) || | |
7600 | self.is_import_coupler() { | |
7601 | // `use *;` or `use ::*;` or `use {...};` or `use ::{...};` | |
ff7c6d11 | 7602 | if self.eat(&token::ModSep) { |
0531ce1d | 7603 | prefix.segments.push(PathSegment::crate_root(lo.shrink_to_lo())); |
ff7c6d11 XL |
7604 | } |
7605 | ||
7606 | if self.eat(&token::BinOp(token::Star)) { | |
ff7c6d11 | 7607 | UseTreeKind::Glob |
c30ab7b3 | 7608 | } else { |
0531ce1d | 7609 | UseTreeKind::Nested(self.parse_use_tree_list()?) |
ff7c6d11 | 7610 | } |
a7813a04 | 7611 | } else { |
0531ce1d XL |
7612 | // `use path::*;` or `use path::{...};` or `use path;` or `use path as bar;` |
7613 | prefix = self.parse_path(PathStyle::Mod)?; | |
ff7c6d11 XL |
7614 | |
7615 | if self.eat(&token::ModSep) { | |
7616 | if self.eat(&token::BinOp(token::Star)) { | |
ff7c6d11 | 7617 | UseTreeKind::Glob |
a7813a04 | 7618 | } else { |
0531ce1d | 7619 | UseTreeKind::Nested(self.parse_use_tree_list()?) |
223e47cc | 7620 | } |
a7813a04 | 7621 | } else { |
94b46f34 | 7622 | UseTreeKind::Simple(self.parse_rename()?, ast::DUMMY_NODE_ID, ast::DUMMY_NODE_ID) |
223e47cc | 7623 | } |
ff7c6d11 XL |
7624 | }; |
7625 | ||
0531ce1d | 7626 | Ok(UseTree { prefix, kind, span: lo.to(self.prev_span) }) |
ff7c6d11 XL |
7627 | } |
7628 | ||
7629 | /// Parse UseTreeKind::Nested(list) | |
7630 | /// | |
7631 | /// USE_TREE_LIST = Ø | (USE_TREE `,`)* USE_TREE [`,`] | |
7632 | fn parse_use_tree_list(&mut self) -> PResult<'a, Vec<(UseTree, ast::NodeId)>> { | |
7633 | self.parse_unspanned_seq(&token::OpenDelim(token::Brace), | |
7634 | &token::CloseDelim(token::Brace), | |
7635 | SeqSep::trailing_allowed(token::Comma), |this| { | |
0531ce1d | 7636 | Ok((this.parse_use_tree()?, ast::DUMMY_NODE_ID)) |
ff7c6d11 | 7637 | }) |
e9174d1e SL |
7638 | } |
7639 | ||
9cc50fc6 SL |
7640 | fn parse_rename(&mut self) -> PResult<'a, Option<Ident>> { |
7641 | if self.eat_keyword(keywords::As) { | |
0531ce1d XL |
7642 | match self.token { |
7643 | token::Ident(ident, false) if ident.name == keywords::Underscore.name() => { | |
7644 | self.bump(); // `_` | |
8faf50e0 | 7645 | Ok(Some(ident.gensym())) |
0531ce1d XL |
7646 | } |
7647 | _ => self.parse_ident().map(Some), | |
7648 | } | |
e9174d1e SL |
7649 | } else { |
7650 | Ok(None) | |
1a4d82fc | 7651 | } |
970d7e83 LB |
7652 | } |
7653 | ||
1a4d82fc JJ |
7654 | /// Parses a source module as a crate. This is the main |
7655 | /// entry point for the parser. | |
9cc50fc6 | 7656 | pub fn parse_crate_mod(&mut self) -> PResult<'a, Crate> { |
cc61c64b | 7657 | let lo = self.span; |
9346a6ac | 7658 | Ok(ast::Crate { |
54a0048b SL |
7659 | attrs: self.parse_inner_attributes()?, |
7660 | module: self.parse_mod_items(&token::Eof, lo)?, | |
cc61c64b | 7661 | span: lo.to(self.span), |
9346a6ac | 7662 | }) |
223e47cc LB |
7663 | } |
7664 | ||
8faf50e0 | 7665 | pub fn parse_optional_str(&mut self) -> Option<(Symbol, ast::StrStyle, Option<ast::Name>)> { |
1a4d82fc | 7666 | let ret = match self.token { |
476ff2be SL |
7667 | token::Literal(token::Str_(s), suf) => (s, ast::StrStyle::Cooked, suf), |
7668 | token::Literal(token::StrRaw(s, n), suf) => (s, ast::StrStyle::Raw(n), suf), | |
9cc50fc6 | 7669 | _ => return None |
1a4d82fc | 7670 | }; |
9cc50fc6 SL |
7671 | self.bump(); |
7672 | Some(ret) | |
1a4d82fc JJ |
7673 | } |
7674 | ||
476ff2be | 7675 | pub fn parse_str(&mut self) -> PResult<'a, (Symbol, StrStyle)> { |
9cc50fc6 | 7676 | match self.parse_optional_str() { |
1a4d82fc | 7677 | Some((s, style, suf)) => { |
c30ab7b3 | 7678 | let sp = self.prev_span; |
e9174d1e | 7679 | self.expect_no_suffix(sp, "string literal", suf); |
9346a6ac | 7680 | Ok((s, style)) |
970d7e83 | 7681 | } |
0531ce1d XL |
7682 | _ => { |
7683 | let msg = "expected string literal"; | |
7684 | let mut err = self.fatal(msg); | |
7685 | err.span_label(self.span, msg); | |
7686 | Err(err) | |
7687 | } | |
223e47cc LB |
7688 | } |
7689 | } | |
7690 | } |