-
Notifications
You must be signed in to change notification settings - Fork 13.2k
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
Closures cannot be constants #50623
Closures cannot be constants #50623
Conversation
During type collection, error if a closures is found in constant position, catching that before they go causing ICEs. Fixes rust-lang#50600. Fixes rust-lang#48838.
(rust_highfive has picked a reviewer for you, use r? to override) |
src/librustc_typeck/collect.rs
Outdated
if gen.is_some() { | ||
let hir_id = tcx.hir.node_to_hir_id(node_id); | ||
return tcx.typeck_tables_of(def_id).node_id_to_type(hir_id); | ||
} | ||
|
||
if !tcx.has_typeck_tables(def_id) { | ||
span_err!(tcx.sess, span, E0912, "closures cannot be constants"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: closures can be constants:
const FOO: fn() = || println!("Gah!");
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True, what about expected numerical constant, found closure
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sounds much better to me, thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need this check at all? I'd assume if we left it out, we'd get the real typeck error.
r? @oli-obk |
@leodasvacas I understand that we need the check in the const interpreter, but typeck can already correctly process type mismatches in e.g. statics. static U: usize = |x: u8| {};
so... we should probably figure out how to make the parent of the closure be the constant? |
The PR as it stands probably errors on struct Foo ([u8; (|x: u8| { }, 9).1]);
enum Functions {
Square = (|x:i32| { }, 42).1,
} And I think that worked at some point in time. |
Good examples, this PR indeed errors on them but the current stable will ICE on them, don't know if it worked on older versions.
That could work, but what do you mean by "the constant"? I tried attaching closure and other sub-exprs to outermost expr of a |
While playing with this I found another issue #50688, not sure if related. |
Sounds very much related (taking the wrong surrounding scope (main instead of the constant)). |
|
…r of some const exprs
In the previous commit I made some progress fiddling with the definition tree, now the struct example works. I opened a bug to track the enum discriminant example, there is probably a better structural fix to all these issues but this PR already makes good progress. |
@@ -268,34 +269,41 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { | |||
fn visit_expr(&mut self, expr: &'a Expr) { | |||
let parent_def = self.parent_def; | |||
|
|||
match expr.node { | |||
self.parent_def = match expr.node { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you store this in a temporary variable and assign the self.parent_def = temp.or(self.parent_def)
below? I think it would make the steps involved here a bit clearer
struct Foo ([u8; (|x: u8| { }, 9).1]); | ||
|
||
// FIXME(#50689) We'd like the below to also work, | ||
// but due to how DefCollector handles discr_expr differently it doesn't right now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you also add a this fixme the the location where discr_expr is handled?
Thank you for the review, I've addressed the comments. |
if gen.is_some() { | ||
let hir_id = tcx.hir.node_to_hir_id(node_id); | ||
return tcx.typeck_tables_of(def_id).node_id_to_type(hir_id); | ||
} | ||
|
||
if !tcx.has_typeck_tables(def_id) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we still need this check? I thought the DefIds were setup correctly now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The def ids in discriminants will still have the enum as parent (so will fail here), for structs a case like struct Foo([u8; |x: u8| { }])
will also fail because the closure itself is the outer expression so it will have no parent to attach. So yhea without the check this would still ICE in some cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh... I thought the changes that made (|x: u8| {}, 42).1
work also got rid of the ICE.
@bors r+ |
📌 Commit 0356813 has been approved by |
Closing in favour of #50851 which is a real fix. |
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
During type collection, error if a closures is found in constant position, catching that before they go causing ICEs.
Fixes #50600.
Fixes #48838.