Skip to content

rustc: introduce {ast,hir}::AnonConst to consolidate so-called "embedded constants". #50851

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 21, 2018

Conversation

eddyb
Copy link
Member

@eddyb eddyb commented May 18, 2018

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).

r? @nikomatsakis

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label May 18, 2018
@@ -1857,7 +1866,7 @@ pub struct Variant_ {
pub attrs: Vec<Attribute>,
pub data: VariantData,
/// Explicit discriminant, e.g. `Foo = 1`
pub disr_expr: Option<P<Expr>>,
pub disr_expr: Option<Const>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bit strange that const and static initializers are not treated as Const and not visited by fn visit_const, for example, despite being same "constant single-expression bodies".

Copy link
Contributor

@petrochenkov petrochenkov May 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it necessary to introduce Const in AST, btw?
New node ids can be assigned during lowering to HIR too.
At least from syntax/expansion point of view Const is "just an expression".

(I see that some stuff in resolve becomes shorter, but I haven't looked in detail yet.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those have items (or trait/impl associated items) they're directly attached to, so they don't need any changes, but also changing them would complicate a bunch of logic that's straight-forward today and would have to jump through an extra hoop.

There's one potential exception to this, which is that static could be considered to be "more disjoint" from its initializer than const and separating them could allow better bookkeeping of the "allocation" vs "value the allocation is initialized with" (cc @oli-obk), but even then it seems a bit stretched.

I wanted to avoid calling the type EmbeddedConst because it's long and potentially even more confusing, but if anyone has a better suggestion, it could use being more explicit.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the static vs its value won't get easier by changing this. Miri's bookkeeping about that is completely sane now.

Copy link
Member Author

@eddyb eddyb May 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it necessary to introduce Const in AST, btw?
New node ids can be assigned during lowering to HIR too.

Sadly, yes, because the DefId tree is built from the AST, and nodes inside a Const need to be its descendants (this is where some of the ICEs for closures came from).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, what criterion should a constant Expr satisfy to become Const then? No direct parent with DefId?
Discriminants in enums have a direct parent with DefId to which they are attached - the variant itself, in this sense I don't see how they are different from consts or statics. Is preferring Const just a matter of convenience in this case?
Could all this be documented in a comment for Const?

Copy link
Contributor

@petrochenkov petrochenkov May 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, expressions in range patterns have very similar properties to array sizes, etc (THIS ... AND_THIS), but I guess they don't need a body because you can't smuggle arbitrary expressions into them, paths at most.

Copy link
Member Author

@eddyb eddyb May 19, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The criterion is a requirement of separate const-evaluation (which requires separate type-checking).

Array type lengths and enum discriminants don't (necessarily) have a parent body so they need a separate DefId and body to even be type-checked (array type lengths could have a DefId attached to the NodeId of the TyArray, but enum variants already have a DefId with a different meaning).

The count of an ExprRepeat is technically guaranteed to be nested inside another body, but type-checking the ExprRepeat requires const-evaluating the count, which currently can't be done without the count being a separate body.

In contrast, const and static

Also, expressions in range patterns have very similar properties to array sizes

It might be a good idea to keep those separate too, but type-checking them could require inference from the outer body (because of associated consts), so it's tricky.

I think long-term we should perhaps keep such constant expressions (including ones from paths involving const generics, in the future), in a separate body but type-check them like closures (sharing the inference context of their parent body), while retaining the ability to const-eval them.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh. will this make the difference between a variant's discriminant and it's isize value clearer?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will this make the difference between a variant's discriminant and it's isize value clearer?

Doubful.

@petrochenkov petrochenkov self-assigned this May 18, 2018
@@ -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, _) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

huzzah 🎉

@@ -921,6 +921,15 @@ pub enum UnsafeSource {
UserProvided,
}

/// A constant (expression) embedded inside a type, an expression,
/// or used to define the discriminant value of an enum variant.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should call this an AnonymousConst or something like that? This would address @petrochenkov's concern about const vs static items to some extent, since they are clearly not anonymous.

Copy link
Contributor

@petrochenkov petrochenkov May 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, Const seems too generic for this thing that has a very specific technical purpose rather than represents constant expressions in general.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking of ty::Const when I picked the name, TBH, but that doesn't make as much sense in the AST/HIR.

I guess AnonConst would work pretty well, thanks!

@nikomatsakis
Copy link
Contributor

r=me once we settle this bikeshed

@petrochenkov petrochenkov removed their assignment May 19, 2018
@eddyb eddyb force-pushed the the-only-constant branch from 38ab622 to ca44bac Compare May 19, 2018 17:31
@eddyb eddyb changed the title rustc: introduce {ast,hir}::Const to consolidate so-called "embedded constants". rustc: introduce {ast,hir}::AnonConst to consolidate so-called "embedded constants". May 19, 2018
@eddyb eddyb force-pushed the the-only-constant branch from ca44bac to 26aad25 Compare May 19, 2018 17:35
@eddyb
Copy link
Member Author

eddyb commented May 20, 2018

@bors r=nikomatsakis

@bors
Copy link
Collaborator

bors commented May 20, 2018

📌 Commit 26aad25 has been approved by nikomatsakis

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels May 20, 2018
@bors
Copy link
Collaborator

bors commented May 20, 2018

⌛ Testing commit 26aad25 with merge 538fea5...

bors added a commit that referenced this pull request May 20, 2018
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
@bors
Copy link
Collaborator

bors commented May 21, 2018

☀️ Test successful - status-appveyor, status-travis
Approved by: nikomatsakis
Pushing 538fea5 to master...

@bors bors merged commit 26aad25 into rust-lang:master May 21, 2018
@eddyb eddyb deleted the the-only-constant branch May 21, 2018 08:58
kngwyu added a commit to kngwyu/racer-nightly that referenced this pull request Jun 1, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
6 participants