Skip to content

Commit d4a2826

Browse files
committed
add trait aliases to AST
1 parent 8624ea5 commit d4a2826

File tree

8 files changed

+134
-14
lines changed

8 files changed

+134
-14
lines changed

src/librustc_passes/ast_validation.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,20 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
283283
}
284284
}
285285
}
286+
ItemKind::TraitAlias(Generics { ref ty_params, .. }, ..) => {
287+
for &TyParam { ref bounds, ref default, span, .. } in ty_params {
288+
if !bounds.is_empty() {
289+
self.err_handler().span_err(span,
290+
"type parameters on the left side of a \
291+
trait alias cannot be bounded");
292+
}
293+
if !default.is_none() {
294+
self.err_handler().span_err(span,
295+
"type parameters on the left side of a \
296+
trait alias cannot have defaults");
297+
}
298+
}
299+
}
286300
ItemKind::Mod(_) => {
287301
// Ensure that `path` attributes on modules are recorded as used (c.f. #35584).
288302
attr::first_attr_value_str_by_name(&item.attrs, "path");

src/libsyntax/ast.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1929,6 +1929,10 @@ pub enum ItemKind {
19291929
///
19301930
/// E.g. `trait Foo { .. }`, `trait Foo<T> { .. }` or `auto trait Foo {}`
19311931
Trait(IsAuto, Unsafety, Generics, TyParamBounds, Vec<TraitItem>),
1932+
/// Trait alias
1933+
///
1934+
/// E.g. `trait Foo = Bar + Quux;`
1935+
TraitAlias(Generics, TyParamBounds),
19321936
/// Auto trait implementation.
19331937
///
19341938
/// E.g. `impl Trait for .. {}` or `impl<T> Trait<T> for .. {}`
@@ -1968,6 +1972,7 @@ impl ItemKind {
19681972
ItemKind::Struct(..) => "struct",
19691973
ItemKind::Union(..) => "union",
19701974
ItemKind::Trait(..) => "trait",
1975+
ItemKind::TraitAlias(..) => "trait alias",
19711976
ItemKind::Mac(..) |
19721977
ItemKind::MacroDef(..) |
19731978
ItemKind::Impl(..) |

src/libsyntax/fold.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -921,6 +921,9 @@ pub fn noop_fold_item_kind<T: Folder>(i: ItemKind, folder: &mut T) -> ItemKind {
921921
folder.fold_bounds(bounds),
922922
items.move_flat_map(|item| folder.fold_trait_item(item)),
923923
),
924+
ItemKind::TraitAlias(generics, bounds) => ItemKind::TraitAlias(
925+
folder.fold_generics(generics),
926+
folder.fold_bounds(bounds)),
924927
ItemKind::Mac(m) => ItemKind::Mac(folder.fold_mac(m)),
925928
ItemKind::MacroDef(def) => ItemKind::MacroDef(folder.fold_macro_def(def)),
926929
}

src/libsyntax/parse/parser.rs

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5182,7 +5182,7 @@ impl<'a> Parser<'a> {
51825182
}
51835183
}
51845184

5185-
/// Parse trait Foo { ... }
5185+
/// Parse `trait Foo { ... }` or `trait Foo = Bar;`
51865186
fn parse_item_trait(&mut self, is_auto: IsAuto, unsafety: Unsafety) -> PResult<'a, ItemInfo> {
51875187
let ident = self.parse_ident()?;
51885188
let mut tps = self.parse_generics()?;
@@ -5194,23 +5194,34 @@ impl<'a> Parser<'a> {
51945194
Vec::new()
51955195
};
51965196

5197-
tps.where_clause = self.parse_where_clause()?;
5198-
5199-
self.expect(&token::OpenDelim(token::Brace))?;
5200-
let mut trait_items = vec![];
5201-
while !self.eat(&token::CloseDelim(token::Brace)) {
5202-
let mut at_end = false;
5203-
match self.parse_trait_item(&mut at_end) {
5204-
Ok(item) => trait_items.push(item),
5205-
Err(mut e) => {
5206-
e.emit();
5207-
if !at_end {
5208-
self.recover_stmt_(SemiColonMode::Break, BlockMode::Break);
5197+
if self.eat(&token::Eq) {
5198+
// it's a trait alias
5199+
let bounds = self.parse_ty_param_bounds()?;
5200+
tps.where_clause = self.parse_where_clause()?;
5201+
self.expect(&token::Semi)?;
5202+
if unsafety != Unsafety::Normal {
5203+
self.span_err(self.prev_span, "trait aliases cannot be unsafe");
5204+
}
5205+
Ok((ident, ItemKind::TraitAlias(tps, bounds), None))
5206+
} else {
5207+
// it's a normal trait
5208+
tps.where_clause = self.parse_where_clause()?;
5209+
self.expect(&token::OpenDelim(token::Brace))?;
5210+
let mut trait_items = vec![];
5211+
while !self.eat(&token::CloseDelim(token::Brace)) {
5212+
let mut at_end = false;
5213+
match self.parse_trait_item(&mut at_end) {
5214+
Ok(item) => trait_items.push(item),
5215+
Err(mut e) => {
5216+
e.emit();
5217+
if !at_end {
5218+
self.recover_stmt_(SemiColonMode::Break, BlockMode::Break);
5219+
}
52095220
}
52105221
}
52115222
}
5223+
Ok((ident, ItemKind::Trait(is_auto, unsafety, tps, bounds, trait_items), None))
52125224
}
5213-
Ok((ident, ItemKind::Trait(is_auto, unsafety, tps, bounds, trait_items), None))
52145225
}
52155226

52165227
/// Parses items implementations variants

src/libsyntax/print/pprust.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1381,6 +1381,27 @@ impl<'a> State<'a> {
13811381
}
13821382
self.bclose(item.span)?;
13831383
}
1384+
ast::ItemKind::TraitAlias(ref generics, ref bounds) => {
1385+
self.head("")?;
1386+
self.print_visibility(&item.vis)?;
1387+
self.word_nbsp("trait")?;
1388+
self.print_ident(item.ident)?;
1389+
self.print_generics(generics)?;
1390+
let mut real_bounds = Vec::with_capacity(bounds.len());
1391+
// FIXME(durka) this seems to be some quite outdated syntax
1392+
for b in bounds.iter() {
1393+
if let TraitTyParamBound(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
1394+
self.s.space()?;
1395+
self.word_space("for ?")?;
1396+
self.print_trait_ref(&ptr.trait_ref)?;
1397+
} else {
1398+
real_bounds.push(b.clone());
1399+
}
1400+
}
1401+
self.print_bounds(" = ", &real_bounds[..])?;
1402+
self.print_where_clause(&generics.where_clause)?;
1403+
self.s.word(";")?;
1404+
}
13841405
ast::ItemKind::Mac(codemap::Spanned { ref node, .. }) => {
13851406
self.print_path(&node.path, false, 0, false)?;
13861407
self.s.word("! ")?;

src/libsyntax/visit.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,10 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
291291
walk_list!(visitor, visit_ty_param_bound, bounds);
292292
walk_list!(visitor, visit_trait_item, methods);
293293
}
294+
ItemKind::TraitAlias(ref generics, ref bounds) => {
295+
visitor.visit_generics(generics);
296+
walk_list!(visitor, visit_ty_param_bound, bounds);
297+
}
294298
ItemKind::Mac(ref mac) => visitor.visit_mac(mac),
295299
ItemKind::MacroDef(ref ts) => visitor.visit_mac_def(ts, item.id),
296300
}

src/test/compile-fail/trait-alias.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
trait Alias1<T> = Default where T: Clone; // ok
12+
trait Alias2<T: Clone = ()> = Default;
13+
//~^ERROR type parameters on the left side of a trait alias cannot be bounded
14+
//~^^ERROR type parameters on the left side of a trait alias cannot have defaults
15+
16+
impl Alias1 { //~ERROR expected type, found trait alias
17+
fn foo() {}
18+
}
19+
20+
fn main() {}
21+

src/test/run-pass/trait-alias.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
trait SimpleAlias = Default;
12+
trait GenericAlias<T> = Iterator<Item=T>;
13+
trait Partial<T> = IntoIterator<Item=T>;
14+
15+
trait Things<T> {}
16+
trait Romeo {}
17+
struct The<T>(T);
18+
struct Fore<T>(T);
19+
impl<T, U> Things<T> for The<U> {}
20+
impl<T> Romeo for Fore<T> {}
21+
22+
trait WithWhere<Art, Thou> = Romeo + Romeo where Fore<(Art, Thou)>: Romeo;
23+
trait BareWhere<Wild, Are> = where The<Wild>: Things<Are>;
24+
25+
trait CD = Clone + Default;
26+
27+
fn foo<T: CD>() -> (T, T) {
28+
let one = T::default();
29+
let two = one.clone();
30+
(one, two)
31+
}
32+
33+
fn main() {
34+
let both = foo();
35+
assert_eq!(both.0, 0);
36+
assert_eq!(both.1, 0);
37+
let both: (i32, i32) = foo();
38+
assert_eq!(both.0, 0);
39+
assert_eq!(both.1, 0);
40+
}
41+

0 commit comments

Comments
 (0)