add trait aliases to AST
This commit is contained in:
parent
8624ea5117
commit
d4a28268cc
8 changed files with 134 additions and 14 deletions
|
@ -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");
|
||||
|
|
|
@ -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(..) |
|
||||
|
|
|
@ -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)),
|
||||
}
|
||||
|
|
|
@ -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,8 +5194,18 @@ impl<'a> Parser<'a> {
|
|||
Vec::new()
|
||||
};
|
||||
|
||||
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)) {
|
||||
|
@ -5212,6 +5222,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
Ok((ident, ItemKind::Trait(is_auto, unsafety, tps, bounds, trait_items), None))
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses items implementations variants
|
||||
/// impl<T> Foo { ... }
|
||||
|
|
|
@ -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("! ")?;
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
|
|
21
src/test/compile-fail/trait-alias.rs
Normal file
21
src/test/compile-fail/trait-alias.rs
Normal file
|
@ -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() {}
|
||||
|
41
src/test/run-pass/trait-alias.rs
Normal file
41
src/test/run-pass/trait-alias.rs
Normal file
|
@ -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);
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue