Skip to content

Commit

Permalink
Auto merge of #50851 - eddyb:the-only-constant, r=nikomatsakis
Browse files Browse the repository at this point in the history
rustc: introduce {ast,hir}::AnonConst to consolidate so-called "embedded constants".

Previously, constants in array lengths and enum variant discriminants were "merely an expression", and had no separate ID for, e.g. type-checking or const-eval, instead reusing the expression's.

That complicated code working with bodies, because such constants were the only special case where the "owner" of the body wasn't the HIR parent, but rather the same node as the body itself.
Also, if the body happened to be a closure, we had no way to allocate a `DefId` for both the constant *and* the closure, leading to *several* bugs (mostly ICEs where type errors were expected).

This PR rectifies the situation by adding another (`{ast,hir}::AnonConst`) node around every such constant. Also, const generics are expected to rely on the new `AnonConst` nodes, as well (cc @varkor).
* fixes #48838
* fixes #50600
* fixes #50688
* fixes #50689
* obsoletes #50623

r? @nikomatsakis
  • Loading branch information
bors committed May 20, 2018
2 parents a1d4a95 + 26aad25 commit 538fea5
Show file tree
Hide file tree
Showing 35 changed files with 336 additions and 320 deletions.
22 changes: 15 additions & 7 deletions src/librustc/hir/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,9 @@ pub trait Visitor<'v> : Sized {
fn visit_decl(&mut self, d: &'v Decl) {
walk_decl(self, d)
}
fn visit_anon_const(&mut self, c: &'v AnonConst) {
walk_anon_const(self, c)
}
fn visit_expr(&mut self, ex: &'v Expr) {
walk_expr(self, ex)
}
Expand Down Expand Up @@ -547,7 +550,7 @@ pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V,
generics,
parent_item_id,
variant.span);
walk_list!(visitor, visit_nested_body, variant.node.disr_expr);
walk_list!(visitor, visit_anon_const, &variant.node.disr_expr);
walk_list!(visitor, visit_attribute, &variant.node.attrs);
}

Expand Down Expand Up @@ -576,9 +579,9 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
TyPath(ref qpath) => {
visitor.visit_qpath(qpath, typ.id, typ.span);
}
TyArray(ref ty, length) => {
TyArray(ref ty, ref length) => {
visitor.visit_ty(ty);
visitor.visit_nested_body(length)
visitor.visit_anon_const(length)
}
TyTraitObject(ref bounds, ref lifetime) => {
for bound in bounds {
Expand All @@ -592,8 +595,8 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
walk_list!(visitor, visit_ty_param_bound, bounds);
walk_list!(visitor, visit_lifetime, lifetimes);
}
TyTypeof(expression) => {
visitor.visit_nested_body(expression)
TyTypeof(ref expression) => {
visitor.visit_anon_const(expression)
}
TyInfer | TyErr => {}
}
Expand Down Expand Up @@ -944,6 +947,11 @@ pub fn walk_decl<'v, V: Visitor<'v>>(visitor: &mut V, declaration: &'v Decl) {
}
}

pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst) {
visitor.visit_id(constant.id);
visitor.visit_nested_body(constant.body);
}

pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
visitor.visit_id(expression.id);
walk_list!(visitor, visit_attribute, expression.attrs.iter());
Expand All @@ -954,9 +962,9 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
ExprArray(ref subexpressions) => {
walk_list!(visitor, visit_expr, subexpressions);
}
ExprRepeat(ref element, count) => {
ExprRepeat(ref element, ref count) => {
visitor.visit_expr(element);
visitor.visit_nested_body(count)
visitor.visit_anon_const(count)
}
ExprStruct(ref qpath, ref fields, ref optional_base) => {
visitor.visit_qpath(qpath, expression.id, expression.span);
Expand Down
23 changes: 14 additions & 9 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1080,12 +1080,10 @@ impl<'a> LoweringContext<'a> {
}),
)),
TyKind::Array(ref ty, ref length) => {
let length = self.lower_body(None, |this| this.lower_expr(length));
hir::TyArray(self.lower_ty(ty, itctx), length)
hir::TyArray(self.lower_ty(ty, itctx), self.lower_anon_const(length))
}
TyKind::Typeof(ref expr) => {
let expr = self.lower_body(None, |this| this.lower_expr(expr));
hir::TyTypeof(expr)
hir::TyTypeof(self.lower_anon_const(expr))
}
TyKind::TraitObject(ref bounds, kind) => {
let mut lifetime_bound = None;
Expand Down Expand Up @@ -1365,10 +1363,7 @@ impl<'a> LoweringContext<'a> {
name: v.node.ident.name,
attrs: self.lower_attrs(&v.node.attrs),
data: self.lower_variant_data(&v.node.data),
disr_expr: v.node
.disr_expr
.as_ref()
.map(|e| self.lower_body(None, |this| this.lower_expr(e))),
disr_expr: v.node.disr_expr.as_ref().map(|e| self.lower_anon_const(e)),
},
span: v.span,
}
Expand Down Expand Up @@ -2927,6 +2922,16 @@ impl<'a> LoweringContext<'a> {
}
}

fn lower_anon_const(&mut self, c: &AnonConst) -> hir::AnonConst {
let LoweredNodeId { node_id, hir_id } = self.lower_node_id(c.id);

hir::AnonConst {
id: node_id,
hir_id,
body: self.lower_body(None, |this| this.lower_expr(&c.value)),
}
}

fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
let kind = match e.node {
ExprKind::Box(ref inner) => hir::ExprBox(P(self.lower_expr(inner))),
Expand All @@ -2936,7 +2941,7 @@ impl<'a> LoweringContext<'a> {
}
ExprKind::Repeat(ref expr, ref count) => {
let expr = P(self.lower_expr(expr));
let count = self.lower_body(None, |this| this.lower_expr(count));
let count = self.lower_anon_const(count);
hir::ExprRepeat(expr, count)
}
ExprKind::Tup(ref elts) => {
Expand Down
9 changes: 9 additions & 0 deletions src/librustc/hir/map/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
NodeImplItem(n) => EntryImplItem(parent, dep_node_index, n),
NodeVariant(n) => EntryVariant(parent, dep_node_index, n),
NodeField(n) => EntryField(parent, dep_node_index, n),
NodeAnonConst(n) => EntryAnonConst(parent, dep_node_index, n),
NodeExpr(n) => EntryExpr(parent, dep_node_index, n),
NodeStmt(n) => EntryStmt(parent, dep_node_index, n),
NodeTy(n) => EntryTy(parent, dep_node_index, n),
Expand Down Expand Up @@ -390,6 +391,14 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
});
}

fn visit_anon_const(&mut self, constant: &'hir AnonConst) {
self.insert(constant.id, NodeAnonConst(constant));

self.with_parent(constant.id, |this| {
intravisit::walk_anon_const(this, constant);
});
}

