Skip to content

Commit 2939666

Browse files
committed
Auto merge of #28816 - petrochenkov:unistruct, r=nrc
This patch uses the same data structures for structs and enum variants in AST and HIR. These changes in data structures lead to noticeable simplification in most of code dealing with them. I didn't touch the top level, i.e. `ItemStruct` is still `ItemStruct` and not `ItemEnum` with one variant, like in the type checker. As part of this patch, structures and variants get the `kind` field making distinction between "normal" structs, tuple structs and unit structs explicit instead of relying on the number of fields and presence of constructor `NodeId`. In particular, we can now distinguish empty tuple structs from unit structs, which was impossible before! Comprehensive tests for empty structs are added and some improvements to empty struct feature gates are made. Some tests don't pass due to issue #28692 , they are still there for completeness, but are commented out. This patch fixes issue mentioned in #16819 (comment), now emptiness of tuple structs is checked after expansion. It also touches #28750 by providing span for visit_struct_def cc #28336 r? @nrc
2 parents c0dc2cb + 607b8c3 commit 2939666

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+845
-894
lines changed

src/doc/reference.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -2357,7 +2357,7 @@ The currently implemented features of the reference compiler are:
23572357
terms of encapsulation).
23582358
* - `default_type_parameter_fallback` - Allows type parameter defaults to
23592359
influence type inference.
2360-
* - `braced_empty_structs` - Allows use of empty structs with braces.
2360+
* - `braced_empty_structs` - Allows use of empty structs and enum variants with braces.
23612361

23622362
If a feature is promoted to a language feature, then all existing programs will
23632363
start to receive compilation warnings about `#![feature]` directives which enabled

src/librustc/front/map/collector.rs

