diff options
| author | Alex Burka <alex@alexburka.com> | 2017-10-02 12:27:45 +0000 |
|---|---|---|
| committer | Alex Burka <aburka@seas.upenn.edu> | 2017-12-14 12:56:26 -0500 |
| commit | d4a28268cc1c8314f0de2519c78ff97696486a36 (patch) | |
| tree | 30a4094b487f9f0772a103adb182602fd9aef7dd | |
| parent | 8624ea51172c8a86d5c7c47d740be65a3a9efbc6 (diff) | |
| download | rust-d4a28268cc1c8314f0de2519c78ff97696486a36.tar.gz rust-d4a28268cc1c8314f0de2519c78ff97696486a36.zip | |
add trait aliases to AST
| -rw-r--r-- | src/librustc_passes/ast_validation.rs | 14 | ||||
| -rw-r--r-- | src/libsyntax/ast.rs | 5 | ||||
| -rw-r--r-- | src/libsyntax/fold.rs | 3 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 39 | ||||
| -rw-r--r-- | src/libsyntax/print/pprust.rs | 21 | ||||
| -rw-r--r-- | src/libsyntax/visit.rs | 4 | ||||
| -rw-r--r-- | src/test/compile-fail/trait-alias.rs | 21 | ||||
| -rw-r--r-- | src/test/run-pass/trait-alias.rs | 41 |
8 files changed, 134 insertions, 14 deletions
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 05ad1643619..96c9323e7dc 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -283,6 +283,20 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } } } + ItemKind::TraitAlias(Generics { ref ty_params, .. }, ..) => { + for &TyParam { ref bounds, ref default, span, .. } in ty_params { + if !bounds.is_empty() { + self.err_handler().span_err(span, + "type parameters on the left side of a \ + trait alias cannot be bounded"); + } + if !default.is_none() { + self.err_handler().span_err(span, + "type parameters on the left side of a \ + trait alias cannot have defaults"); + } + } + } ItemKind::Mod(_) => { // Ensure that `path` attributes on modules are recorded as used (c.f. #35584). attr::first_attr_value_str_by_name(&item.attrs, "path"); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 3c1d6ea18f7..0d289dbd46b 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1929,6 +1929,10 @@ pub enum ItemKind { /// /// E.g. `trait Foo { .. }`, `trait Foo<T> { .. }` or `auto trait Foo {}` Trait(IsAuto, Unsafety, Generics, TyParamBounds, Vec<TraitItem>), + /// Trait alias + /// + /// E.g. `trait Foo = Bar + Quux;` + TraitAlias(Generics, TyParamBounds), /// Auto trait implementation. /// /// E.g. `impl Trait for .. {}` or `impl<T> Trait<T> for .. {}` @@ -1968,6 +1972,7 @@ impl ItemKind { ItemKind::Struct(..) => "struct", ItemKind::Union(..) => "union", ItemKind::Trait(..) => "trait", + ItemKind::TraitAlias(..) => "trait alias", ItemKind::Mac(..) | ItemKind::MacroDef(..) | ItemKind::Impl(..) | diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 1a92f057e5e..6f973e2bcfa 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -921,6 +921,9 @@ pub fn noop_fold_item_kind<T: Folder>(i: ItemKind, folder: &mut T) -> ItemKind { folder.fold_bounds(bounds), items.move_flat_map(|item| folder.fold_trait_item(item)), ), + ItemKind::TraitAlias(generics, bounds) => ItemKind::TraitAlias( + folder.fold_generics(generics), + folder.fold_bounds(bounds)), ItemKind::Mac(m) => ItemKind::Mac(folder.fold_mac(m)), ItemKind::MacroDef(def) => ItemKind::MacroDef(folder.fold_macro_def(def)), } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index b3ef70fd18e..ec77d85f030 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5182,7 +5182,7 @@ impl<'a> Parser<'a> { } } - /// Parse trait Foo { ... } + /// Parse `trait Foo { ... }` or `trait Foo = Bar;` fn parse_item_trait(&mut self, is_auto: IsAuto, unsafety: Unsafety) -> PResult<'a, ItemInfo> { let ident = self.parse_ident()?; let mut tps = self.parse_generics()?; @@ -5194,23 +5194,34 @@ impl<'a> Parser<'a> { Vec::new() }; - tps.where_clause = self.parse_where_clause()?; - - self.expect(&token::OpenDelim(token::Brace))?; - let mut trait_items = vec![]; - while !self.eat(&token::CloseDelim(token::Brace)) { - let mut at_end = false; - match self.parse_trait_item(&mut at_end) { - Ok(item) => trait_items.push(item), - Err(mut e) => { - e.emit(); - if !at_end { - self.recover_stmt_(SemiColonMode::Break, BlockMode::Break); + if self.eat(&token::Eq) { + // it's a trait alias + let bounds = self.parse_ty_param_bounds()?; + tps.where_clause = self.parse_where_clause()?; + self.expect(&token::Semi)?; + if unsafety != Unsafety::Normal { + self.span_err(self.prev_span, "trait aliases cannot be unsafe"); + } + Ok((ident, ItemKind::TraitAlias(tps, bounds), None)) + } else { + // it's a normal trait + tps.where_clause = self.parse_where_clause()?; + self.expect(&token::OpenDelim(token::Brace))?; + let mut trait_items = vec![]; + while !self.eat(&token::CloseDelim(token::Brace)) { + let mut at_end = false; + match self.parse_trait_item(&mut at_end) { + Ok(item) => trait_items.push(item), + Err(mut e) => { + e.emit(); + if !at_end { + self.recover_stmt_(SemiColonMode::Break, BlockMode::Break); + } } } } + Ok((ident, ItemKind::Trait(is_auto, unsafety, tps, bounds, trait_items), None)) } - Ok((ident, ItemKind::Trait(is_auto, unsafety, tps, bounds, trait_items), None)) } /// Parses items implementations variants diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index e4b7dc26d32..e9386e5187f 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1381,6 +1381,27 @@ impl<'a> State<'a> { } self.bclose(item.span)?; } + ast::ItemKind::TraitAlias(ref generics, ref bounds) => { + self.head("")?; + self.print_visibility(&item.vis)?; + self.word_nbsp("trait")?; + self.print_ident(item.ident)?; + self.print_generics(generics)?; + let mut real_bounds = Vec::with_capacity(bounds.len()); + // FIXME(durka) this seems to be some quite outdated syntax + for b in bounds.iter() { + if let TraitTyParamBound(ref ptr, ast::TraitBoundModifier::Maybe) = *b { + self.s.space()?; + self.word_space("for ?")?; + self.print_trait_ref(&ptr.trait_ref)?; + } else { + real_bounds.push(b.clone()); + } + } + self.print_bounds(" = ", &real_bounds[..])?; + self.print_where_clause(&generics.where_clause)?; + self.s.word(";")?; + } ast::ItemKind::Mac(codemap::Spanned { ref node, .. }) => { self.print_path(&node.path, false, 0, false)?; self.s.word("! ")?; diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 9a06ed0ba02..9266cc28097 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -291,6 +291,10 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { walk_list!(visitor, visit_ty_param_bound, bounds); walk_list!(visitor, visit_trait_item, methods); } + ItemKind::TraitAlias(ref generics, ref bounds) => { + visitor.visit_generics(generics); + walk_list!(visitor, visit_ty_param_bound, bounds); + } ItemKind::Mac(ref mac) => visitor.visit_mac(mac), ItemKind::MacroDef(ref ts) => visitor.visit_mac_def(ts, item.id), } diff --git a/src/test/compile-fail/trait-alias.rs b/src/test/compile-fail/trait-alias.rs new file mode 100644 index 00000000000..de87fe39395 --- /dev/null +++ b/src/test/compile-fail/trait-alias.rs @@ -0,0 +1,21 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Alias1<T> = Default where T: Clone; // ok +trait Alias2<T: Clone = ()> = Default; + //~^ERROR type parameters on the left side of a trait alias cannot be bounded + //~^^ERROR type parameters on the left side of a trait alias cannot have defaults + +impl Alias1 { //~ERROR expected type, found trait alias + fn foo() {} +} + +fn main() {} + diff --git a/src/test/run-pass/trait-alias.rs b/src/test/run-pass/trait-alias.rs new file mode 100644 index 00000000000..529765320a2 --- /dev/null +++ b/src/test/run-pass/trait-alias.rs @@ -0,0 +1,41 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait SimpleAlias = Default; +trait GenericAlias<T> = Iterator<Item=T>; +trait Partial<T> = IntoIterator<Item=T>; + +trait Things<T> {} +trait Romeo {} +struct The<T>(T); +struct Fore<T>(T); +impl<T, U> Things<T> for The<U> {} +impl<T> Romeo for Fore<T> {} + +trait WithWhere<Art, Thou> = Romeo + Romeo where Fore<(Art, Thou)>: Romeo; +trait BareWhere<Wild, Are> = where The<Wild>: Things<Are>; + +trait CD = Clone + Default; + +fn foo<T: CD>() -> (T, T) { + let one = T::default(); + let two = one.clone(); + (one, two) +} + +fn main() { + let both = foo(); + assert_eq!(both.0, 0); + assert_eq!(both.1, 0); + let both: (i32, i32) = foo(); + assert_eq!(both.0, 0); + assert_eq!(both.1, 0); +} + |
