From 4da58a5bd6f921b446e46cf65790975598289308 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Tue, 23 Oct 2012 19:18:18 -0700 Subject: [PATCH] rustc: Implement typechecking for tuple structs. r=nmatsakis --- src/libsyntax/ast.rs | 30 +++++++++++++++++++++++++- src/libsyntax/fold.rs | 6 ++++-- src/libsyntax/parse/parser.rs | 7 ++++-- src/rustc/middle/resolve.rs | 21 ++++++++++++------ src/rustc/middle/typeck/collect.rs | 34 ++++++++++++++++++++++++++++++ 5 files changed, 87 insertions(+), 11 deletions(-) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 8aef8a0caee9..e25fb470bb9b 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1444,6 +1444,31 @@ enum struct_field_kind { unnamed_field // element of a tuple-like struct } +impl struct_field_kind : cmp::Eq { + pure fn eq(other: &struct_field_kind) -> bool { + match self { + named_field(ident_a, class_mutability_a, visibility_a) => { + match *other { + named_field(ident_b, class_mutability_b, visibility_b) + => { + ident_a == ident_b && + class_mutability_a == class_mutability_b && + visibility_a == visibility_b + } + unnamed_field => false + } + } + unnamed_field => { + match *other { + named_field(*) => false, + unnamed_field => true + } + } + } + } + pure fn ne(other: &struct_field_kind) -> bool { !self.eq(other) } +} + #[auto_serialize] #[auto_deserialize] type struct_def = { @@ -1452,7 +1477,10 @@ type struct_def = { methods: ~[@method], /* methods */ /* (not including ctor or dtor) */ /* dtor is optional */ - dtor: Option + dtor: Option, + /* ID of the constructor. This is only used for tuple- or enum-like + * structs. */ + ctor_id: node_id }; /* diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 2fd1d8ec928d..d1b975492254 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -280,7 +280,8 @@ fn fold_struct_def(struct_def: @ast::struct_def, fld: ast_fold) traits: vec::map(struct_def.traits, |p| fold_trait_ref(*p, fld)), fields: vec::map(struct_def.fields, |f| fold_struct_field(*f, fld)), methods: vec::map(struct_def.methods, |m| fld.fold_method(*m)), - dtor: dtor + dtor: dtor, + ctor_id: fld.new_id(struct_def.ctor_id) }; } @@ -563,7 +564,8 @@ fn noop_fold_variant(v: variant_, fld: ast_fold) -> variant_ { |f| fld.fold_struct_field(*f)), methods: vec::map(struct_def.methods, |m| fld.fold_method(*m)), - dtor: dtor + dtor: dtor, + ctor_id: fld.new_id(struct_def.ctor_id) }) } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6e16e4eec1ab..e0570c537a70 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2722,12 +2722,14 @@ impl Parser { self_id: self.get_id(), body: d_body}, span: d_s}}; + let _ = self.get_id(); // XXX: Workaround for crazy bug. (class_name, item_class(@{ traits: traits, fields: move fields, methods: move methods, - dtor: actual_dtor + dtor: actual_dtor, + ctor_id: self.get_id() }, ty_params), None) } @@ -3073,7 +3075,8 @@ impl Parser { traits: ~[], fields: move fields, methods: move methods, - dtor: actual_dtor + dtor: actual_dtor, + ctor_id: self.get_id() }; } diff --git a/src/rustc/middle/resolve.rs b/src/rustc/middle/resolve.rs index efddd6f44711..1f7b3b1c8612 100644 --- a/src/rustc/middle/resolve.rs +++ b/src/rustc/middle/resolve.rs @@ -9,8 +9,7 @@ use middle::pat_util::{pat_bindings}; use syntax::ast::{_mod, add, arm}; use syntax::ast::{bind_by_ref, bind_by_implicit_ref, bind_by_value}; use syntax::ast::{bitand, bitor, bitxor}; -use syntax::ast::{binding_mode, blk, - capture_clause, class_ctor, class_dtor}; +use syntax::ast::{binding_mode, blk, capture_clause, class_ctor, class_dtor}; use syntax::ast::{crate, crate_num, decl_item}; use syntax::ast::{def, def_arg, def_binding, def_class, def_const, def_fn}; use syntax::ast::{def_foreign_mod, def_id, def_label, def_local, def_mod}; @@ -39,7 +38,7 @@ use syntax::ast::{trait_ref, tuple_variant_kind, Ty, ty_bool, ty_char}; use syntax::ast::{ty_f, ty_f32, ty_f64, ty_float, ty_i, ty_i16, ty_i32}; use syntax::ast::{ty_i64, ty_i8, ty_int, ty_param, ty_path, ty_str, ty_u}; use syntax::ast::{ty_u16, ty_u32, ty_u64, ty_u8, ty_uint, type_value_ns}; -use syntax::ast::{ty_param_bound}; +use syntax::ast::{ty_param_bound, unnamed_field}; use syntax::ast::{variant, view_item, view_item_export, view_item_import}; use syntax::ast::{view_item_use, view_path_glob, view_path_list}; use syntax::ast::{view_path_simple, visibility, anonymous, named}; @@ -1179,12 +1178,22 @@ impl Resolver { } // These items live in both the type and value namespaces. - item_class(*) => { + item_class(struct_def, _) => { let (name_bindings, new_parent) = self.add_child(ident, parent, ForbidDuplicateTypes, sp); - (*name_bindings).define_type - (privacy, def_ty(local_def(item.id)), sp); + name_bindings.define_type( + privacy, def_ty(local_def(item.id)), sp); + + // If this struct is tuple-like or enum-like, define a name + // in the value namespace. + if struct_def.fields.len() == 0 || + struct_def.fields[0].node.kind == unnamed_field { + name_bindings.define_value( + privacy, + def_class(local_def(struct_def.ctor_id)), + sp); + } // Record the def ID of this struct. self.structs.insert(local_def(item.id), ()); diff --git a/src/rustc/middle/typeck/collect.rs b/src/rustc/middle/typeck/collect.rs index 1660f1e076ce..c8dcde52ebb9 100644 --- a/src/rustc/middle/typeck/collect.rs +++ b/src/rustc/middle/typeck/collect.rs @@ -22,6 +22,7 @@ are represented as `ty_param()` instances. use astconv::{ast_conv, ty_of_fn_decl, ty_of_arg, ast_ty_to_ty}; use ast_util::trait_method_to_ty_method; +use middle::ty::{FnMeta, FnSig, FnTyBase}; use rscope::*; use ty::{FnTyBase, FnMeta, FnSig, InstantiatedTraitRef}; use util::common::pluralize; @@ -559,6 +560,39 @@ fn convert_struct(ccx: @crate_ctxt, write_ty_to_tcx(tcx, trait_ref.impl_id, tpt.ty); tcx.tcache.insert(local_def(trait_ref.impl_id), tpt); } + + // If this struct is enum-like or tuple-like, create the type of its + // constructor. + if struct_def.fields.len() == 0 { + // Enum-like. + write_ty_to_tcx(tcx, struct_def.ctor_id, selfty); + tcx.tcache.insert(local_def(struct_def.ctor_id), tpt); + } else if struct_def.fields[0].node.kind == ast::unnamed_field { + // Tuple-like. + let ctor_fn_ty = ty::mk_fn(tcx, FnTyBase { + meta: FnMeta { + purity: ast::pure_fn, + proto: ty::proto_bare, + bounds: @~[], + ret_style: ast::return_val, + }, + sig: FnSig { + inputs: do struct_def.fields.map |field| { + { + mode: ast::expl(ast::by_copy), + ty: ccx.tcx.tcache.get(local_def(field.node.id)).ty + } + }, + output: selfty + } + }); + write_ty_to_tcx(tcx, struct_def.ctor_id, ctor_fn_ty); + tcx.tcache.insert(local_def(struct_def.ctor_id), { + bounds: tpt.bounds, + region_param: tpt.region_param, + ty: ctor_fn_ty + }); + } } fn convert_foreign(ccx: @crate_ctxt, i: @ast::foreign_item) {