-
Notifications
You must be signed in to change notification settings - Fork 138
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
Fix for #1904 autolifting of data fields #1921
base: develop
Are you sure you want to change the base?
Fix for #1904 autolifting of data fields #1921
Conversation
I have added more tests. The second test in the checklist fails, and I'm not sure why. LH doesn't declare it unsafe, it seems to just issue an error, so the test is "correct", but not outputting what the test harness expects. Not sure how to deal with this. Additionally, the third test has been added but does not pass. I will wait until I get confirmation that it should before I start work on it, however. |
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.
Looks pretty good!
It surprises me a bit that all that was needed was to generate the appropriate selector names.
There is one test that looks amiss though (tests/datacon/neg/AutoliftedFields00.hs).
|
||
{-@ f :: { t : T | getT t <= 0 } -> Nat @-} | ||
f :: T -> Nat | ||
f (T x) = x |
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.
If x
is a Nat
, as the type of getT
says, shouldn't this function be accepted by LH?
If I try the following program, supposedly equivalent to this test, LH accepts it.
{-@ LIQUID "--exact-data-cons" @-}
module AutoliftedFields00 where
{-@ type Nat = { v : Int | v >= 0 } @-}
type Nat = Int
{-@ data T = T { getT :: Nat } @-}
data T = T { getT :: Nat }
{-@ f :: { t : T | getT t <= 0 } -> Nat @-}
f :: T -> Nat
f (T x) = x
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 can confirm your program is accepted while the one I wrote is not... though I'm not sure why!
I do not understand fully why the one with the explicit data decl is accepted. My understanding is that if getT :: Nat
and getT t <= 0
then the only available value for the function to return is when x == 0
. I suppose that subtypes Nat
, and that's why it's accepted, since there is no "true" (in the HM sense) refinement type for anything?
Then it must be that Nat
is being used as Int
in the no decl case... No, I still don't understand. Since, getT t <= 0
would imply x <= 0
which subtypes Int
, just like in the above case! I will investigate further.
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 understand it this way. LH needs to prove that f
returns a Nat
, since that is what the specification says. There are two hypothesis to accomplish this
- the returned
x
is aNat
becauset = T x
(inferred from the pattern matching), andT :: Nat -> T
. x = getT t && getT t <= 0
So LH completes the proof using hypothesis (1).
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 can confirm that the reason is that the fields are being inferred to have (refinement) type GHC.Types.Int
instead of AutoliftedFields00.Nat
. With the specification, the type is correctly Nat
. @nikivazou, do you happen to have an idea of why this would be? I'm vaguely aware of expansion being done using the Expand
typeclass, and I suspect it's being done too early on for fields/data decls, so that the alias is being expanded before LH has a chance to see it and know that it should use the corresponding LH alias. However, the details are much more complicated than what I've been able to figure out myself. For example, I don't know when the type for the field is first grabbed from GHC; if you knew this or could point me in the right direction it would be greatly appreciated!
type Nat = Int | ||
|
||
{-@ data T = T { getMyT :: Nat } @-} | ||
data T = T { getT :: Nat } |
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 would have expected naming a field differently in the specification to be an error. Shouldn't it fail?
I have tried many times to get this to work, but I can't seem to. I thought I was close at one point, but I can't seem to close the deal! Was wondering if @nikivazou had any hints? Consider the following LH program, where I have double-primed {-@ LIQUID "--exact-data-cons" @-}
-- data decl in LH is missing but uses a LH-refined type alias correctly
module AutoliftedFields000 where
{-@ type Nat'' = { v : Int | v >= 0 } @-}
type Nat'' = Int
data T = T { getT :: Nat'' }
f :: Int -> Nat''
f = getT . T
g :: Int -> Nat''
g z = getT (T z)
x :: T
x = T 0
y :: Nat''
y = getT x We would like this program to fail with errors about With some effort, I was able to disable this early expansion, but then of course we fail with sort errors because Right now I am able to defer expansion, but I can't manage to actually execute it later. |
I have converted to a draft until I can wrap my head around this better, and will be working on other simpler issues. |
Sorry!!! I totally miss that :( |
As discussed in the issue (#1904), this proceeds with Solution B.
I am looking to write more tests for this change, but I'm not quite sure the best way to do so. I was hoping to add the following, and was hoping reviewers might be able to suggest others: