add auto keyword, parse auto trait, lower to HIR

Adds an `IsAuto` field to `ItemTrait` which flags if the trait was
declared as an `auto trait`.

Auto traits cannot have generics nor super traits.
This commit is contained in:
leonardo.yvens 2017-10-12 09:51:31 -03:00
parent 06506bb751
commit 1f4b630899
17 changed files with 122 additions and 31 deletions

View File

@ -520,7 +520,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
visitor.visit_id(item.id);
visitor.visit_variant_data(struct_definition, item.name, generics, item.id, item.span);
}
ItemTrait(_, ref generics, ref bounds, ref trait_item_refs) => {
ItemTrait(.., ref generics, ref bounds, ref trait_item_refs) => {
visitor.visit_id(item.id);
visitor.visit_generics(generics);
walk_list!(visitor, visit_ty_param_bound, bounds);

View File

@ -198,7 +198,7 @@ impl<'a> LoweringContext<'a> {
ItemKind::Union(_, ref generics) |
ItemKind::Enum(_, ref generics) |
ItemKind::Ty(_, ref generics) |
ItemKind::Trait(_, ref generics, ..) => {
ItemKind::Trait(_, _, ref generics, ..) => {
let def_id = self.lctx.resolver.definitions().local_def_id(item.id);
let count = generics.lifetimes.len();
self.lctx.type_def_lifetime_params.insert(def_id, count);
@ -1515,10 +1515,11 @@ impl<'a> LoweringContext<'a> {
self.lower_ty(ty),
new_impl_items)
}
ItemKind::Trait(unsafety, ref generics, ref bounds, ref items) => {
ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref items) => {
let bounds = self.lower_bounds(bounds);
let items = items.iter().map(|item| self.lower_trait_item_ref(item)).collect();
hir::ItemTrait(self.lower_unsafety(unsafety),
hir::ItemTrait(self.lower_is_auto(is_auto),
self.lower_unsafety(unsafety),
self.lower_generics(generics),
bounds,
items)
@ -1741,6 +1742,13 @@ impl<'a> LoweringContext<'a> {
}
}
fn lower_is_auto(&mut self, u: IsAuto) -> hir::IsAuto {
match u {
IsAuto::Yes => hir::IsAuto::Yes,
IsAuto::No => hir::IsAuto::No,
}
}
fn lower_unsafety(&mut self, u: Unsafety) -> hir::Unsafety {
match u {
Unsafety::Unsafe => hir::Unsafety::Unsafe,

View File

@ -1500,6 +1500,13 @@ pub struct FnDecl {
pub has_implicit_self: bool,
}
/// Is the trait definition an auto trait?
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum IsAuto {
Yes,
No
}
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum Unsafety {
Unsafe,
@ -1811,7 +1818,7 @@ pub enum Item_ {
/// A union definition, e.g. `union Foo<A, B> {x: A, y: B}`
ItemUnion(VariantData, Generics),
/// Represents a Trait Declaration
ItemTrait(Unsafety, Generics, TyParamBounds, HirVec<TraitItemRef>),
ItemTrait(IsAuto, Unsafety, Generics, TyParamBounds, HirVec<TraitItemRef>),
/// Auto trait implementations
///

View File

@ -717,9 +717,10 @@ impl<'a> State<'a> {
}
self.bclose(item.span)?;
}
hir::ItemTrait(unsafety, ref generics, ref bounds, ref trait_items) => {
hir::ItemTrait(is_auto, unsafety, ref generics, ref bounds, ref trait_items) => {
self.head("")?;
self.print_visibility(&item.vis)?;
self.print_is_auto(is_auto)?;
self.print_unsafety(unsafety)?;
self.word_nbsp("trait")?;
self.print_name(item.name)?;
@ -2274,6 +2275,13 @@ impl<'a> State<'a> {
hir::Unsafety::Unsafe => self.word_nbsp("unsafe"),
}
}
pub fn print_is_auto(&mut self, s: hir::IsAuto) -> io::Result<()> {
match s {
hir::IsAuto::Yes => self.word_nbsp("auto"),
hir::IsAuto::No => Ok(()),
}
}
}
// Dup'ed from parse::classify, but adapted for the HIR.

View File

@ -944,7 +944,7 @@ impl_stable_hash_for!(enum hir::Item_ {
ItemEnum(enum_def, generics),
ItemStruct(variant_data, generics),
ItemUnion(variant_data, generics),
ItemTrait(unsafety, generics, bounds, item_refs),
ItemTrait(is_auto, unsafety, generics, bounds, item_refs),
ItemAutoImpl(unsafety, trait_ref),
ItemImpl(unsafety, impl_polarity, impl_defaultness, generics, trait_ref, ty, impl_item_refs)
});
@ -1126,6 +1126,10 @@ impl_stable_hash_for!(enum hir::Mutability {
MutImmutable
});
impl_stable_hash_for!(enum hir::IsAuto {
Yes,
No
});
impl_stable_hash_for!(enum hir::Unsafety {
Unsafe,

View File

@ -332,7 +332,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
hir::ItemEnum(_, ref generics) |
hir::ItemStruct(_, ref generics) |
hir::ItemUnion(_, ref generics) |
hir::ItemTrait(_, ref generics, ..) |
hir::ItemTrait(_, _, ref generics, ..) |
hir::ItemImpl(_, _, _, ref generics, ..) => {
// These kinds of items have only early bound lifetime parameters.
let mut index = if let hir::ItemTrait(..) = item.node {
@ -688,7 +688,7 @@ fn compute_object_lifetime_defaults(sess: &Session, hir_map: &Map)
hir::ItemUnion(_, ref generics) |
hir::ItemEnum(_, ref generics) |
hir::ItemTy(_, ref generics) |
hir::ItemTrait(_, ref generics, ..) => {
hir::ItemTrait(_, _, ref generics, ..) => {
let result = object_lifetime_defaults_for_item(hir_map, generics);
// Debugging aid.
@ -844,7 +844,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
index += 1; // Self comes first.
}
match parent.node {
hir::ItemTrait(_, ref generics, ..) |
hir::ItemTrait(_, _, ref generics, ..) |
hir::ItemImpl(_, _, _, ref generics, ..) => {
index += (generics.lifetimes.len() + generics.ty_params.len()) as u32;
}

View File

@ -228,7 +228,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnsafeCode {
fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
match it.node {
hir::ItemTrait(hir::Unsafety::Unsafe, ..) => {
hir::ItemTrait(_, hir::Unsafety::Unsafe, ..) => {
self.report_unsafe(cx, it.span, "declaration of an `unsafe` trait")
}

View File

@ -1854,7 +1854,7 @@ impl<'a> Resolver<'a> {
item.id,
impl_items),
ItemKind::Trait(_, ref generics, ref bounds, ref trait_items) => {
ItemKind::Trait(.., ref generics, ref bounds, ref trait_items) => {
// Create a new rib for the trait-wide type parameters.
self.with_type_parameter_rib(HasTypeParameters(generics, ItemRibKind), |this| {
let local_def_id = this.definitions.local_def_id(item.id);

View File

@ -1232,7 +1232,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
ref impl_items) => {
self.process_impl(item, ty_params, trait_ref, &typ, impl_items)
}
Trait(_, ref generics, ref trait_refs, ref methods) =>
Trait(_, _, ref generics, ref trait_refs, ref methods) =>
self.process_trait(item, generics, trait_refs, methods),
Mod(ref m) => {
self.process_mod(item);

View File

@ -477,8 +477,13 @@ impl Sig for ast::Item {
sig.text.push_str(" {}");
Ok(sig)
}
ast::ItemKind::Trait(unsafety, ref generics, ref bounds, _) => {
ast::ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, _) => {
let mut text = String::new();
if is_auto == ast::IsAuto::Yes {
text.push_str("auto ");
}
if unsafety == ast::Unsafety::Unsafe {
text.push_str("unsafe ");
}

View File

@ -273,7 +273,7 @@ fn type_param_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
ItemEnum(_, ref generics) |
ItemStruct(_, ref generics) |
ItemUnion(_, ref generics) => generics,
ItemTrait(_, ref generics, ..) => {
ItemTrait(_, _, ref generics, ..) => {
// Implied `Self: Trait` and supertrait bounds.
if param_id == item_node_id {
result.predicates.push(ty::TraitRef {
@ -670,7 +670,7 @@ fn super_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
};
let (generics, bounds) = match item.node {
hir::ItemTrait(_, ref generics, ref supertraits, _) => (generics, supertraits),
hir::ItemTrait(.., ref generics, ref supertraits, _) => (generics, supertraits),
_ => span_bug!(item.span,
"super_predicates invoked on non-trait"),
};
@ -713,7 +713,7 @@ fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let item = tcx.hir.expect_item(node_id);
let unsafety = match item.node {
hir::ItemTrait(unsafety, ..) => unsafety,
hir::ItemTrait(_, unsafety, ..) => unsafety,
_ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"),
};
@ -888,7 +888,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
generics
}
ItemTrait(_, ref generics, ..) => {
ItemTrait(_, _, ref generics, ..) => {
// Add in the self type parameter.
//
// Something of a hack: use the node id for the trait, also as
@ -1350,7 +1350,7 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
generics
}
ItemTrait(_, ref generics, .., ref items) => {
ItemTrait(_, _, ref generics, .., ref items) => {
is_trait = Some((ty::TraitRef {
def_id,
substs: Substs::identity_for_item(tcx, def_id)

View File

@ -1581,6 +1581,13 @@ impl FnDecl {
}
}
/// Is the trait definition an auto trait?
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum IsAuto {
Yes,
No
}
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum Unsafety {
Unsafe,
@ -1942,8 +1949,8 @@ pub enum ItemKind {
Union(VariantData, Generics),
/// A Trait declaration (`trait` or `pub trait`).
///
/// E.g. `trait Foo { .. }` or `trait Foo<T> { .. }`
Trait(Unsafety, Generics, TyParamBounds, Vec<TraitItem>),
/// E.g. `trait Foo { .. }`, `trait Foo<T> { .. }` or `auto trait Foo {}`
Trait(IsAuto, Unsafety, Generics, TyParamBounds, Vec<TraitItem>),
/// Auto trait implementation.
///
/// E.g. `impl Trait for .. {}` or `impl<T> Trait<T> for .. {}`

View File

@ -926,7 +926,8 @@ pub fn noop_fold_item_kind<T: Folder>(i: ItemKind, folder: &mut T) -> ItemKind {
folder.fold_ty(ty),
impl_items.move_flat_map(|item| folder.fold_impl_item(item)),
),
ItemKind::Trait(unsafety, generics, bounds, items) => ItemKind::Trait(
ItemKind::Trait(is_auto, unsafety, generics, bounds, items) => ItemKind::Trait(
is_auto,
unsafety,
folder.fold_generics(generics),
folder.fold_bounds(bounds),

View File

@ -16,12 +16,13 @@ use ast::{Mod, Arg, Arm, Attribute, BindingMode, TraitItemKind};
use ast::Block;
use ast::{BlockCheckMode, CaptureBy};
use ast::{Constness, Crate};
use ast::Generics;
use ast::Defaultness;
use ast::EnumDef;
use ast::{Expr, ExprKind, RangeLimits};
use ast::{Field, FnDecl};
use ast::{ForeignItem, ForeignItemKind, FunctionRetTy};
use ast::{Ident, ImplItem, Item, ItemKind};
use ast::{Ident, ImplItem, IsAuto, Item, ItemKind};
use ast::{Lifetime, LifetimeDef, Lit, LitKind, UintTy};
use ast::Local;
use ast::MacStmtStyle;
@ -5078,7 +5079,17 @@ impl<'a> Parser<'a> {
}
}
}
Ok((ident, ItemKind::Trait(unsafety, tps, bounds, trait_items), None))
Ok((ident, ItemKind::Trait(IsAuto::No, unsafety, tps, bounds, trait_items), None))
}
fn parse_item_auto_trait(&mut self, unsafety: Unsafety) -> PResult<'a, ItemInfo> {
let ident = self.parse_ident()?;
self.expect(&token::OpenDelim(token::Brace))?;
self.expect(&token::CloseDelim(token::Brace))?;
// Auto traits cannot have generics, super traits nor contain items.
Ok((ident,
ItemKind::Trait(IsAuto::Yes, unsafety, Generics::default(), Vec::new(), Vec::new()),
None))
}
/// Parses items implementations variants
@ -6127,6 +6138,37 @@ impl<'a> Parser<'a> {
maybe_append(attrs, extra_attrs));
return Ok(Some(item));
}
if self.eat_keyword(keywords::Auto) {
self.expect_keyword(keywords::Trait)?;
// AUTO TRAIT ITEM
let (ident,
item_,
extra_attrs) = self.parse_item_auto_trait(ast::Unsafety::Normal)?;
let prev_span = self.prev_span;
let item = self.mk_item(lo.to(prev_span),
ident,
item_,
visibility,
maybe_append(attrs, extra_attrs));
return Ok(Some(item));
}
if self.check_keyword(keywords::Unsafe) &&
self.look_ahead(1, |t| t.is_keyword(keywords::Auto)) {
self.expect_keyword(keywords::Unsafe)?;
self.expect_keyword(keywords::Auto)?;
self.expect_keyword(keywords::Trait)?;
// UNSAFE AUTO TRAIT ITEM
let (ident,
item_,
extra_attrs) = self.parse_item_auto_trait(ast::Unsafety::Unsafe)?;
let prev_span = self.prev_span;
let item = self.mk_item(lo.to(prev_span),
ident,
item_,
visibility,
maybe_append(attrs, extra_attrs));
return Ok(Some(item));
}
if self.eat_keyword(keywords::Struct) {
// STRUCT ITEM
let (ident, item_, extra_attrs) = self.parse_item_struct()?;

View File

@ -1338,9 +1338,10 @@ impl<'a> State<'a> {
}
self.bclose(item.span)?;
}
ast::ItemKind::Trait(unsafety, ref generics, ref bounds, ref trait_items) => {
ast::ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref trait_items) => {
self.head("")?;
self.print_visibility(&item.vis)?;
self.print_is_auto(is_auto)?;
self.print_unsafety(unsafety)?;
self.word_nbsp("trait")?;
self.print_ident(item.ident)?;
@ -3123,6 +3124,13 @@ impl<'a> State<'a> {
ast::Unsafety::Unsafe => self.word_nbsp("unsafe"),
}
}
pub fn print_is_auto(&mut self, s: ast::IsAuto) -> io::Result<()> {
match s {
ast::IsAuto::Yes => self.word_nbsp("auto"),
ast::IsAuto::No => Ok(()),
}
}
}
fn repeat(s: &str, n: usize) -> String { iter::repeat(s).take(n).collect() }

View File

@ -300,7 +300,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
visitor.visit_variant_data(struct_definition, item.ident,
generics, item.id, item.span);
}
ItemKind::Trait(_, ref generics, ref bounds, ref methods) => {
ItemKind::Trait(.., ref generics, ref bounds, ref methods) => {
visitor.visit_generics(generics);
walk_list!(visitor, visit_ty_param_bound, bounds);
walk_list!(visitor, visit_trait_item, methods);

View File

@ -309,11 +309,12 @@ declare_keywords! {
(54, Yield, "yield")
// Weak keywords, have special meaning only in specific contexts.
(55, Catch, "catch")
(56, Default, "default")
(57, Dyn, "dyn")
(58, StaticLifetime, "'static")
(59, Union, "union")
(55, Auto, "auto")
(56, Catch, "catch")
(57, Default, "default")
(58, Dyn, "dyn")
(59, StaticLifetime, "'static")
(60, Union, "union")
}
// If an interner exists in TLS, return it. Otherwise, prepare a fresh one.