diff options
| author | bors <bors@rust-lang.org> | 2017-10-14 16:11:05 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2017-10-14 16:11:05 +0000 |
| commit | 7920a7cc74bb2a2a80d90e32386e6194bb9a05dc (patch) | |
| tree | d6b97fe87bb256a420f600877f7fb8dad1561599 /src/libsyntax | |
| parent | 9c5e9a500da3210735160ee24736d2cae09eb4fb (diff) | |
| parent | 9d373204a5e67c91953f0080d4f93ebdcdcfc402 (diff) | |
| download | rust-7920a7cc74bb2a2a80d90e32386e6194bb9a05dc.tar.gz rust-7920a7cc74bb2a2a80d90e32386e6194bb9a05dc.zip | |
Auto merge of #45175 - petrochenkov:dyn, r=nikomatsakis
Implement `dyn Trait` syntax (RFC 2113) cc https://github.com/rust-lang/rust/issues/44662 r? @nikomatsakis
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/ast.rs | 9 | ||||
| -rw-r--r-- | src/libsyntax/feature_gate.rs | 7 | ||||
| -rw-r--r-- | src/libsyntax/fold.rs | 4 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 66 | ||||
| -rw-r--r-- | src/libsyntax/parse/token.rs | 6 | ||||
| -rw-r--r-- | src/libsyntax/print/pprust.rs | 5 | ||||
| -rw-r--r-- | src/libsyntax/visit.rs | 2 |
7 files changed, 67 insertions, 32 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 021f96aff8c..f445def9e03 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1419,7 +1419,7 @@ pub enum TyKind { Path(Option<QSelf>, Path), /// A trait object type `Bound1 + Bound2 + Bound3` /// where `Bound` is a trait or a lifetime. - TraitObject(TyParamBounds), + TraitObject(TyParamBounds, TraitObjectSyntax), /// An `impl Bound1 + Bound2 + Bound3` type /// where `Bound` is a trait or a lifetime. ImplTrait(TyParamBounds), @@ -1438,6 +1438,13 @@ pub enum TyKind { Err, } +/// Syntax used to declare a trait object. +#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum TraitObjectSyntax { + Dyn, + None, +} + /// Inline assembly dialect. /// /// E.g. `"intel"` as in `asm!("mov eax, 2" : "={eax}"(result) : : : "intel")`` diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index a2f29181a20..9060a613bc1 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -398,6 +398,9 @@ declare_features! ( // Default match binding modes (RFC 2005) (active, match_default_bindings, "1.22.0", Some(42640)), + + // Trait object syntax with `dyn` prefix + (active, dyn_trait, "1.22.0", Some(44662)), ); declare_features! ( @@ -1417,6 +1420,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, never_type, ty.span, "The `!` type is experimental"); }, + ast::TyKind::TraitObject(_, ast::TraitObjectSyntax::Dyn) => { + gate_feature_post!(&self, dyn_trait, ty.span, + "`dyn Trait` syntax is unstable"); + } _ => {} } visit::walk_ty(self, ty) diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 03c47b71d02..d7d491db71f 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -400,8 +400,8 @@ pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> { TyKind::Typeof(expr) => { TyKind::Typeof(fld.fold_expr(expr)) } - TyKind::TraitObject(bounds) => { - TyKind::TraitObject(bounds.move_map(|b| fld.fold_ty_param_bound(b))) + TyKind::TraitObject(bounds, syntax) => { + TyKind::TraitObject(bounds.move_map(|b| fld.fold_ty_param_bound(b)), syntax) } TyKind::ImplTrait(bounds) => { TyKind::ImplTrait(bounds.move_map(|b| fld.fold_ty_param_bound(b))) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 04e6cdcfe58..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, ()> { @@ -4256,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 { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 959dd4ef30f..02f871c58c7 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1049,8 +1049,9 @@ impl<'a> State<'a> { ast::TyKind::Path(Some(ref qself), ref path) => { self.print_qpath(path, qself, false)? } - ast::TyKind::TraitObject(ref bounds) => { - self.print_bounds("", &bounds[..])?; + ast::TyKind::TraitObject(ref bounds, syntax) => { + let prefix = if syntax == ast::TraitObjectSyntax::Dyn { "dyn " } else { "" }; + self.print_bounds(prefix, &bounds[..])?; } ast::TyKind::ImplTrait(ref bounds) => { self.print_bounds("impl ", &bounds[..])?; diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 05077d42a0b..521c6030eba 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -348,7 +348,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) { visitor.visit_ty(ty); visitor.visit_expr(expression) } - TyKind::TraitObject(ref bounds) | + TyKind::TraitObject(ref bounds, ..) | TyKind::ImplTrait(ref bounds) => { walk_list!(visitor, visit_ty_param_bound, bounds); } |
