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

Support const evaulation #596

Closed
wants to merge 17 commits into from
Closed

Conversation

hayashi-stl
Copy link

@hayashi-stl hayashi-stl commented Aug 19, 2020

Fixes #548
For Chalk's tests, a special-formatted Option<u32> is used, where Some(n) evaluates to n and None evaluates to a specific but unknown constant. Some(n) is formatted as n? and None is formatted as ?.

Copy link
Member

@jackh726 jackh726 left a comment

Choose a reason for hiding this comment

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

Just a quick first pass.

@@ -483,6 +483,44 @@ impl<I: Interner> AntiUnifier<'_, '_, I> {
}
}

(ConstValue::Concrete(e), ConstValue::Unevaluated(u))
Copy link
Member

Choose a reason for hiding this comment

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

Initial thought: Will we ever actually give an answer with an Unevaluated const?

Copy link
Author

Choose a reason for hiding this comment

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

I don't see why not. Chalk can return associated type projections in answers, and an unevalutated const is basically a projection.

match u.try_eval(answer_ty, interner) {
Ok(ev) => assert!(c.const_eq(answer_ty, &ev, interner)),

Err(ConstEvalError::TooGeneric) => panic!(
Copy link
Member

Choose a reason for hiding this comment

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

Similarly here...feels like we should have already have caught this before and the answer itself (or the goal) shouldn't have unevaluated consts. (Well...maybe the goal would?)

Copy link
Author

Choose a reason for hiding this comment

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

Turns out that unevaluated const expressions can appear in the answer and the goal in the resolvent if we so much as write impl Foo<3?> for Baz {}.

chalk-integration/src/interner.rs Outdated Show resolved Hide resolved
chalk-ir/src/interner.rs Outdated Show resolved Hide resolved
chalk-ir/src/lib.rs Show resolved Hide resolved
chalk-parse/src/parser.lalrpop Outdated Show resolved Hide resolved
S<N>: Trait
}
} yields {
"Unique; substitution [?0 := 3?], lifetime constraints []"
Copy link
Member

Choose a reason for hiding this comment

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

Ah, interesting. I have to think if this is something we want to be able to support. (Giving solutions with unevaluated consts). It's pretty clear that these would have to be evaluable, since they would have to pass WF/coherence checks.

tests/test/constants.rs Show resolved Hide resolved
goal {
S<?>: Trait
} yields {
"Unique"
Copy link
Member

Choose a reason for hiding this comment

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

See, this should be Ambiguous, for a similar reason that two InferenceVars aren't the same: we don't actually know this would evaluate to the same const.

Copy link
Author

Choose a reason for hiding this comment

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

I've been assuming that for chalk testing purposes that ? evaluates to a specific but unknown constant. I don't feel like breaking reflexivity.

Copy link
Member

Choose a reason for hiding this comment

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

But that's not true. The point here is that ? represents a constant that can't be evaluated yet. Importantly, if you have two constants that can't be evaluated (e.g. {N+1} and {X +1}), then we can't say that if there is a solution that covers one case, there is a solution that covers all cases.

Copy link
Author

Choose a reason for hiding this comment

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

As it turns out, removing const_eq for unevaluated consts and assuming that two ?s don't necessarily evaluate to the same value breaks LocalImplAllowed(Baz: Foo<?>) in the unevaluated_const_unknown coherence test.

Copy link
Member

Choose a reason for hiding this comment

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

That's probably okay and what we expect :) That can be a lowering_error

Copy link
Author

Choose a reason for hiding this comment

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

Wouldn't it be weird for it to fail because it violated the orphan rules, though? impl Foo<?> for Baz isn't violating the orphan rules because Foo is local.

Copy link
Member

Choose a reason for hiding this comment

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

Oops, I never responded to this. Sorry about that.

So, I think theoretically we could always say that impl Foo<?0> for Baz {} never violates orphan rules, since both Foo and Baz are local. However, I think for unevaluated consts, it's okay to say it's Ambiguous if we get TooGeneric. I would have to look more into the orphan rules code to figure out how to best handle this. For this PR, we can mark a comment or FIXME and file a followup issue for more discussion.

tests/test/constants.rs Outdated Show resolved Hide resolved
tests/test/coherence.rs Outdated Show resolved Hide resolved
Comment on lines 587 to 592
// FIXME: The following test fails by violation of the orphan rules.
// This is because right now, unevaluated const expressions have a
// temporary reflexivity hole, where ? != ?,
// which messes with the SLG resolvent.
// The test should be uncommented when the reflexivity hole is fixed.
// It is supposed to fail because of overlapping impls.
Copy link
Member

Choose a reason for hiding this comment

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

See above. What error do we get here if we leave these uncommented? With these, we actually don't know that these are overlapping impls (could impl Foo<3> and impl Foo<4>). But this still shouldn't lower successfully.

Copy link
Author

Choose a reason for hiding this comment

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

Right now it's structural mismatch between answer '?' and pending goal '?'. Is the resolvent allowed to create a CannotProve goal? Also, in the case where chalk can't prove that impls don't overlap, it assumes that they do.

tests/test/constants.rs Outdated Show resolved Hide resolved
chalk-solve/src/infer/unify.rs Outdated Show resolved Hide resolved
@bors
Copy link
Contributor

bors commented Sep 11, 2020

☔ The latest upstream changes (presumably #606) made this pull request unmergeable. Please resolve the merge conflicts.

Note that reviewers usually do not review pull requests until merge conflicts are resolved! Once you resolve the conflicts, you should change the labels applied by bors to indicate that your PR is ready for review. Post this as a comment to change the labels:

@rustbot modify labels: +S-waiting-on-review -S-waiting-on-author

/// `InternedUnevaluatedConst` instances are not created by chalk,
/// it can only evaluate them with the [`try_eval_const`] method
/// and check for (syntactic for now) equality between them.
type InternedUnevaluatedConst: Debug + Clone + Eq + Hash;
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we anticipate that this will carry a "substitutions"?

Copy link
Contributor

Choose a reason for hiding this comment

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

I expect not, right?

&self,
ty: &Self::InternedType,
constant: &Self::InternedUnevaluatedConst,
) -> Result<Self::InternedConcreteConst, ConstEvalError>;
Copy link
Contributor

Choose a reason for hiding this comment

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

I kind of expect this to take a set of substitutions. Consider how the rustc variant looks.

// Note that we assume that the unevaluated const doesn't contain inference variables.
// Also, for now, the unevalutable unevaluated const is too generic.
(&ConstValue::InferenceVar(_), &ConstValue::Unevaluated(_))
| (&ConstValue::Unevaluated(_), &ConstValue::InferenceVar(_)) => Ok(self.goals.push(
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, I think I expected us to unify an inference variable here...

@@ -440,9 +452,23 @@ impl<'t, I: Interner> Unifier<'t, I> {
}
}

// For now, the unevalutable unevaluated const is too generic.
(&ConstValue::Concrete(_), &ConstValue::Unevaluated(_))
| (&ConstValue::Unevaluated(_), &ConstValue::Concrete(_)) => Ok(self.goals.push(
Copy link
Contributor

Choose a reason for hiding this comment

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

...and then to generate a subobligation here, kind of like associated type normalization. Is this planned for "future PRs" or is my idea of how to approach this outdated :)

}
}

// FIXME: The following test fails by structural mismatch of ? and ?
Copy link
Contributor

Choose a reason for hiding this comment

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

What does this FIXME mean exactly?

@jackh726
Copy link
Member

We discussed this in our meeting Tuesday. The conclusion was that the PR as-is isn't correct (see @nikomatsakis's review). Part of this is we need better direction for how consts will be handled.

I'm going to go ahead and close this for now. @josh65536 if you still want to work on this, feel free to reopen. Either Niko or I can answer questions on here or, preferably, Zulip. We really would like to get this over the finish line :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support const evaluation
4 participants