-
Notifications
You must be signed in to change notification settings - Fork 4
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 for ghc-9.2 #35
Open
gelisam
wants to merge
4
commits into
main
Choose a base branch
from
gelisam/ghc-9.2
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+15
−4
Open
Changes from 3 commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
This looks suspicious. If the test has to be changed in order for the test to pass, that means the test is failing, no?
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.
I see that in ghc-9.2, the unmodified test fails with
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 commit which introduces this test says:
The body of
f6
isfoo @(F a (G x y))
, which requires aFoo (F a (G x y))
instance. The constraintF a b ~ G x y
means that ghc could decide to simplify the requirement toFoo (F a (F a b))
. This would allow the rewrite ruleforall a b. F a (F a b) ~ F a b
to fire, thus simplifying the requirement toFoo (F a b)
, which matches the given.The difficulty is that ghc has no reason to choose to make that "simplification", because
F a b
is not in any way simpler thanG x y
. It is thus the job of typelevel-rewrite-rules to look at the available equality constraints and conclude thatFoo (F a (G x y))
can be simplified toFoo (F a b)
.In other words, this is a legitimate test. Changing the constraint from
F a b ~ G x y
tob ~ G x y
completely changes the test:b
is simpler thanG x y
, so ghc is more likely to decide to make the simplification on its own, so the test no longer checks that typelevel-rewrite-rules is able to use the available equality constraints to look a few steps ahead.Foo (F a b)
, which already matches the given without requiring typelevel-rewrite-rules to rewrite anything.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.
Looking at the contents of
typeSubst
, the problem is clear: ghc-9.2 no longer replaces nested calls to type families with type variables namedfskN
. typelevel-rewrite-rules thus needs to work harder to determine whether rewrite rules should fire.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.
Thank you for your review.
The reason why hasktorch didn't generate an error was that this condition was not used by chance.
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.
I think we might also need to add a test where the expression to be substituted is inside a larger expression. Previously, with GHC separating all the sub-expressions, it was enough to check if the RHS of a
fskN ~ F a b
constraint matched the rewrite pattern, but it is now necessary to look deeper inside both the LHS and the RHS ofF x (F a b) ~ G x (F a b)
.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 rewrite code is using two different substitution types:
Beside the poor naming choice (both hold types, so the "Type" prefix doesn't clarify the difference between the two) and the accidental use of two different data structure, the main difference is the key type:
TyVar
is a type variable, whileTypeEq
can be any type... But the code assumes it's a type variable 🤦The one which uses
TyVar
keys holds the replacements for the variables in the LHS of a rewrite rule, while the one which usesTypeEq
keys holds thefsk1 ~ G x y
constraints from GHC.The fact that
TypeEq
allows arbitrary types as keys is what allows typelevel-rewrite-rules not to barf on ghc-9.2'sF a b ~ G x y
constraints: the key is nowF a b
. But that doesn't work because if the type expression to be rewritten contains anF a b
, that part will be expanded toFun "F" [Var "a", Var "b"]
before the rewrite begins, and it is only at the leaves that the rewrite code checks whether"a"
or"b"
matches the keyF a b
. The substitution is thus not performed, and that's why the test fails on ghc-9.2.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.
Taking a closer look, the data structure choice is not accidental at all! ghc simplifies the constraint
F a b ~ G x y
to two constraints,fsk1 ~ F a b
andfsk1 ~ G x y
. Normally an association list with duplicate keys just wastes space becauseData.List.lookup
stops after the first occurrence, but the rewrite code looks at all the possible substitutions. This has exponential cost, but has the benefit of being correct!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.
It doesn't look like the rewrite code is carefully undoing the substitutions it performs when it encounters an
fskN
. Iffsk1 ~ F a fsk2
andfsk2 ~ G x y
, then when the rewrite code encountersFoo fsk1
, it expands it toFoo (F a (G x y))
, rewrites that toFoo (F a b)
, and then replaces the originalFoo fsk1
withFoo (F a b)
. That seems to work fine, but I am now concerned that if ghc also knew thatfsk2 ~ H u v
, that information is now lost. So perhaps we should be more careful.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.
Thinking about this further, there is no reason to expect that
fsk2 ~ H u v
should still hold. If the rewrite rules says thatF a (F a b)
should rewrite toF a
, that's a claim about a property ofF
, it does not imply that the rewrite should be performed becauseF a b ~ F a
. So I now think that the current code is correct, for pre-ghc-9.2 versions at least.