summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-12-14 20:57:09 +0000
committerbors <bors@rust-lang.org>2017-12-14 20:57:09 +0000
commit0077d128d33543290140763ce7d84d05eb57c40a (patch)
tree1d7cc06236dd24ffa7590d9c131c43dabb7b9f57 /src/libsyntax
parent3fc7f8522bbe59189b6423295a65f337b9735a88 (diff)
parent834674fa1d97f0e83baf99e1da5e24b82d41f63c (diff)
downloadrust-0077d128d33543290140763ce7d84d05eb57c40a.tar.gz
rust-0077d128d33543290140763ce7d84d05eb57c40a.zip
Auto merge of #45047 - durka:trait-alias, r=petrochenkov
trait alias infrastructure

This will be an implementation of trait aliases (RFC 1733, #41517).

Progress so far:

- [x] Feature gate
- [x] Add to parser
  - [x] `where` clauses
    - [x] prohibit LHS type parameter bounds via AST validation https://github.com/rust-lang/rust/pull/45047#discussion_r143575575
- [x] Add to AST and HIR
  - [x] make a separate PathSource for trait alias contexts https://github.com/rust-lang/rust/pull/45047#discussion_r143353932
- [x] Stub out enough of typeck and resolve to just barely not ICE

Postponed:

- [ ] Actually implement the alias part
- [ ] #21903
- [ ] #24010

I need some pointers on where to start with that last one. The test currently does this:

```
error[E0283]: type annotations required: cannot resolve `_: CD`
  --> src/test/run-pass/trait-alias.rs:34:16
   |
34 |     let both = foo();
   |                ^^^
   |
   = note: required by `foo`
```
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ast.rs5
-rw-r--r--src/libsyntax/feature_gate.rs8
-rw-r--r--src/libsyntax/fold.rs3
-rw-r--r--src/libsyntax/parse/parser.rs39
-rw-r--r--src/libsyntax/print/pprust.rs21
-rw-r--r--src/libsyntax/visit.rs4
6 files changed, 66 insertions, 14 deletions
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/feature_gate.rs b/src/libsyntax/feature_gate.rs
index c7bfb121f80..ba534676324 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -368,6 +368,8 @@ declare_features! (
     // Generators
     (active, generators, "1.21.0", None),
 
+    // Trait aliases
+    (active, trait_alias, "1.24.0", Some(41517)),
 
     // global allocators and their internals
     (active, global_allocator, "1.20.0", None),
@@ -1406,6 +1408,12 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                 }
             }
 
+            ast::ItemKind::TraitAlias(..) => {
+                gate_feature_post!(&self, trait_alias,
+                                   i.span,
+                                   "trait aliases are not yet fully implemented");
+            }
+
             ast::ItemKind::AutoImpl(..) => {
                 gate_feature_post!(&self, optin_builtin_traits,
                                    i.span,
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),
     }