]> git.lizzy.rs Git - rust.git/commitdiff
add trait aliases to AST
authorAlex Burka <alex@alexburka.com>
Mon, 2 Oct 2017 12:27:45 +0000 (12:27 +0000)
committerAlex Burka <aburka@seas.upenn.edu>
Thu, 14 Dec 2017 17:56:26 +0000 (12:56 -0500)
src/librustc_passes/ast_validation.rs
src/libsyntax/ast.rs
src/libsyntax/fold.rs
src/libsyntax/parse/parser.rs
src/libsyntax/print/pprust.rs
src/libsyntax/visit.rs
src/test/compile-fail/trait-alias.rs [new file with mode: 0644]
src/test/run-pass/trait-alias.rs [new file with mode: 0644]

index 05ad1643619058e363c73418755f8873c5472529..96c9323e7dc733a60127f190a95489b7d4a35518 100644 (file)
@@ -283,6 +283,20 @@ fn visit_item(&mut self, item: &'a Item) {
                     }
                 }
             }
+            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");
index 3c1d6ea18f7c2d38be251cd5cb10a0baeb126883..0d289dbd46b5b596efffd533c0562cfce228a796 100644 (file)
@@ -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 @@ pub fn descriptive_variant(&self) -> &str {
             ItemKind::Struct(..) => "struct",
             ItemKind::Union(..) => "union",
             ItemKind::Trait(..) => "trait",
+            ItemKind::TraitAlias(..) => "trait alias",
             ItemKind::Mac(..) |
             ItemKind::MacroDef(..) |
             ItemKind::Impl(..) |
index 1a92f057e5e874fdf751442a014e3976ec2559c3..6f973e2bcfaef918da6388e0f6bfc592887e57b3 100644 (file)
@@ -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)),
     }
index b3ef70fd18eb901e47f0a6374c923888ef042259..ec77d85f030eb9c02177e823c3335762b3ef6b2e 100644 (file)
@@ -5182,7 +5182,7 @@ fn parse_impl_method(&mut self, vis: &Visibility, at_end: &mut bool)
         }
     }
 
-    /// 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 @@ fn parse_item_trait(&mut self, is_auto: IsAuto, unsafety: Unsafety) -> PResult<'
             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
index e4b7dc26d326149aaacd28fc7e93357a86091a9a..e9386e5187ff0a20c942a35306dc5cf4991601fb 100644 (file)
@@ -1381,6 +1381,27 @@ pub fn print_item(&mut self, item: &ast::Item) -> io::Result<()> {
                 }
                 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("! ")?;
index 9a06ed0ba0297417719fea64e93d784ecac30d46..9266cc280974df503c0353d1730e6cd65a124ca4 100644 (file)
@@ -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 (file)
index 0000000..de87fe3
--- /dev/null
@@ -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 (file)
index 0000000..5297653
--- /dev/null
@@ -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);
+}
+