Unify structures and enum variants in AST

This commit is contained in:
Vadim Petrochenkov 2015-10-01 18:47:27 +03:00
parent ec4362da56
commit ea47c2b6b3
13 changed files with 97 additions and 226 deletions

View File

@ -267,14 +267,13 @@ pub fn lower_variant(_lctx: &LoweringContext, v: &Variant) -> P<hir::Variant> {
id: v.node.id,
name: v.node.name.name,
attrs: v.node.attrs.clone(),
kind: match v.node.kind {
TupleVariantKind(ref variant_args) => {
hir::TupleVariantKind(variant_args.iter()
.map(|ref x| lower_variant_arg(_lctx, x))
.collect())
}
StructVariantKind(ref struct_def) => {
hir::StructVariantKind(lower_struct_def(_lctx, struct_def))
kind: {
if v.node.def.ctor_id.is_none() {
hir::StructVariantKind(lower_struct_def(_lctx, &v.node.def))
} else {
hir::TupleVariantKind(v.node.def.fields.iter().map(|ref field| {
hir::VariantArg { id: field.node.id, ty: lower_ty(_lctx, &field.node.ty) }
}).collect())
}
},
disr_expr: v.node.disr_expr.as_ref().map(|e| lower_expr(_lctx, e)),
@ -567,13 +566,6 @@ fn lower_bounds(_lctx: &LoweringContext, bounds: &TyParamBounds) -> hir::TyParam
bounds.iter().map(|bound| lower_ty_param_bound(_lctx, bound)).collect()
}
fn lower_variant_arg(_lctx: &LoweringContext, va: &VariantArg) -> hir::VariantArg {
hir::VariantArg {
id: va.id,
ty: lower_ty(_lctx, &va.ty),
}
}
pub fn lower_block(_lctx: &LoweringContext, b: &Block) -> P<hir::Block> {
P(hir::Block {
id: b.id,

View File

@ -504,40 +504,20 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
qualname.push_str("::");
qualname.push_str(name);
let val = self.span.snippet(variant.span);
match variant.node.kind {
ast::TupleVariantKind(ref args) => {
// first ident in span is the variant's name
self.fmt.tuple_variant_str(variant.span,
self.span.span_for_first_ident(variant.span),
variant.node.id,
name,
&qualname,
&enum_data.qualname,
&val,
enum_data.id);
for arg in args {
self.visit_ty(&*arg.ty);
}
}
ast::StructVariantKind(ref struct_def) => {
let ctor_id = match struct_def.ctor_id {
Some(node_id) => node_id,
None => ast::DUMMY_NODE_ID,
};
self.fmt.struct_variant_str(variant.span,
self.span.span_for_first_ident(variant.span),
variant.node.id,
ctor_id,
&qualname,
&enum_data.qualname,
&val,
enum_data.id);
for field in &struct_def.fields {
self.process_struct_field_def(field, variant.node.id);
self.visit_ty(&*field.node.ty);
}
}
let ctor_id = variant.node.def.ctor_id.unwrap_or(ast::DUMMY_NODE_ID);
self.fmt.struct_variant_str(variant.span,
self.span.span_for_first_ident(variant.span),
variant.node.id,
ctor_id,
&qualname,
&enum_data.qualname,
&val,
enum_data.id);
for field in &variant.node.def.fields {
self.process_struct_field_def(field, variant.node.id);
self.visit_ty(&*field.node.ty);
}
}
self.process_generic_params(ty_params, item.span, &enum_data.qualname, enum_data.id);

View File

@ -1594,7 +1594,7 @@ pub struct EnumDef {
pub struct Variant_ {
pub name: Ident,
pub attrs: Vec<Attribute>,
pub kind: VariantKind,
pub def: P<StructDef>,
pub id: NodeId,
/// Explicit discriminant, eg `Foo = 1`
pub disr_expr: Option<P<Expr>>,

View File

@ -140,19 +140,14 @@ fn fold_item_underscore<F>(cx: &mut Context<F>, item: ast::Item_) -> ast::Item_
if !(cx.in_cfg)(&v.node.attrs) {
None
} else {
Some(v.map(|Spanned {node: ast::Variant_ {id, name, attrs, kind,
Some(v.map(|Spanned {node: ast::Variant_ {id, name, attrs, def,
disr_expr}, span}| {
Spanned {
node: ast::Variant_ {
id: id,
name: name,
attrs: attrs,
kind: match kind {
ast::TupleVariantKind(..) => kind,
ast::StructVariantKind(def) => {
ast::StructVariantKind(fold_struct(cx, def))
}
},
def: fold_struct(cx, def),
disr_expr: disr_expr,
},
span: span

View File

@ -993,15 +993,20 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
}
fn variant(&self, span: Span, name: Ident, tys: Vec<P<ast::Ty>> ) -> ast::Variant {
let args = tys.into_iter().map(|ty| {
ast::VariantArg { ty: ty, id: ast::DUMMY_NODE_ID }
let fields = tys.into_iter().map(|ty| {
Spanned { span: ty.span, node: ast::StructField_ {
ty: ty,
kind: ast::UnnamedField(ast::Inherited),
attrs: Vec::new(),
id: ast::DUMMY_NODE_ID,
}}
}).collect();
respan(span,
ast::Variant_ {
name: name,
attrs: Vec::new(),
kind: ast::TupleVariantKind(args),
def: P(ast::StructDef { fields: fields, ctor_id: Some(ast::DUMMY_NODE_ID) }),
id: ast::DUMMY_NODE_ID,
disr_expr: None,
})

View File

@ -700,16 +700,8 @@ impl<'a> TraitDef<'a> {
let mut field_tys = Vec::new();
for variant in &enum_def.variants {
match variant.node.kind {
ast::VariantKind::TupleVariantKind(ref args) => {
field_tys.extend(args.iter()
.map(|arg| arg.ty.clone()));
}
ast::VariantKind::StructVariantKind(ref args) => {
field_tys.extend(args.fields.iter()
.map(|field| field.node.ty.clone()));
}
}
field_tys.extend(variant.node.def.fields.iter()
.map(|field| field.node.ty.clone()));
}
let methods = self.methods.iter().map(|method_def| {
@ -1413,14 +1405,7 @@ impl<'a> MethodDef<'a> {
-> P<Expr> {
let summary = enum_def.variants.iter().map(|v| {
let ident = v.node.name;
let summary = match v.node.kind {
ast::TupleVariantKind(ref args) => {
Unnamed(args.iter().map(|va| trait_.set_expn_info(cx, va.ty.span)).collect())
}
ast::StructVariantKind(ref struct_def) => {
trait_.summarise_struct(cx, &**struct_def)
}
};
let summary = trait_.summarise_struct(cx, &v.node.def);
(ident, v.span, summary)
}).collect();
self.call_substructure_method(cx, trait_, type_ident,
@ -1560,34 +1545,7 @@ impl<'a> TraitDef<'a> {
-> (P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>, &'a [ast::Attribute])>) {
let variant_ident = variant.node.name;
let variant_path = cx.path(variant.span, vec![enum_ident, variant_ident]);
match variant.node.kind {
ast::TupleVariantKind(ref variant_args) => {
if variant_args.is_empty() {
return (cx.pat_enum(variant.span, variant_path, vec![]), vec![]);
}
let mut paths = Vec::new();
let mut ident_expr: Vec<(_, _, _, &'a [ast::Attribute])> = Vec::new();
for (i, va) in variant_args.iter().enumerate() {
let sp = self.set_expn_info(cx, va.ty.span);
let ident = cx.ident_of(&format!("{}_{}", prefix, i));
let path1 = codemap::Spanned{span: sp, node: ident};
paths.push(path1);
let expr_path = cx.expr_path(cx.path_ident(sp, ident));
let val = cx.expr(sp, ast::ExprParen(cx.expr_deref(sp, expr_path)));
ident_expr.push((sp, None, val, &[]));
}
let subpats = self.create_subpatterns(cx, paths, mutbl);
(cx.pat_enum(variant.span, variant_path, subpats),
ident_expr)
}
ast::StructVariantKind(ref struct_def) => {
self.create_struct_pattern(cx, variant_path, &**struct_def,
prefix, mutbl)
}
}
self.create_struct_pattern(cx, variant_path, &variant.node.def, prefix, mutbl)
}
}

View File

@ -94,45 +94,35 @@ fn cs_from(name: &str, cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure
let mut arms = Vec::new();
for variant in &enum_def.variants {
match variant.node.kind {
ast::TupleVariantKind(ref args) => {
if !args.is_empty() {
cx.span_err(trait_span,
"`FromPrimitive` cannot be derived for \
enum variants with arguments");
return cx.expr_fail(trait_span,
InternedString::new(""));
}
let span = variant.span;
// expr for `$n == $variant as $name`
let path = cx.path(span, vec![substr.type_ident, variant.node.name]);
let variant = cx.expr_path(path);
let ty = cx.ty_ident(span, cx.ident_of(name));
let cast = cx.expr_cast(span, variant.clone(), ty);
let guard = cx.expr_binary(span, ast::BiEq, n.clone(), cast);
// expr for `Some($variant)`
let body = cx.expr_some(span, variant);
// arm for `_ if $guard => $body`
let arm = ast::Arm {
attrs: vec!(),
pats: vec!(cx.pat_wild(span)),
guard: Some(guard),
body: body,
};
arms.push(arm);
}
ast::StructVariantKind(_) => {
cx.span_err(trait_span,
"`FromPrimitive` cannot be derived for enums \
with struct variants");
return cx.expr_fail(trait_span,
InternedString::new(""));
}
let def = &variant.node.def;
if def.ctor_id.is_none() || !def.fields.is_empty() {
cx.span_err(trait_span, "`FromPrimitive` cannot be derived \
for enums with non-unit variants");
return cx.expr_fail(trait_span,
InternedString::new(""));
}
let span = variant.span;
// expr for `$n == $variant as $name`
let path = cx.path(span, vec![substr.type_ident, variant.node.name]);
let variant = cx.expr_path(path);
let ty = cx.ty_ident(span, cx.ident_of(name));
let cast = cx.expr_cast(span, variant.clone(), ty);
let guard = cx.expr_binary(span, ast::BiEq, n.clone(), cast);
// expr for `Some($variant)`
let body = cx.expr_some(span, variant);
// arm for `_ if $guard => $body`
let arm = ast::Arm {
attrs: vec!(),
pats: vec!(cx.pat_wild(span)),
guard: Some(guard),
body: body,
};
arms.push(arm);
}
// arm for `_ => None`

View File

@ -450,20 +450,12 @@ pub fn noop_fold_foreign_mod<T: Folder>(ForeignMod {abi, items}: ForeignMod,
}
pub fn noop_fold_variant<T: Folder>(v: P<Variant>, fld: &mut T) -> P<Variant> {
v.map(|Spanned {node: Variant_ {id, name, attrs, kind, disr_expr}, span}| Spanned {
v.map(|Spanned {node: Variant_ {id, name, attrs, def, disr_expr}, span}| Spanned {
node: Variant_ {
id: fld.new_id(id),
name: name,
attrs: fold_attrs(attrs, fld),
kind: match kind {
TupleVariantKind(variant_args) => {
TupleVariantKind(variant_args.move_map(|x|
fld.fold_variant_arg(x)))
}
StructVariantKind(struct_def) => {
StructVariantKind(fld.fold_struct_def(struct_def))
}
},
def: fld.fold_struct_def(def),
disr_expr: disr_expr.map(|e| fld.fold_expr(e)),
},
span: fld.new_span(span),

View File

@ -46,11 +46,11 @@ use ast::PatWildSingle;
use ast::{PolyTraitRef, QSelf};
use ast::{Return, BiShl, BiShr, Stmt, StmtDecl};
use ast::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField};
use ast::{StructVariantKind, BiSub, StrStyle};
use ast::{BiSub, StrStyle};
use ast::{SelfExplicit, SelfRegion, SelfStatic, SelfValue};
use ast::{Delimited, SequenceRepetition, TokenTree, TraitItem, TraitRef};
use ast::{TtDelimited, TtSequence, TtToken};
use ast::{TupleVariantKind, Ty, Ty_, TypeBinding};
use ast::{Ty, Ty_, TypeBinding};
use ast::{TyMac};
use ast::{TyFixedLengthVec, TyBareFn, TyTypeof, TyInfer};
use ast::{TyParam, TyParamBound, TyParen, TyPath, TyPolyTraitRef, TyPtr};
@ -5131,22 +5131,13 @@ impl<'a> Parser<'a> {
let variant_attrs = self.parse_outer_attributes();
let vlo = self.span.lo;
let kind;
let mut args = Vec::new();
let struct_def;
let mut disr_expr = None;
let ident = try!(self.parse_ident());
if try!(self.eat(&token::OpenDelim(token::Brace)) ){
// Parse a struct variant.
all_nullary = false;
let start_span = self.span;
let struct_def = try!(self.parse_struct_def());
if struct_def.fields.is_empty() {
self.span_err(start_span,
&format!("unit-like struct variant should be written \
without braces, as `{},`",
ident));
}
kind = StructVariantKind(struct_def);
struct_def = try!(self.parse_struct_def());
} else if self.check(&token::OpenDelim(token::Paren)) {
all_nullary = false;
let arg_tys = try!(self.parse_enum_variant_seq(
@ -5155,25 +5146,31 @@ impl<'a> Parser<'a> {
seq_sep_trailing_allowed(token::Comma),
|p| p.parse_ty_sum()
));
let mut fields = Vec::new();
for ty in arg_tys {
args.push(ast::VariantArg {
fields.push(Spanned { span: ty.span, node: ast::StructField_ {
ty: ty,
kind: ast::UnnamedField(ast::Inherited),
attrs: Vec::new(),
id: ast::DUMMY_NODE_ID,
});
}});
}
kind = TupleVariantKind(args);
struct_def = P(StructDef { fields: fields,
ctor_id: Some(ast::DUMMY_NODE_ID) });
} else if try!(self.eat(&token::Eq) ){
disr_expr = Some(try!(self.parse_expr_nopanic()));
any_disr = disr_expr.as_ref().map(|expr| expr.span);
kind = TupleVariantKind(args);
struct_def = P(StructDef { fields: Vec::new(),
ctor_id: Some(ast::DUMMY_NODE_ID) });
} else {
kind = TupleVariantKind(Vec::new());
struct_def = P(StructDef { fields: Vec::new(),
ctor_id: Some(ast::DUMMY_NODE_ID) });
}
let vr = ast::Variant_ {
name: ident,
attrs: variant_attrs,
kind: kind,
def: struct_def,
id: ast::DUMMY_NODE_ID,
disr_expr: disr_expr,
};

View File

@ -1223,7 +1223,7 @@ impl<'a> State<'a> {
}
ast::ItemStruct(ref struct_def, ref generics) => {
try!(self.head(&visibility_qualified(item.vis,"struct")));
try!(self.print_struct(&**struct_def, generics, item.ident, item.span));
try!(self.print_struct(&struct_def, generics, item.ident, item.span, true));
}
ast::ItemDefaultImpl(unsafety, ref trait_ref) => {
@ -1388,7 +1388,8 @@ impl<'a> State<'a> {
struct_def: &ast::StructDef,
generics: &ast::Generics,
ident: ast::Ident,
span: codemap::Span) -> io::Result<()> {
span: codemap::Span,
print_finalizer: bool) -> io::Result<()> {
try!(self.print_ident(ident));
try!(self.print_generics(generics));
if ast_util::struct_def_is_tuple_like(struct_def) {
@ -1410,7 +1411,9 @@ impl<'a> State<'a> {
try!(self.pclose());
}
try!(self.print_where_clause(&generics.where_clause));
try!(word(&mut self.s, ";"));
if print_finalizer {
try!(word(&mut self.s, ";"));
}
try!(self.end());
self.end() // close the outer-box
} else {
@ -1505,23 +1508,9 @@ impl<'a> State<'a> {
}
pub fn print_variant(&mut self, v: &ast::Variant) -> io::Result<()> {
match v.node.kind {
ast::TupleVariantKind(ref args) => {
try!(self.print_ident(v.node.name));
if !args.is_empty() {
try!(self.popen());
try!(self.commasep(Consistent,
&args[..],
|s, arg| s.print_type(&*arg.ty)));
try!(self.pclose());
}
}
ast::StructVariantKind(ref struct_def) => {
try!(self.head(""));
let generics = ast_util::empty_generics();
try!(self.print_struct(&**struct_def, &generics, v.node.name, v.span));
}
}
try!(self.head(""));
let generics = ast_util::empty_generics();
try!(self.print_struct(&v.node.def, &generics, v.node.name, v.span, false));
match v.node.disr_expr {
Some(ref d) => {
try!(space(&mut self.s));
@ -3103,6 +3092,7 @@ mod tests {
use ast_util;
use codemap;
use parse::token;
use ptr::P;
#[test]
fn test_fun_to_string() {
@ -3129,7 +3119,7 @@ mod tests {
name: ident,
attrs: Vec::new(),
// making this up as I go.... ?
kind: ast::TupleVariantKind(Vec::new()),
def: P(ast::StructDef { fields: Vec::new(), ctor_id: Some(ast::DUMMY_NODE_ID) }),
id: 0,
disr_expr: None,
});

View File

@ -315,20 +315,7 @@ pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V,
variant: &'v Variant,
generics: &'v Generics) {
visitor.visit_ident(variant.span, variant.node.name);
match variant.node.kind {
TupleVariantKind(ref variant_arguments) => {
for variant_argument in variant_arguments {
visitor.visit_ty(&variant_argument.ty)
}
}
StructVariantKind(ref struct_definition) => {
visitor.visit_struct_def(struct_definition,
variant.node.name,
generics,
variant.node.id)
}
}
visitor.visit_struct_def(&variant.node.def, variant.node.name, generics, variant.node.id);
walk_list!(visitor, visit_expr, &variant.node.disr_expr);
walk_list!(visitor, visit_attribute, &variant.node.attrs);
}

View File

@ -23,12 +23,12 @@ struct B(isize);
#[derive(FromPrimitive)]
enum C { Foo(isize), Bar(usize) }
//~^^ ERROR `FromPrimitive` cannot be derived for enum variants with arguments
//~^^^ ERROR `FromPrimitive` cannot be derived for enum variants with arguments
//~^^ ERROR `FromPrimitive` cannot be derived for enums with non-unit variants
//~^^^ ERROR `FromPrimitive` cannot be derived for enums with non-unit variants
#[derive(FromPrimitive)]
enum D { Baz { x: isize } }
//~^^ ERROR `FromPrimitive` cannot be derived for enums with struct variants
//~^^^ ERROR `FromPrimitive` cannot be derived for enums with struct variants
//~^^ ERROR `FromPrimitive` cannot be derived for enums with non-unit variants
//~^^^ ERROR `FromPrimitive` cannot be derived for enums with non-unit variants
pub fn main() {}

View File

@ -1,15 +0,0 @@
// Copyright 2014 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.
// compile-flags: -Z parse-only
enum Foo {
Bar {} //~ ERROR unit-like struct variant should be written without braces, as `Bar,`
}