+9-20
Original file line numberDiff line numberDiff line change
@@ -134,40 +134,29 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
134134
ItemEnum(ref enum_definition, _) => {
135135
for v in &enum_definition.variants {
136136
let variant_def_index =
137-
self.insert_def(v.node.id,
137+
self.insert_def(v.node.data.id(),
138138
NodeVariant(&**v),
139139
DefPathData::EnumVariant(v.node.name));
140140

141-
match v.node.kind {
142-
TupleVariantKind(ref args) => {
143-
for arg in args {
144-
self.create_def_with_parent(Some(variant_def_index),
145-
arg.id,
146-
DefPathData::PositionalField);
147-
}
148-
}
149-
StructVariantKind(ref def) => {
150-
for field in &def.fields {
151-
self.create_def_with_parent(
152-
Some(variant_def_index),
153-
field.node.id,
154-
DefPathData::Field(field.node.kind));
155-
}
156-
}
141+
for field in v.node.data.fields() {
142+
self.create_def_with_parent(
143+
Some(variant_def_index),
144+
field.node.id,
145+
DefPathData::Field(field.node.kind));
157146
}
158147
}
159148
}
160149
ItemForeignMod(..) => {
161150
}
162151
ItemStruct(ref struct_def, _) => {
163152
// If this is a tuple-like struct, register the constructor.
164-
if let Some(ctor_id) = struct_def.ctor_id {
165-
self.insert_def(ctor_id,
153+
if !struct_def.is_struct() {
154+
self.insert_def(struct_def.id(),
166155
NodeStructCtor(&**struct_def),
167156
DefPathData::StructCtor);
168157
}
169158

170-
for field in &struct_def.fields {
159+
for field in struct_def.fields() {
171160
self.create_def(field.node.id, DefPathData::Field(field.node.kind));
172161
}
173162
}

src/librustc/front/map/mod.rs

+8-7
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ pub enum Node<'ast> {
124124
NodeBlock(&'ast Block),
125125

126126
/// NodeStructCtor represents a tuple struct.
127-
NodeStructCtor(&'ast StructDef),
127+
NodeStructCtor(&'ast VariantData),
128128

129129
NodeLifetime(&'ast Lifetime),
130130
NodeTyParam(&'ast TyParam)
@@ -149,7 +149,7 @@ pub enum MapEntry<'ast> {
149149
EntryLocal(NodeId, &'ast Pat),
150150
EntryPat(NodeId, &'ast Pat),
151151
EntryBlock(NodeId, &'ast Block),
152-
EntryStructCtor(NodeId, &'ast StructDef),
152+
EntryStructCtor(NodeId, &'ast VariantData),
153153
EntryLifetime(NodeId, &'ast Lifetime),
154154
EntryTyParam(NodeId, &'ast TyParam),
155155

@@ -471,18 +471,19 @@ impl<'ast> Map<'ast> {
471471
}
472472
}
473473

474-
pub fn expect_struct(&self, id: NodeId) -> &'ast StructDef {
474+
pub fn expect_struct(&self, id: NodeId) -> &'ast VariantData {
475475
match self.find(id) {
476476
Some(NodeItem(i)) => {
477477
match i.node {
478-
ItemStruct(ref struct_def, _) => &**struct_def,
478+
ItemStruct(ref struct_def, _) => struct_def,
479479
_ => panic!("struct ID bound to non-struct")
480480
}
481481
}
482482
Some(NodeVariant(variant)) => {
483-
match variant.node.kind {
484-
StructVariantKind(ref struct_def) => &**struct_def,
485-
_ => panic!("struct ID bound to enum variant that isn't struct-like"),
483+
if variant.node.data.is_struct() {
484+
&variant.node.data
485+
} else {
486+
panic!("struct ID bound to enum variant that isn't struct-like")
486487
}
487488
}
488489
_ => panic!(format!("expected struct, found {}", self.node_to_string(id))),

src/librustc/lint/context.rs

+16-14
Original file line numberDiff line numberDiff line change
@@ -661,14 +661,15 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
661661
hir_visit::walk_fn(self, fk, decl, body, span);
662662
}
663663

664-
fn visit_struct_def(&mut self,
665-
s: &hir::StructDef,
664+
fn visit_variant_data(&mut self,
665+
s: &hir::VariantData,
666666
name: ast::Name,
667667
g: &hir::Generics,
668-
id: ast::NodeId) {
669-
run_lints!(self, check_struct_def, late_passes, s, name, g, id);
668+
item_id: ast::NodeId,
669+
_: Span) {
670+
run_lints!(self, check_struct_def, late_passes, s, name, g, item_id);
670671
hir_visit::walk_struct_def(self, s);
671-
run_lints!(self, check_struct_def_post, late_passes, s, name, g, id);
672+
run_lints!(self, check_struct_def_post, late_passes, s, name, g, item_id);
672673
}
673674

674675
fn visit_struct_field(&mut self, s: &hir::StructField) {
@@ -678,10 +679,10 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
678679
})
679680
}
680681

681-
fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics) {
682+
fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics, item_id: ast::NodeId) {
682683
self.with_lint_attrs(&v.node.attrs, |cx| {
683684
run_lints!(cx, check_variant, late_passes, v, g);
684-
hir_visit::walk_variant(cx, v, g);
685+
hir_visit::walk_variant(cx, v, g, item_id);
685686
run_lints!(cx, check_variant_post, late_passes, v, g);
686687
})
687688
}
@@ -810,14 +811,15 @@ impl<'a, 'v> ast_visit::Visitor<'v> for EarlyContext<'a> {
810811
ast_visit::walk_fn(self, fk, decl, body, span);
811812
}
812813

813-
fn visit_struct_def(&mut self,
814-
s: &ast::StructDef,
814+
fn visit_variant_data(&mut self,
815+
s: &ast::VariantData,
815816
ident: ast::Ident,
816817
g: &ast::Generics,
817-
id: ast::NodeId) {
818-
run_lints!(self, check_struct_def, early_passes, s, ident, g, id);
818+
item_id: ast::NodeId,
819+
_: Span) {
820+
run_lints!(self, check_struct_def, early_passes, s, ident, g, item_id);
819821
ast_visit::walk_struct_def(self, s);
820-
run_lints!(self, check_struct_def_post, early_passes, s, ident, g, id);
822+
run_lints!(self, check_struct_def_post, early_passes, s, ident, g, item_id);
821823
}
822824

823825
fn visit_struct_field(&mut self, s: &ast::StructField) {
@@ -827,10 +829,10 @@ impl<'a, 'v> ast_visit::Visitor<'v> for EarlyContext<'a> {
827829
})
828830
}
829831

830-
fn visit_variant(&mut self, v: &ast::Variant, g: &ast::Generics) {
832+
fn visit_variant(&mut self, v: &ast::Variant, g: &ast::Generics, item_id: ast::NodeId) {
831833
self.with_lint_attrs(&v.node.attrs, |cx| {
832834
run_lints!(cx, check_variant, early_passes, v, g);
833-
ast_visit::walk_variant(cx, v, g);
835+
ast_visit::walk_variant(cx, v, g, item_id);
834836
run_lints!(cx, check_variant_post, early_passes, v, g);
835837
})
836838
}

src/librustc/lint/mod.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,9 @@ pub trait LateLintPass: LintPass {
150150
fn check_trait_item(&mut self, _: &LateContext, _: &hir::TraitItem) { }
151151
fn check_impl_item(&mut self, _: &LateContext, _: &hir::ImplItem) { }
152152
fn check_struct_def(&mut self, _: &LateContext,
153-
_: &hir::StructDef, _: ast::Name, _: &hir::Generics, _: ast::NodeId) { }
153+
_: &hir::VariantData, _: ast::Name, _: &hir::Generics, _: ast::NodeId) { }
154154
fn check_struct_def_post(&mut self, _: &LateContext,
155-
_: &hir::StructDef, _: ast::Name, _: &hir::Generics, _: ast::NodeId) { }
155+
_: &hir::VariantData, _: ast::Name, _: &hir::Generics, _: ast::NodeId) { }
156156
fn check_struct_field(&mut self, _: &LateContext, _: &hir::StructField) { }
157157
fn check_variant(&mut self, _: &LateContext, _: &hir::Variant, _: &hir::Generics) { }
158158
fn check_variant_post(&mut self, _: &LateContext, _: &hir::Variant, _: &hir::Generics) { }
@@ -192,9 +192,9 @@ pub trait EarlyLintPass: LintPass {
192192
fn check_trait_item(&mut self, _: &EarlyContext, _: &ast::TraitItem) { }
193193
fn check_impl_item(&mut self, _: &EarlyContext, _: &ast::ImplItem) { }
194194
fn check_struct_def(&mut self, _: &EarlyContext,
195-
_: &ast::StructDef, _: ast::Ident, _: &ast::Generics, _: ast::NodeId) { }
195+
_: &ast::VariantData, _: ast::Ident, _: &ast::Generics, _: ast::NodeId) { }
196196
fn check_struct_def_post(&mut self, _: &EarlyContext,
197-
_: &ast::StructDef, _: ast::Ident, _: &ast::Generics, _: ast::NodeId) { }
197+
_: &ast::VariantData, _: ast::Ident, _: &ast::Generics, _: ast::NodeId) { }
198198
fn check_struct_field(&mut self, _: &EarlyContext, _: &ast::StructField) { }
199199
fn check_variant(&mut self, _: &EarlyContext, _: &ast::Variant, _: &ast::Generics) { }
200200
fn check_variant_post(&mut self, _: &EarlyContext, _: &ast::Variant, _: &ast::Generics) { }

src/librustc/metadata/encoder.rs

+9-14
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
315315
let vid = variant.did;
316316
let variant_node_id = ecx.local_id(vid);
317317

318-
if let ty::VariantKind::Dict = variant.kind() {
318+
if let ty::VariantKind::Struct = variant.kind() {
319319
// tuple-like enum variant fields aren't really items so
320320
// don't try to encode them.
321321
for field in &variant.fields {
@@ -328,7 +328,7 @@ fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
328328
encode_def_id_and_key(ecx, rbml_w, vid);
329329
encode_family(rbml_w, match variant.kind() {
330330
ty::VariantKind::Unit | ty::VariantKind::Tuple => 'v',
331-
ty::VariantKind::Dict => 'V'
331+
ty::VariantKind::Struct => 'V'
332332
});
333333
encode_name(rbml_w, variant.name);
334334
encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(id));
@@ -381,12 +381,8 @@ fn each_auxiliary_node_id<F>(item: &hir::Item, callback: F) -> bool where
381381
match item.node {
382382
hir::ItemStruct(ref struct_def, _) => {
383383
// If this is a newtype struct, return the constructor.
384-
match struct_def.ctor_id {
385-
Some(ctor_id) if !struct_def.fields.is_empty() &&
386-
struct_def.fields[0].node.kind.is_unnamed() => {
387-
continue_ = callback(ctor_id);
388-
}
389-
_ => {}
384+
if struct_def.is_tuple() {
385+
continue_ = callback(struct_def.id());
390386
}
391387
}
392388
_ => {}
@@ -1023,7 +1019,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
10231019
encode_attributes(rbml_w, &item.attrs);
10241020
encode_repr_attrs(rbml_w, ecx, &item.attrs);
10251021
for v in &enum_definition.variants {
1026-
encode_variant_id(rbml_w, ecx.tcx.map.local_def_id(v.node.id));
1022+
encode_variant_id(rbml_w, ecx.tcx.map.local_def_id(v.node.data.id()));
10271023
}
10281024
encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(item));
10291025
encode_path(rbml_w, path);
@@ -1072,8 +1068,8 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
10721068
// Encode inherent implementations for this structure.
10731069
encode_inherent_implementations(ecx, rbml_w, def_id);
10741070

1075-
if let Some(ctor_id) = struct_def.ctor_id {
1076-
let ctor_did = ecx.tcx.map.local_def_id(ctor_id);
1071+
if !struct_def.is_struct() {
1072+
let ctor_did = ecx.tcx.map.local_def_id(struct_def.id());
10771073
rbml_w.wr_tagged_u64(tag_items_data_item_struct_ctor,
10781074
def_to_u64(ctor_did));
10791075
}
@@ -1085,9 +1081,8 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
10851081
}
10861082

10871083
// If this is a tuple-like struct, encode the type of the constructor.
1088-
if let Some(ctor_id) = struct_def.ctor_id {
1089-
encode_info_for_struct_ctor(ecx, rbml_w, item.name,
1090-
ctor_id, index, item.id);
1084+
if !struct_def.is_struct() {
1085+
encode_info_for_struct_ctor(ecx, rbml_w, item.name, struct_def.id(), index, item.id);
10911086
}
10921087
}
10931088
hir::ItemDefaultImpl(unsafety, _) => {

src/librustc/middle/astencode.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -1315,17 +1315,17 @@ fn copy_item_types(dcx: &DecodeContext, ii: &InlinedItem, orig_did: DefId) {
13151315
def.variants.iter().zip(orig_def.variants.iter())
13161316
{
13171317
debug!("astencode: copying variant {:?} => {:?}",
1318-
orig_variant.did, i_variant.node.id);
1319-
copy_item_type(dcx, i_variant.node.id, orig_variant.did);
1318+
orig_variant.did, i_variant.node.data.id());
1319+
copy_item_type(dcx, i_variant.node.data.id(), orig_variant.did);
13201320
}
13211321
}
13221322
hir::ItemStruct(ref def, _) => {
1323-
if let Some(ctor_id) = def.ctor_id {
1323+
if !def.is_struct() {
13241324
let ctor_did = dcx.tcx.lookup_adt_def(orig_did)
13251325
.struct_variant().did;
13261326
debug!("astencode: copying ctor {:?} => {:?}", ctor_did,
1327-
ctor_id);
1328-
copy_item_type(dcx, ctor_id, ctor_did);
1327+
def.id());
1328+
copy_item_type(dcx, def.id(), ctor_did);
13291329
}
13301330
}
13311331
_ => {}

src/librustc/middle/check_match.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -518,7 +518,7 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor,
518518

519519
ty::TyEnum(adt, _) | ty::TyStruct(adt, _) => {
520520
let v = adt.variant_of_ctor(ctor);
521-
if let VariantKind::Dict = v.kind() {
521+
if let VariantKind::Struct = v.kind() {
522522
let field_pats: Vec<_> = v.fields.iter()
523523
.zip(pats)
524524
.filter(|&(_, ref pat)| pat.node != hir::PatWild(hir::PatWildSingle))

src/librustc/middle/check_static_recursion.rs

+9-8
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckCrateVisitor<'a, 'ast> {
5454
let mut recursion_visitor =
5555
CheckItemRecursionVisitor::new(self, &variant.span);
5656
recursion_visitor.populate_enum_discriminants(enum_def);
57-
recursion_visitor.visit_variant(variant, generics);
57+
recursion_visitor.visit_variant(variant, generics, it.id);
5858
}
5959
}
6060
}
@@ -168,7 +168,7 @@ impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> {
168168
let mut discriminant_map = self.discriminant_map.borrow_mut();
169169
match enum_definition.variants.first() {
170170
None => { return; }
171-
Some(variant) if discriminant_map.contains_key(&variant.node.id) => {
171+
Some(variant) if discriminant_map.contains_key(&variant.node.data.id()) => {
172172
return;
173173
}
174174
_ => {}
@@ -177,7 +177,7 @@ impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> {
177177
// Go through all the variants.
178178
let mut variant_stack: Vec<ast::NodeId> = Vec::new();
179179
for variant in enum_definition.variants.iter().rev() {
180-
variant_stack.push(variant.node.id);
180+
variant_stack.push(variant.node.data.id());
181181
// When we find an expression, every variant currently on the stack
182182
// is affected by that expression.
183183
if let Some(ref expr) = variant.node.disr_expr {
@@ -201,14 +201,14 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> {
201201
}
202202

203203
fn visit_enum_def(&mut self, enum_definition: &'ast hir::EnumDef,
204-
generics: &'ast hir::Generics) {
204+
generics: &'ast hir::Generics, item_id: ast::NodeId) {
205205
self.populate_enum_discriminants(enum_definition);
206-
visit::walk_enum_def(self, enum_definition, generics);
206+
visit::walk_enum_def(self, enum_definition, generics, item_id);
207207
}
208208

209209
fn visit_variant(&mut self, variant: &'ast hir::Variant,
210-
_: &'ast hir::Generics) {
211-
let variant_id = variant.node.id;
210+
_: &'ast hir::Generics, _: ast::NodeId) {
211+
let variant_id = variant.node.data.id();
212212
let maybe_expr;
213213
if let Some(get_expr) = self.discriminant_map.borrow().get(&variant_id) {
214214
// This is necessary because we need to let the `discriminant_map`
@@ -269,9 +269,10 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> {
269269
self.ast_map.expect_item(enum_node_id).node
270270
{
271271
self.populate_enum_discriminants(enum_def);
272+
let enum_id = self.ast_map.as_local_node_id(enum_id).unwrap();
272273
let variant_id = self.ast_map.as_local_node_id(variant_id).unwrap();
273274
let variant = self.ast_map.expect_variant(variant_id);
274-
self.visit_variant(variant, generics);
275+
self.visit_variant(variant, generics, enum_id);
275276
} else {
276277
self.sess.span_bug(e.span,
277278
"`check_static_recursion` found \

src/librustc/middle/const_eval.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ fn lookup_variant_by_id<'a>(tcx: &'a ty::ctxt,
6363
fn variant_expr<'a>(variants: &'a [P<hir::Variant>], id: ast::NodeId)
6464
-> Option<&'a Expr> {
6565
for variant in variants {
66-
if variant.node.id == id {
66+
if variant.node.data.id() == id {
6767
return variant.node.disr_expr.as_ref().map(|e| &**e);
6868
}
6969
}

0 commit comments

Comments
 (0)