fn visit_expr(&mut self, expr: &'hir Expr) {
self.insert(expr.id, NodeExpr(expr));

Expand Down
118 changes: 42 additions & 76 deletions src/librustc/hir/map/def_collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ pub struct DefCollector<'a> {
pub struct MacroInvocationData {
pub mark: Mark,
pub def_index: DefIndex,
pub const_expr: bool,
}

impl<'a> DefCollector<'a> {
Expand Down Expand Up @@ -74,25 +73,10 @@ impl<'a> DefCollector<'a> {
self.parent_def = parent;
}

pub fn visit_const_expr(&mut self, expr: &Expr) {
match expr.node {
// Find the node which will be used after lowering.
ExprKind::Paren(ref inner) => return self.visit_const_expr(inner),
ExprKind::Mac(..) => return self.visit_macro_invoc(expr.id, true),
// FIXME(eddyb) Closures should have separate
// function definition IDs and expression IDs.
ExprKind::Closure(..) => return,
_ => {}
}

self.create_def(expr.id, DefPathData::Initializer, REGULAR_SPACE, expr.span);
}

fn visit_macro_invoc(&mut self, id: NodeId, const_expr: bool) {
fn visit_macro_invoc(&mut self, id: NodeId) {
if let Some(ref mut visit) = self.visit_macro_invoc {
visit(MacroInvocationData {
mark: id.placeholder_to_mark(),
const_expr,
def_index: self.parent_def.unwrap(),
})
}
Expand All @@ -119,7 +103,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) =>
DefPathData::ValueNs(i.ident.name.as_interned_str()),
ItemKind::MacroDef(..) => DefPathData::MacroDef(i.ident.name.as_interned_str()),
ItemKind::Mac(..) => return self.visit_macro_invoc(i.id, false),
ItemKind::Mac(..) => return self.visit_macro_invoc(i.id),
ItemKind::GlobalAsm(..) => DefPathData::Misc,
ItemKind::Use(..) => {
return visit::walk_item(self, i);
Expand All @@ -129,30 +113,6 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {

self.with_parent(def, |this| {
match i.node {
ItemKind::Enum(ref enum_definition, _) => {
for v in &enum_definition.variants {
let variant_def_index =
this.create_def(v.node.data.id(),
DefPathData::EnumVariant(v.node.ident
.name.as_interned_str()),
REGULAR_SPACE,
v.span);
this.with_parent(variant_def_index, |this| {
for (index, field) in v.node.data.fields().iter().enumerate() {
let name = field.ident.map(|ident| ident.name)
.unwrap_or_else(|| Symbol::intern(&index.to_string()));
this.create_def(field.id,
DefPathData::Field(name.as_interned_str()),
REGULAR_SPACE,
field.span);
}

if let Some(ref expr) = v.node.disr_expr {
this.visit_const_expr(expr);
}
});
}
}
ItemKind::Struct(ref struct_def, _) | ItemKind::Union(ref struct_def, _) => {
// If this is a tuple-like struct, register the constructor.
if !struct_def.is_struct() {
Expand All @@ -161,15 +121,6 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
REGULAR_SPACE,
i.span);
}

for (index, field) in struct_def.fields().iter().enumerate() {
let name = field.ident.map(|ident| ident.name)
.unwrap_or_else(|| Symbol::intern(&index.to_string()));
this.create_def(field.id,
DefPathData::Field(name.as_interned_str()),
REGULAR_SPACE,
field.span);
}
}
_ => {}
}
Expand All @@ -184,7 +135,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {

fn visit_foreign_item(&mut self, foreign_item: &'a ForeignItem) {
if let ForeignItemKind::Macro(_) = foreign_item.node {
return self.visit_macro_invoc(foreign_item.id, false);
return self.visit_macro_invoc(foreign_item.id);
}

let def = self.create_def(foreign_item.id,
Expand All @@ -197,6 +148,28 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
});
}

fn visit_variant(&mut self, v: &'a Variant, g: &'a Generics, item_id: NodeId) {
let def = self.create_def(v.node.data.id(),
DefPathData::EnumVariant(v.node.ident
.name.as_interned_str()),
REGULAR_SPACE,
v.span);
self.with_parent(def, |this| visit::walk_variant(this, v, g, item_id));
}

fn visit_variant_data(&mut self, data: &'a VariantData, _: Ident,
_: &'a Generics, _: NodeId, _: Span) {
for (index, field) in data.fields().iter().enumerate() {
let name = field.ident.map(|ident| ident.name)
.unwrap_or_else(|| Symbol::intern(&index.to_string()));
let def = self.create_def(field.id,
DefPathData::Field(name.as_interned_str()),
REGULAR_SPACE,
field.span);
self.with_parent(def, |this| this.visit_struct_field(field));
}
}

fn visit_generic_param(&mut self, param: &'a GenericParam) {
match *param {
GenericParam::Lifetime(ref lifetime_def) => {
Expand Down Expand Up @@ -227,50 +200,45 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
TraitItemKind::Type(..) => {
DefPathData::AssocTypeInTrait(ti.ident.name.as_interned_str())
},
TraitItemKind::Macro(..) => return self.visit_macro_invoc(ti.id, false),
TraitItemKind::Macro(..) => return self.visit_macro_invoc(ti.id),
};

let def = self.create_def(ti.id, def_data, ITEM_LIKE_SPACE, ti.span);
self.with_parent(def, |this| {
if let TraitItemKind::Const(_, Some(ref expr)) = ti.node {
this.visit_const_expr(expr);
}

visit::walk_trait_item(this, ti);
});
self.with_parent(def, |this| visit::walk_trait_item(this, ti));
}

fn visit_impl_item(&mut self, ii: &'a ImplItem) {
let def_data = match ii.node {
ImplItemKind::Method(..) | ImplItemKind::Const(..) =>
DefPathData::ValueNs(ii.ident.name.as_interned_str()),
ImplItemKind::Type(..) => DefPathData::AssocTypeInImpl(ii.ident.name.as_interned_str()),
ImplItemKind::Macro(..) => return self.visit_macro_invoc(ii.id, false),
ImplItemKind::Macro(..) => return self.visit_macro_invoc(ii.id),
};

let def = self.create_def(ii.id, def_data, ITEM_LIKE_SPACE, ii.span);
self.with_parent(def, |this| {
if let ImplItemKind::Const(_, ref expr) = ii.node {
this.visit_const_expr(expr);
}

visit::walk_impl_item(this, ii);
});
self.with_parent(def, |this| visit::walk_impl_item(this, ii));
}

fn visit_pat(&mut self, pat: &'a Pat) {
match pat.node {
PatKind::Mac(..) => return self.visit_macro_invoc(pat.id, false),
PatKind::Mac(..) => return self.visit_macro_invoc(pat.id),
_ => visit::walk_pat(self, pat),
}
}

fn visit_anon_const(&mut self, constant: &'a AnonConst) {
let def = self.create_def(constant.id,
DefPathData::AnonConst,
REGULAR_SPACE,
constant.value.span);
self.with_parent(def, |this| visit::walk_anon_const(this, constant));
}

fn visit_expr(&mut self, expr: &'a Expr) {
let parent_def = self.parent_def;

match expr.node {
ExprKind::Mac(..) => return self.visit_macro_invoc(expr.id, false),
ExprKind::Repeat(_, ref count) => self.visit_const_expr(count),
ExprKind::Mac(..) => return self.visit_macro_invoc(expr.id),
ExprKind::Closure(..) => {
let def = self.create_def(expr.id,
DefPathData::ClosureExpr,
Expand All @@ -287,20 +255,18 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {

fn visit_ty(&mut self, ty: &'a Ty) {
match ty.node {
TyKind::Mac(..) => return self.visit_macro_invoc(ty.id, false),
TyKind::Array(_, ref length) => self.visit_const_expr(length),
TyKind::Mac(..) => return self.visit_macro_invoc(ty.id),
TyKind::ImplTrait(..) => {
self.create_def(ty.id, DefPathData::ImplTrait, REGULAR_SPACE, ty.span);
}
TyKind::Typeof(ref expr) => self.visit_const_expr(expr),
_ => {}
}
visit::walk_ty(self, ty);
}

fn visit_stmt(&mut self, stmt: &'a Stmt) {
match stmt.node {
StmtKind::Mac(..) => self.visit_macro_invoc(stmt.id, false),
StmtKind::Mac(..) => self.visit_macro_invoc(stmt.id),
_ => visit::walk_stmt(self, stmt),
}
}
Expand All @@ -310,7 +276,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
match nt.0 {
token::NtExpr(ref expr) => {
if let ExprKind::Mac(..) = expr.node {
self.visit_macro_invoc(expr.id, false);
self.visit_macro_invoc(expr.id);
}
}
_ => {}
Expand Down
Loading

0 comments on commit 538fea5

Please sign in to comment.