Skip to content
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

typeck: always expose repeat count AnonConsts' parent in generics_of. #70452

Merged
merged 6 commits into from
Apr 15, 2020

Conversation

eddyb
Copy link
Member

@eddyb eddyb commented Mar 27, 2020

This should reduce some of the confusion around #43408, although, if you look at the changed test outputs (for the last commit), they all hit #68436, so nothing new will start compiling.

We can let counts of "repeat expressions" (N in [x; N]) always have the correct generics parenting, because they're always in a body, so nothing in the where clauses or impl trait/type of the parent can use it, and therefore no query cycles can occur.


Other potential candidates we might want to apply the same approach to, are:

We should've done so from the start, the only reason we haven't is because I was squeamish about blacklisting some of the cases, but if we whitelist instead we should be fine.
Also, lazy normalization is taking forever 😞.


There's also 5 other commits here:

r? @nikomatsakis cc @pnkfelix @varkor @yodaldevoid @oli-obk @estebank

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Mar 27, 2020
@eddyb

This comment has been minimized.

@rust-timer

This comment has been minimized.

@bors

This comment has been minimized.

@rust-highfive

This comment has been minimized.

@bors

This comment has been minimized.

@bors bors added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Mar 27, 2020
@eddyb

This comment has been minimized.

@eddyb
Copy link
Member Author

eddyb commented Mar 27, 2020

@bors try @rust-timer queue (we'll also want check-only crater, but only if perf isn't terrible)

@rust-timer
Copy link
Collaborator

Awaiting bors try build completion

@bors
Copy link
Contributor

bors commented Mar 27, 2020

⌛ Trying commit 295003105405c3d12d74f6d1ab7da612cb898350 with merge 97830c559b7e0548f2bde4aea5bfa7277197ac14...

@bors

This comment has been minimized.

Comment on lines +9 to +15
error: constant expression depends on a generic parameter
--> $DIR/issue-62456.rs:5:20
|
LL | let _ = [0u64; N + 1];
| ^^^^^
|
= note: this may fail depending on what value the parameter takes
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should improve the wording of the error. In my eyes I would prefer something along the lines of

error: constant expression can't depend on generic parameter
  --> $DIR/issue-62456.rs:5:20
   |
LL |     let _ = [0u64; N + 1];
   |                    ^^^^^ depends on a generic parameter
   |
   = note: this will be supported in the future, but isn't now

preferably with a link to documentation, tracking issue or its own error code so that we explain why we don't support it yet and when it might be done.

Copy link
Member Author

Choose a reason for hiding this comment

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

The error is indeed misleading, because what you're suggesting isn't what the error means.

