]> git.lizzy.rs Git - rust.git/blobdiff - compiler/rustc_parse/src/parser/expr.rs
Add support for using qualified paths with structs in expression and pattern
[rust.git] / compiler / rustc_parse / src / parser / expr.rs
index 02ee268b88c29cc24a0b3a25bd6e6752bb46189d..c8789abc142d6cf1179a8f0bf712398656e58620 100644 (file)
@@ -94,17 +94,7 @@ pub fn parse_expr(&mut self) -> PResult<'a, P<Expr>> {
 
     /// Parses an expression, forcing tokens to be collected
     pub fn parse_expr_force_collect(&mut self) -> PResult<'a, P<Expr>> {
-        // If we have outer attributes, then the call to `collect_tokens_trailing_token`
-        // will be made for us.
-        if matches!(self.token.kind, TokenKind::Pound | TokenKind::DocComment(..)) {
-            self.parse_expr()
-        } else {
-            // If we don't have outer attributes, then we need to ensure
-            // that collection happens by using `collect_tokens_no_attrs`.
-            // Expression don't support custom inner attributes, so `parse_expr`
-            // will never try to collect tokens if we don't have outer attributes.
-            self.collect_tokens_no_attrs(|this| this.parse_expr())
-        }
+        self.collect_tokens_no_attrs(|this| this.parse_expr())
     }
 
     pub fn parse_anon_const_expr(&mut self) -> PResult<'a, AnonConst> {
@@ -1118,9 +1108,6 @@ fn parse_bottom_expr(&mut self) -> PResult<'a, P<Expr>> {
             self.parse_closure_expr(attrs)
         } else if self.check(&token::OpenDelim(token::Bracket)) {
             self.parse_array_or_repeat_expr(attrs)
-        } else if self.eat_lt() {
-            let (qself, path) = self.parse_qpath(PathStyle::Expr)?;
-            Ok(self.mk_expr(lo.to(path.span), ExprKind::Path(Some(qself), path), attrs))
         } else if self.check_path() {
             self.parse_path_start_expr(attrs)
         } else if self.check_keyword(kw::Move) || self.check_keyword(kw::Static) {
@@ -1216,10 +1203,9 @@ fn parse_lit_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
         }
     }
 
-    fn parse_tuple_parens_expr(&mut self, mut attrs: AttrVec) -> PResult<'a, P<Expr>> {
+    fn parse_tuple_parens_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
         let lo = self.token.span;
         self.expect(&token::OpenDelim(token::Paren))?;
-        attrs.extend(self.parse_inner_attributes()?); // `(#![foo] a, b, ...)` is OK.
         let (es, trailing_comma) = match self.parse_seq_to_end(
             &token::CloseDelim(token::Paren),
             SeqSep::trailing_allowed(token::Comma),
@@ -1239,12 +1225,10 @@ fn parse_tuple_parens_expr(&mut self, mut attrs: AttrVec) -> PResult<'a, P<Expr>
         self.maybe_recover_from_bad_qpath(expr, true)
     }
 
-    fn parse_array_or_repeat_expr(&mut self, mut attrs: AttrVec) -> PResult<'a, P<Expr>> {
+    fn parse_array_or_repeat_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
         let lo = self.token.span;
         self.bump(); // `[`
 
-        attrs.extend(self.parse_inner_attributes()?);
-
         let close = &token::CloseDelim(token::Bracket);
         let kind = if self.eat(close) {
             // Empty vector
@@ -1275,12 +1259,20 @@ fn parse_array_or_repeat_expr(&mut self, mut attrs: AttrVec) -> PResult<'a, P<Ex
     }
 
     fn parse_path_start_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
-        let path = self.parse_path(PathStyle::Expr)?;
+        let (qself, path) = if self.eat_lt() {
+            let (qself, path) = self.parse_qpath(PathStyle::Expr)?;
+            (Some(qself), path)
+        } else {
+            (None, self.parse_path(PathStyle::Expr)?)
+        };
         let lo = path.span;
 
         // `!`, as an operator, is prefix, so we know this isn't that.
         let (hi, kind) = if self.eat(&token::Not) {
             // MACRO INVOCATION expression
+            if qself.is_some() {
+                self.struct_span_err(path.span, "macros cannot use qualified paths").emit();
+            }
             let mac = MacCall {
                 path,
                 args: self.parse_mac_args()?,
@@ -1288,13 +1280,16 @@ fn parse_path_start_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
             };
             (self.prev_token.span, ExprKind::MacCall(mac))
         } else if self.check(&token::OpenDelim(token::Brace)) {
-            if let Some(expr) = self.maybe_parse_struct_expr(&path, &attrs) {
+            if let Some(expr) = self.maybe_parse_struct_expr(qself.as_ref(), &path, &attrs) {
+                if qself.is_some() {
+                    self.sess.gated_spans.gate(sym::more_qualified_paths, path.span);
+                }
                 return expr;
             } else {
-                (path.span, ExprKind::Path(None, path))
+                (path.span, ExprKind::Path(qself, path))
             }
         } else {
-            (path.span, ExprKind::Path(None, path))
+            (path.span, ExprKind::Path(qself, path))
         };
 
         let expr = self.mk_expr(lo.to(hi), kind, attrs);
@@ -1950,7 +1945,7 @@ fn eat_label(&mut self) -> Option<Label> {
     }
 
     /// Parses a `match ... { ... }` expression (`match` token already eaten).
-    fn parse_match_expr(&mut self, mut attrs: AttrVec) -> PResult<'a, P<Expr>> {
+    fn parse_match_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
         let match_span = self.prev_token.span;
         let lo = self.prev_token.span;
         let scrutinee = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
@@ -1965,7 +1960,6 @@ fn parse_match_expr(&mut self, mut attrs: AttrVec) -> PResult<'a, P<Expr>> {
             }
             return Err(e);
         }
-        attrs.extend(self.parse_inner_attributes()?);
 
         let mut arms: Vec<Arm> = Vec::new();
         while self.token != token::CloseDelim(token::Brace) {
@@ -2261,6 +2255,7 @@ fn is_certainly_not_a_block(&self) -> bool {
 
     fn maybe_parse_struct_expr(
         &mut self,
+        qself: Option<&ast::QSelf>,
         path: &ast::Path,
         attrs: &AttrVec,
     ) -> Option<PResult<'a, P<Expr>>> {
@@ -2269,7 +2264,7 @@ fn maybe_parse_struct_expr(
             if let Err(err) = self.expect(&token::OpenDelim(token::Brace)) {
                 return Some(Err(err));
             }
-            let expr = self.parse_struct_expr(path.clone(), attrs.clone(), true);
+            let expr = self.parse_struct_expr(qself.cloned(), path.clone(), attrs.clone(), true);
             if let (Ok(expr), false) = (&expr, struct_allowed) {
                 // This is a struct literal, but we don't can't accept them here.
                 self.error_struct_lit_not_allowed_here(path.span, expr.span);
@@ -2292,16 +2287,15 @@ fn error_struct_lit_not_allowed_here(&self, lo: Span, sp: Span) {
     /// Precondition: already parsed the '{'.
     pub(super) fn parse_struct_expr(
         &mut self,
+        qself: Option<ast::QSelf>,
         pth: ast::Path,
-        mut attrs: AttrVec,
+        attrs: AttrVec,
         recover: bool,
     ) -> PResult<'a, P<Expr>> {
         let mut fields = Vec::new();
         let mut base = ast::StructRest::None;
         let mut recover_async = false;
 
-        attrs.extend(self.parse_inner_attributes()?);
-
         let mut async_block_err = |e: &mut DiagnosticBuilder<'_>, span: Span| {
             recover_async = true;
             e.span_label(span, "`async` blocks are only allowed in Rust 2018 or later");
@@ -2391,7 +2385,7 @@ pub(super) fn parse_struct_expr(
         let expr = if recover_async {
             ExprKind::Err
         } else {
-            ExprKind::Struct(P(ast::StructExpr { path: pth, fields, rest: base }))
+            ExprKind::Struct(P(ast::StructExpr { qself, path: pth, fields, rest: base }))
         };
         Ok(self.mk_expr(span, expr, attrs))
     }
@@ -2581,19 +2575,17 @@ fn collect_tokens_for_expr(
         attrs: AttrWrapper,
         f: impl FnOnce(&mut Self, Vec<ast::Attribute>) -> PResult<'a, P<Expr>>,
     ) -> PResult<'a, P<Expr>> {
-        // FIXME - come up with a nice way to properly forward `ForceCollect`from
-        // the nonterminal parsing code. TThis approach iscorrect, but will cause
-        // us to unnecessarily capture tokens for exprs that have only builtin
-        // attributes. Revisit this before #![feature(stmt_expr_attributes)] is stabilized
-        let force_collect = if attrs.is_empty() { ForceCollect::No } else { ForceCollect::Yes };
-        self.collect_tokens_trailing_token(attrs, force_collect, |this, attrs| {
+        self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
             let res = f(this, attrs)?;
             let trailing = if this.restrictions.contains(Restrictions::STMT_EXPR)
                 && this.token.kind == token::Semi
             {
                 TrailingToken::Semi
             } else {
-                TrailingToken::None
+                // FIXME - pass this through from the place where we know
+                // we need a comma, rather than assuming that `#[attr] expr,`
+                // always captures a trailing comma
+                TrailingToken::MaybeComma
             };
             Ok((res, trailing))
         })