about summary refs log tree commit diff
path: root/src/libsyntax/parse
diff options
context:
space:
mode:
authorjohnthagen <johnthagen@users.noreply.github.com>2017-10-16 17:56:12 -0400
committerGitHub <noreply@github.com>2017-10-16 17:56:12 -0400
commitbd8497884c2863a10b6d67855bd90d40783ce2da (patch)
tree5fe9ffe7f65dbea1130217b5136264d4dbc7b513 /src/libsyntax/parse
parent49a73d0901a60b1b77452b92372fd8629f636c2a (diff)
parent4e9527cf6f2d3749554d07a96fe14967f5470ef6 (diff)
downloadrust-bd8497884c2863a10b6d67855bd90d40783ce2da.tar.gz
rust-bd8497884c2863a10b6d67855bd90d40783ce2da.zip
Merge branch 'master' into future_imports
Diffstat (limited to 'src/libsyntax/parse')
-rw-r--r--src/libsyntax/parse/lexer/unicode_chars.rs2
-rw-r--r--src/libsyntax/parse/parser.rs97
-rw-r--r--src/libsyntax/parse/token.rs6
3 files changed, 75 insertions, 30 deletions
diff --git a/src/libsyntax/parse/lexer/unicode_chars.rs b/src/libsyntax/parse/lexer/unicode_chars.rs
index 39b5482a066..35afe8dd56d 100644
--- a/src/libsyntax/parse/lexer/unicode_chars.rs
+++ b/src/libsyntax/parse/lexer/unicode_chars.rs
@@ -144,7 +144,7 @@ const UNICODE_ARRAY: &'static [(char, &'static str, char)] = &[
     ('‵', "Reversed Prime", '\''),
     ('՚', "Armenian Apostrophe", '\''),
     ('׳', "Hebrew Punctuation Geresh", '\''),
-    ('`', "Greek Accent", '\''),
+    ('`', "Grave Accent", '\''),
     ('`', "Greek Varia", '\''),
     ('`', "Fullwidth Grave Accent", '\''),
     ('´', "Acute Accent", '\''),
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 978e06c75dd..bd400ef6dd6 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -33,7 +33,7 @@ use ast::{Stmt, StmtKind};
 use ast::{VariantData, StructField};
 use ast::StrStyle;
 use ast::SelfKind;
-use ast::{TraitItem, TraitRef};
+use ast::{TraitItem, TraitRef, TraitObjectSyntax};
 use ast::{Ty, TyKind, TypeBinding, TyParam, TyParamBounds};
 use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
 use ast::{Visibility, WhereClause};
@@ -364,6 +364,13 @@ fn is_ident_or_underscore(t: &token::Token) -> bool {
     t.is_ident() || *t == token::Underscore
 }
 
+// Returns true if `IDENT t` can start a type - `IDENT::a::b`, `IDENT<u8, u8>`,
+// `IDENT<<u8 as Trait>::AssocTy>`, `IDENT(u8, u8) -> u8`.
+fn can_continue_type_after_ident(t: &token::Token) -> bool {
+    t == &token::ModSep || t == &token::Lt ||
+    t == &token::BinOp(token::Shl) || t == &token::OpenDelim(token::Paren)
+}
+
 /// Information about the path to a module.
 pub struct ModulePath {
     pub name: String,
@@ -1428,7 +1435,7 @@ impl<'a> Parser<'a> {
                     TyKind::Path(None, ref path) if maybe_bounds => {
                         self.parse_remaining_bounds(Vec::new(), path.clone(), lo, true)?
                     }
-                    TyKind::TraitObject(ref bounds)
+                    TyKind::TraitObject(ref bounds, TraitObjectSyntax::None)
                             if maybe_bounds && bounds.len() == 1 && !trailing_plus => {
                         let path = match bounds[0] {
                             TraitTyParamBound(ref pt, ..) => pt.trait_ref.path.clone(),
@@ -1472,27 +1479,6 @@ impl<'a> Parser<'a> {
         } else if self.eat(&token::Underscore) {
             // A type to be inferred `_`
             TyKind::Infer
-        } else if self.eat_lt() {
-            // Qualified path
-            let (qself, path) = self.parse_qpath(PathStyle::Type)?;
-            TyKind::Path(Some(qself), path)
-        } else if self.token.is_path_start() {
-            // Simple path
-            let path = self.parse_path(PathStyle::Type)?;
-            if self.eat(&token::Not) {
-                // Macro invocation in type position
-                let (_, tts) = self.expect_delimited_token_tree()?;
-                TyKind::Mac(respan(lo.to(self.span), Mac_ { path: path, tts: tts }))
-            } else {
-                // Just a type path or bound list (trait object type) starting with a trait.
-                //   `Type`
-                //   `Trait1 + Trait2 + 'a`
-                if allow_plus && self.check(&token::BinOp(token::Plus)) {
-                    self.parse_remaining_bounds(Vec::new(), path, lo, true)?
-                } else {
-                    TyKind::Path(None, path)
-                }
-            }
         } else if self.token_is_bare_fn_keyword() {
             // Function pointer type
             self.parse_ty_bare_fn(Vec::new())?
@@ -1512,10 +1498,37 @@ impl<'a> Parser<'a> {
         } else if self.eat_keyword(keywords::Impl) {
             // FIXME: figure out priority of `+` in `impl Trait1 + Trait2` (#34511).
             TyKind::ImplTrait(self.parse_ty_param_bounds()?)
+        } else if self.check_keyword(keywords::Dyn) &&
+                  self.look_ahead(1, |t| t.can_begin_bound() && !can_continue_type_after_ident(t)) {
+            // FIXME: figure out priority of `+` in `dyn Trait1 + Trait2` (#34511).
+            self.bump(); // `dyn`
+            TyKind::TraitObject(self.parse_ty_param_bounds()?, TraitObjectSyntax::Dyn)
         } else if self.check(&token::Question) ||
-                  self.check_lifetime() && self.look_ahead(1, |t| t == &token::BinOp(token::Plus)){
+                  self.check_lifetime() && self.look_ahead(1, |t| t == &token::BinOp(token::Plus)) {
             // Bound list (trait object type)
-            TyKind::TraitObject(self.parse_ty_param_bounds_common(allow_plus)?)
+            TyKind::TraitObject(self.parse_ty_param_bounds_common(allow_plus)?,
+                                TraitObjectSyntax::None)
+        } else if self.eat_lt() {
+            // Qualified path
+            let (qself, path) = self.parse_qpath(PathStyle::Type)?;
+            TyKind::Path(Some(qself), path)
+        } else if self.token.is_path_start() {
+            // Simple path
+            let path = self.parse_path(PathStyle::Type)?;
+            if self.eat(&token::Not) {
+                // Macro invocation in type position
+                let (_, tts) = self.expect_delimited_token_tree()?;
+                TyKind::Mac(respan(lo.to(self.span), Mac_ { path: path, tts: tts }))
+            } else {
+                // Just a type path or bound list (trait object type) starting with a trait.
+                //   `Type`
+                //   `Trait1 + Trait2 + 'a`
+                if allow_plus && self.check(&token::BinOp(token::Plus)) {
+                    self.parse_remaining_bounds(Vec::new(), path, lo, true)?
+                } else {
+                    TyKind::Path(None, path)
+                }
+            }
         } else {
             let msg = format!("expected type, found {}", self.this_token_descr());
             return Err(self.fatal(&msg));
@@ -1538,7 +1551,7 @@ impl<'a> Parser<'a> {
             self.bump(); // `+`
             bounds.append(&mut self.parse_ty_param_bounds()?);
         }
-        Ok(TyKind::TraitObject(bounds))
+        Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None))
     }
 
     fn maybe_recover_from_bad_type_plus(&mut self, allow_plus: bool, ty: &Ty) -> PResult<'a, ()> {
@@ -2314,6 +2327,7 @@ impl<'a> Parser<'a> {
 
         while self.token != token::CloseDelim(token::Brace) {
             if self.eat(&token::DotDot) {
+                let exp_span = self.prev_span;
                 match self.parse_expr() {
                     Ok(e) => {
                         base = Some(e);
@@ -2323,6 +2337,16 @@ impl<'a> Parser<'a> {
                         self.recover_stmt();
                     }
                 }
+                if self.token == token::Comma {
+                    let mut err = self.sess.span_diagnostic.mut_span_err(
+                        exp_span.to(self.prev_span),
+                        "cannot use a comma after the base struct",
+                    );
+                    err.span_suggestion_short(self.span, "remove this comma", "".to_owned());
+                    err.note("the base struct must always be the last field");
+                    err.emit();
+                    self.recover_stmt();
+                }
                 break;
             }
 
@@ -2890,17 +2914,30 @@ impl<'a> Parser<'a> {
 
                 match self.parse_path(PathStyle::Expr) {
                     Ok(path) => {
+                        let (op_noun, op_verb) = match self.token {
+                            token::Lt => ("comparison", "comparing"),
+                            token::BinOp(token::Shl) => ("shift", "shifting"),
+                            _ => {
+                                // We can end up here even without `<` being the next token, for
+                                // example because `parse_ty_no_plus` returns `Err` on keywords,
+                                // but `parse_path` returns `Ok` on them due to error recovery.
+                                // Return original error and parser state.
+                                mem::replace(self, parser_snapshot_after_type);
+                                return Err(type_err);
+                            }
+                        };
+
                         // Successfully parsed the type path leaving a `<` yet to parse.
                         type_err.cancel();
 
                         // Report non-fatal diagnostics, keep `x as usize` as an expression
                         // in AST and continue parsing.
                         let msg = format!("`<` is interpreted as a start of generic \
-                                           arguments for `{}`, not a comparison", path);
+                                           arguments for `{}`, not a {}", path, op_noun);
                         let mut err = self.sess.span_diagnostic.struct_span_err(self.span, &msg);
                         err.span_label(self.look_ahead_span(1).to(parser_snapshot_after_type.span),
                                        "interpreted as generic arguments");
-                        err.span_label(self.span, "not interpreted as comparison");
+                        err.span_label(self.span, format!("not interpreted as {}", op_noun));
 
                         let expr = mk_expr(self, P(Ty {
                             span: path.span,
@@ -2911,7 +2948,7 @@ impl<'a> Parser<'a> {
                         let expr_str = self.sess.codemap().span_to_snippet(expr.span)
                                                 .unwrap_or(pprust::expr_to_string(&expr));
                         err.span_suggestion(expr.span,
-                                            "try comparing the casted value",
+                                            &format!("try {} the casted value", op_verb),
                                             format!("({})", expr_str));
                         err.emit();
 
@@ -2947,6 +2984,7 @@ impl<'a> Parser<'a> {
                 {                                  //     Foo<Bar<Baz<Qux, ()>>>
                     err.help(
                         "use `::<...>` instead of `<...>` if you meant to specify type arguments");
+                    err.help("or use `(...)` if you meant to specify fn arguments");
                 }
                 err.emit();
             }
@@ -4231,6 +4269,7 @@ impl<'a> Parser<'a> {
     fn parse_ty_param_bounds_common(&mut self, allow_plus: bool) -> PResult<'a, TyParamBounds> {
         let mut bounds = Vec::new();
         loop {
+            // This needs to be syncronized with `Token::can_begin_bound`.
             let is_bound_start = self.check_path() || self.check_lifetime() ||
                                  self.check(&token::Question) ||
                                  self.check_keyword(keywords::For) ||
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index 4888654fac9..20db87cfc82 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -258,6 +258,12 @@ impl Token {
         }
     }
 
+    /// Returns `true` if the token can appear at the start of a generic bound.
+    pub fn can_begin_bound(&self) -> bool {
+        self.is_path_start() || self.is_lifetime() || self.is_keyword(keywords::For) ||
+        self == &Question || self == &OpenDelim(Paren)
+    }
+
     /// Returns `true` if the token is any literal
     pub fn is_lit(&self) -> bool {
         match *self {