The error is trying to say that evaluating the constant expression may only succeed for some "values" of the generic parameter.
The missing piece of the puzzle is a way to put that expression in a where clause to force the caller to evaluate it, ruling out post-monomorphization errors (#68436).

Note that expressions using generics can still evaluate just fine while remaining polymorphic.

cc @varkor

Copy link
Member

Choose a reason for hiding this comment

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

I agree that this diagnostic could be improved, especially as it was misinterpreted. How about something like:

error: constant expression may not depend on a generic parameter
  --> $DIR/issue-62456.rs:5:20
   |
LL |     let _ = [0u64; N + 1];
   |                    ^^^^^
   |
   = note: this expression may only be valid for some values of `N`, which `N` is guaranteed to take

This is a bit long, though this sort of thing hopefully gets the intention across better.

Copy link
Member Author

Choose a reason for hiding this comment

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

"constant expression may not depend on a generic parameter"? (emphasis mine)

Copy link
Contributor

@Centril Centril Mar 27, 2020

Choose a reason for hiding this comment

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

   = note: this will be supported in the future, but isn't now

(Let's not make promises. ^^)

"constant expression may not depend on a generic parameter"? (emphasis mine)

I think we tend to prefer cannot over may not. The former is more definitive.

Copy link
Member

Choose a reason for hiding this comment

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

Maybe is not allowed to depend, which makes clear whether the constant expression is supposed to or not.

Copy link
Member Author

@eddyb eddyb Mar 27, 2020

Choose a reason for hiding this comment

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

But it can depend on generic parameters, the only problem is we have no guarantor for it evaluating successfully.

So perhaps a better phrasing for the error itself might be "cannot prove/determine/guarantee/etc. that constant expression will evaluate successfully" and then we can search its Substs for type/const parameters and list them out to give the more helpful information.

We should also link https://github.com/rust-lang/rust/issues/68436, in some sort of help messaging along the lines of "there is no way to currently write the necessary where clause, watch this space".

Copy link
Member

Choose a reason for hiding this comment

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

Well, I suppose I meant that it could not depend on an "unrestricted" generic parameter (or "guaranteed well-formed"). Yes, it's quite difficult to use language that's both intuitive, and doesn't take up a lot of space. Linking to the issue would be good.

Copy link
Contributor

Choose a reason for hiding this comment

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

+1 on linking to that issue. I would say I've come around to the position that reducing verbosity is a goal, but much lower than correct understandable wording.

Copy link
Member Author

Choose a reason for hiding this comment

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

Opened #71142 for this subthread.

@bors

This comment has been minimized.

@eddyb
Copy link
Member Author

eddyb commented Apr 4, 2020

Got back to this and it looks like the build failure (#70452 (comment)) is a pre-existing bug in the MIR type-checker, for which I've opened #70773 and will now attempt to fix in this PR.

@eddyb eddyb force-pushed the repeat-expr-correct-generics-parent branch from 2950031 to 5aefae3 Compare April 4, 2020 18:39
Comment on lines 2402 to 2378
pub fn eval(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> &Const<'tcx> {
let try_const_eval = |did, param_env: ParamEnv<'tcx>, substs, promoted| {
if let ConstKind::Unevaluated(did, substs, promoted) = self.val {
let param_env_and_substs = param_env.with_reveal_all().and(substs);

// Avoid querying `tcx.const_eval(...)` with any e.g. inference vars.
if param_env_and_substs.has_local_value() {
return None;
}
// HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
// also does later, but we want to do it before checking for
// inference variables.
let param_env_and_substs = tcx.erase_regions(&param_env_and_substs);

// HACK(eddyb) when the query key would contain e.g. inference variables,
// attempt using identity substs and `ParamEnv` instead, that will succeed
// when the expression doesn't depend on any parameters.
// FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that
// we can call `infcx.const_eval_resolve` which handles inference variables.
let param_env_and_substs = if param_env_and_substs.has_local_value() {
tcx.param_env(did).and(InternalSubsts::identity_for_item(tcx, did))
} else {
param_env_and_substs
};

// FIXME(eddyb) maybe the `const_eval_*` methods should take
// `ty::ParamEnvAnd<SubstsRef>` instead of having them separate.
let (param_env, substs) = param_env_and_substs.into_parts();

// try to resolve e.g. associated constants to their definition on an impl, and then
// evaluate the const.
tcx.const_eval_resolve(param_env, did, substs, promoted, None)
.ok()
.map(|val| Const::from_value(tcx, val, self.ty))
};

match self.val {
ConstKind::Unevaluated(did, substs, promoted) => {
// HACK(eddyb) when substs contain e.g. inference variables,
// attempt using identity substs instead, that will succeed
// when the expression doesn't depend on any parameters.
// FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that
// we can call `infcx.const_eval_resolve` which handles inference variables.
if substs.has_local_value() {
let identity_substs = InternalSubsts::identity_for_item(tcx, did);
// The `ParamEnv` needs to match the `identity_substs`.
let identity_param_env = tcx.param_env(did);
match try_const_eval(did, identity_param_env, identity_substs, promoted) {
Some(ct) => ct.subst(tcx, substs),
None => self,
}
} else {
try_const_eval(did, param_env, substs, promoted).unwrap_or(self)
}
match tcx.const_eval_resolve(param_env, did, substs, promoted, None) {
// NOTE(eddyb) `val` contains no lifetimes/types/consts,
// and we use the original type, so nothing from `substs`
// (which may be identity substs, see above),
// can leak through `val` into the const we return.
Ok(val) => Const::from_value(tcx, val, self.ty),

Err(_) => self,
}
_ => self,
} else {
self
}
}
Copy link
Member Author

Choose a reason for hiding this comment

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

@nikomatsakis NB: this is the entirety of the commit that I mentioned in the PR description as being a false start for fixing #70773 and doesn't have to be in this PR. Let me know what you prefer.

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't really understand what this commit is doing exactly. It's erasing lifetimes -- why exactly? And why we do want to do it before checking for inference variables?

Copy link
Member Author

Choose a reason for hiding this comment

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

It's erasing lifetimes that would be erased later, just to increase the chances of the inference variable check passing (and doing fully specific evaluation instead of the polymorphic evaluation attempt with identity substs).

Copy link
Contributor

Choose a reason for hiding this comment

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

How could it lead to the inference variable check passing when it wouldn't have passed otherwise?

Copy link
Member Author

Choose a reason for hiding this comment

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

By erasing lifetime inference variables?

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, I see, duh.

Copy link
Contributor

Choose a reason for hiding this comment

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

OK, makes sense I guess. Might as well keep it.

@eddyb
Copy link
Member Author

eddyb commented Apr 4, 2020

Now that git2-rs compiles fine with this PR:

@bors try @rust-timer queue (we'll also want check-only crater, but only if perf isn't terrible)

@rust-timer
Copy link
Collaborator

Awaiting bors try build completion

@eddyb
Copy link
Member Author

eddyb commented Apr 14, 2020

@bors r=nikomatsakis rollup=never

@bors
Copy link
Contributor

bors commented Apr 14, 2020

📌 Commit 8bb7b7b 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 Apr 14, 2020
@Dylan-DPC-zz
Copy link

@bors p=1

@bors
Copy link
Contributor

bors commented Apr 14, 2020

⌛ Testing commit 8bb7b7b with merge d12f030...

@bors
Copy link
Contributor

bors commented Apr 15, 2020

☀️ Test successful - checks-azure
Approved by: nikomatsakis
Pushing d12f030 to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Apr 15, 2020
@bors bors merged commit d12f030 into rust-lang:master Apr 15, 2020
@eddyb eddyb deleted the repeat-expr-correct-generics-parent branch April 16, 2020 23:19
bors added a commit to rust-lang-ci/rust that referenced this pull request May 3, 2020
…ent, r=nikomatsakis

typeck: always expose explicit enum discriminant `AnonConst`s' parent in `generics_of`.

This is similar to rust-lang#70452 but for explicit `enum` discriminant constant expressions.
However, unlike rust-lang#70452, this PR should have no effect on stable code, as while it alleviates rust-lang#43408 errors, there is no way to actually compile an `enum` with generic parameters *and* explicit discriminants, without `#![feature(arbitrary_enum_discriminant)]`, as explicit discriminant expression don't count as uses of parameters (if they did, they would count as invariant uses).

<hr/>

There's also 2 other commits here, both related to rust-lang#70453:
* "ty: use `delay_span_bug` in `ty::AdtDef::eval_explicit_discr`." - hides the ICEs demonstrated on rust-lang#70453, when there are other errors (which the next commit adds)
* "typeck/wfcheck: require that explicit enum discriminants const-evaluate succesfully." - closes rust-lang#70453 by picking alternative "2", i.e. erroring when a discriminant doesn't fully const-evaluate from the perspective of the `enum` definition

In the future, it might be possible to allow `enum` discriminants to actually depend on parameters, but that will likely require rust-lang#68436 + some way to restrict the values so no two variants can end up with overlapping discriminants.

As this PR would close rust-lang#70453, it shouldn't be merged until a decision is reached there.

r? @nikomatsakis
Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this pull request Aug 16, 2020
Add regression test for issue-66768

Fixes rust-lang#66768

This is fixed by rust-lang#70452 (in particular, https://github.com/rust-lang/rust/pull/70452/files#diff-53aef089a36a8e2ed07627fc8915fe63R1763) and I'm not sure it's worth to add this test (i.e. the tests in rust-lang#70452 are enough), so r? @eddyb to confirm it.
tmandry added a commit to tmandry/rust that referenced this pull request Aug 16, 2020
Add regression test for issue-66768

Fixes rust-lang#66768

This is fixed by rust-lang#70452 (in particular, https://github.com/rust-lang/rust/pull/70452/files#diff-53aef089a36a8e2ed07627fc8915fe63R1763) and I'm not sure it's worth to add this test (i.e. the tests in rust-lang#70452 are enough), so r? @eddyb to confirm it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
F-const_generics `#![feature(const_generics)]` merged-by-bors This PR was explicitly merged by bors. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet