refine: improve typ_at_lifts and add typ_at_props' locale - #1006
Conversation
| by (auto simp: valid_bound_tcb'_def valid_def typ_at_tcb'[symmetric] split: option.splits) | ||
| (* use b_itself parameter to fix free type variable in interface lemmas *) | ||
| locale typ_at_gen = Invariants_H_cte_ats + | ||
| fixes b_itself :: 'b |
There was a problem hiding this comment.
This fixes was a pain but is necessary to be able to make this interface. The alternative would be to move all of these gen constructions to InvariantUpdates_H, after ArchInvsLemmas_H and where the needed arch lemmas could be requalified.
The parameter is generally resolved once the typ_at_gen locale is interpreted in ArchInvsLemmas_H, but the downside is that it appears in all future interpretations of the gen_typ_at_props locale as a parameter that can be ignored.
There was a problem hiding this comment.
See https://github.com/seL4/l4v/pull/1006/changes#diff-1e2b2cf051529198334e7ad45c0bebf1785e31a833e15cb37429a0610a6d82c0R1337 for an example of what I mean by the parameter appearing as something that can be ignored. Adding the _ is very easy if you know about it or are copying an existing interpretation but could be confusing otherwise.
There was a problem hiding this comment.
We might need a longer comment somewhere central that explains how to use the infrastructure (then this bit could go there). It's fairly clear now while we're focussing on it, but I can well imagine being confused later what sublocale I need to do when and which methods I should be using.
(the usual name for the kernel ext type would be z -- any particular reason you didn't pick that one?)
There was a problem hiding this comment.
I don't think this is the kernel ext type, the 'kernel' here is a monad?
These assumptions appear to be saying:
"given a monadic function with a return value of 'b, assume that you can do a typ_at' lift over valid_arch_tcb' (strong version, for some reason) and valid_arch_cap' (weak version, for some reason)"
Then for every function you want the typ_at' lifting tech for, you have to instantiate this locale via interpretation?
Also, why these specific assumptions?
There was a problem hiding this comment.
What I'm also not understanding is how you'd get rid of the type parameter by moving things to InvariantUpdates_H. I'd've thought if you instantiate with a function, it would fill in the type parameter, so you would still need it, but maybe not 'b itself?
There was a problem hiding this comment.
Sorry for the confusion, hopefully the new commit structure and big comment in this PR makes it a bit easier to understand.
This locale is the arch-split interface for the following typ_at_lifts lemmas. The assumptions are the arch-specific typ_at_lift lemmas that hold for all architectures and are needed to prove the generic ones.
Once the locale is interpreted in ArchInvsLemmas_H then we never need to think about it again, like with other arch-split interface locales.
There was a problem hiding this comment.
(the usual name for the kernel ext type would be
z-- any particular reason you didn't pick that one?)
I don't think this is the kernel ext type, the 'kernel' here is a monad?
@Xaphiosis is right, this is the free return type of the monads in the interface lemmas, not the kernel ext type. I fix it so that the generic lemmas in this locale can have the same type and make use of the interface lemmas.
However, it should maybe be 'a. I think I only went with 'b because 'a was already used by something else in the goal when I was first working out what the problem was and how I could solve it.
There was a problem hiding this comment.
What I'm also not understanding is how you'd get rid of the type parameter by moving things to InvariantUpdates_H. I'd've thought if you instantiate with a function, it would fill in the type parameter, so you would still need it, but maybe not
'b itself?
I think your confusion here is due to mixing up this locale with the later one which gets instantiated with a function. In this case, what I was referring to is that instead of introducing this locale as an interface in Invariants_H, we could move the generic lemmas that depend on the arch-specific ones to InvariantUpdates_H, where those arch-specific lemmas could just be requalified.
| \<comment>\<open> We're using @{command ML_goal} here because there are two useful formulations | ||
| of typ_at lifting lemmas and we do not want to write all of the possibilities | ||
| out by hand. If we use typ_at_lift_tcb' as an example, then the first is | ||
| @{term "\<lbrace>\<lambda>s. P (typ_at' TCBT p s)\<rbrace> f \<lbrace>\<lambda>_ s. P (typ_at' TCBT p s)\<rbrace> | ||
| \<Longrightarrow> \<lbrace>\<lambda>s. P (tcb_at' p s)\<rbrace> f \<lbrace>\<lambda>_ s. P (tcb_at' p s)\<rbrace>"} and the second is | ||
| @{term "(\<And>P. \<lbrace>\<lambda>s. P (typ_at' TCBT p s)\<rbrace> f \<lbrace>\<lambda>_ s. P (typ_at' TCBT p s)\<rbrace>) | ||
| \<Longrightarrow> \<lbrace>\<lambda>s. P (tcb_at' p s)\<rbrace> f \<lbrace>\<lambda>_ s. P (tcb_at' p s)\<rbrace>"}. | ||
| The first form is stronger, and therefore preferred for backward reasoning | ||
| using rule. However, since the P in the premise is free in the first form, | ||
| forward unification using the OF attribute produces flex-flex pairs which | ||
| causes problems. The second form avoids the unification issue by demanding | ||
| that there is a P that is free in the lemma supplied to the OF attribute. | ||
| However, it can only be applied if @{term f} preserves both | ||
| @{term "typ_at' TCBT p s"} and @{term "\<not> typ_at' TCBT p s"}. | ||
| The following @{command ML_goal} generates lemmas of the second form based on | ||
| the previously proven stronger lemmas of the first form. \<close> | ||
| ML \<open> | ||
| local | ||
| val strong_thms = @{thms gen_typ_at_lifts_strong[no_vars]}; | ||
| fun abstract_P term = Logic.all (Free ("P", @{typ "bool \<Rightarrow> bool"})) term | ||
| fun abstract thm = | ||
| let | ||
| val prems = List.map abstract_P (Thm.prems_of thm); | ||
| fun imp [] = Thm.concl_of thm | ||
| | imp (p :: pms) = @{const Pure.imp} $ p $ imp pms | ||
| in | ||
| imp prems | ||
| end | ||
| in | ||
| val gen_typ_at_lifts_internal_goals = List.map abstract strong_thms | ||
| end | ||
| \<close> |
There was a problem hiding this comment.
The comment and the code are currently duplicated for the architectures. If we give gen_typ_at_lifts_strong as a parameter, the code as such could be generic in a separate theory file somewhere, together with the long comment, which we could then point to here.
There was a problem hiding this comment.
Yeah, I think I commented the same. Definitely would be good to de-duplicate the comment and tech.
There was a problem hiding this comment.
I've done this now, the comment and ML function are in the generic Invariants_H and pointed at from each ArchInvsLemmas_H file.
| sublocale setObject: typ_at_props' "setObject p v" | ||
| by typ_at_props' |
There was a problem hiding this comment.
after looking at many of these, I'm starting to wonder if it would be worth adding a little ML command that only needs the constant name (or list of names) and does the rest. So that we could write
typ_at_props doMachineOp, setEndpoint
and it figures out parameters etc itself. Not for this PR, but could be a follow-up if we like the idea.
There was a problem hiding this comment.
it would be convenient to use, but then we'd end up with the param_a and param_b that crunch does... then again this is a bit like crunching, so would be worth investigating at some point
There was a problem hiding this comment.
Yeah, while going through all of the files and doing these I definitely had the feeling that a command like that would be useful. @Xaphiosis is right though, it was annoying to have to work out sensible parameters for each function but it does end up with much nicer lemmas than crunch ones with param_a and param_b.
| sublocale cancelIPC: typ_at_props' "cancelIPC tptr" by typ_at_props' | ||
|
|
||
| lemmas finaliseCap_typ_ats[wp] = typ_at_lifts[OF finaliseCap_typ_at'] | ||
| sublocale cancelAllIPC: typ_at_props' "cancelAllIPC epptr" by typ_at_props' |
There was a problem hiding this comment.
uses a different style to the rest. Should we one-line all of them?
There was a problem hiding this comment.
I'd say given how many there are, one-lining if it fits on one line is something I'd support
There was a problem hiding this comment.
A lot of these were being copied across from the rt branch but yeah, I noticed all the different styles. At the time I thought it was better to be consistent with rt to make merges easier but now I'm not sure if we should just pick a style now and deal with the merge the one time.
| lemmas cancelAllIPC_typs[wp] = typ_at_lifts[OF cancelAllIPC_typ_at'] | ||
| lemmas cancelAllSignals_typs[wp] = typ_at_lifts[OF cancelAllSignals_typ_at'] | ||
| lemmas suspend_typs[wp] = typ_at_lifts[OF suspend_typ_at'] | ||
| sublocale cancelIPC: typ_at_props' "cancelIPC tptr" by typ_at_props' |
lsf37
left a comment
There was a problem hiding this comment.
Thanks for doing that. The setup/instantiating is a bit more verbose, but proofs all become simpler. I think this is good. We might try to simplify making instances at some point, but I don't think we need to do that immediately.
One thing we should add is documentation. With the locale and arch split this has become complex enough that it should be explained somewhere in a reasonably central/findable location (what it does, why it exists, how to extend properties, when to do which kind of sublocale).
|
|
||
| private ML_goal typ_at_lifts_internal: | ||
| \<open>typ_at_lifts_internal_goals\<close> | ||
| by (auto simp: typ_at_lifts_strong) |
There was a problem hiding this comment.
I'm a bit lost here. Firstly, I'm wondering why this tech has to be duplicated across all the arches, along with the big comment, etc.
Second, I'm wondering, the deployment here only works once, right, to make the weaker form from the strong? So if someone wants to add more, they have to add both a strong and a weak? How does that work?
There was a problem hiding this comment.
Second, I'm wondering, the deployment here only works once, right, to make the weaker form from the strong? So if someone wants to add more, they have to add both a strong and a weak? How does that work?
Yes, this only works once, to make the weaker form of the specific 'strong' lemmas that were introduced here.
I'm not quite sure what you mean with the second half. If someone has new 'strong' lemmas then they could add them here easily by proving them and then adding them to typ_at_lifts_strong. If they proved them in a later file for whatever reason then they could still add them to the typ_at_props' locale, and construct the weaker version as well if needed.
| context | ||
| begin | ||
|
|
||
| private method typ_at_proof = |
There was a problem hiding this comment.
small comment, or add a docstring?
There was a problem hiding this comment.
(there's no such thing as a truly private method, they seem to leak when you do print_methods)
There was a problem hiding this comment.
This was taken directly from rt. I guess I could try to come up with a comment, I think it's just wrapping up the duplicated proofs for the following typ_ats' lemmas into something that can be used for all of them.
There was a problem hiding this comment.
(there's no such thing as a truly private method, they seem to leak when you do
print_methods)
And yeah, I guess still useful though as an indication that it's not intended for general use.
| apply (simp add: valid_irq_node'_def) | ||
| apply (wp hoare_vcg_all_lift P typ_at_lift_cte') | ||
| apply (wp hoare_vcg_all_lift P typ_at_lift_cte'_strong) | ||
| done |
There was a problem hiding this comment.
why do all these proofs appear so much nicer than the Arch proofs that seem to go via bool_to_bool_cases? am I not comparing the right kinds of proofs?
There was a problem hiding this comment.
The proofs with bool_to_bool_cases are all lemmas I made into 'strong' versions. For these lemmas I was either unable to or didn't think to make 'strong', and the proofs could stay simpler.
| sublocale cteMove: typ_at_props' "cteMove cap src dest" | ||
| by typ_at_props' | ||
|
|
||
| end |
There was a problem hiding this comment.
end tags please. also, consistency, in some files you have empty lines in between, in others they run into each other
Also: while context Arch is cheaper than interpretation Arch ., it's still not free; any chance these could go into an Arch block above?
There was a problem hiding this comment.
Also: while
context Archis cheaper thaninterpretation Arch ., it's still not free; any chance these could go into an Arch block above?
Hmm, I have conflicted opinions here. I agree that moving them into an already existing Arch block would be much nicer, but doing that would almost definitely result in them being duplicated when this is merged into the rt branch.
There was a problem hiding this comment.
Ah, actually in this case I put them here because they need to go after the interpretation of CNodeInv_R. I don't see an easy way around this.
| sublocale receiveIPC: typ_at_props' "receiveIPC t cap b" | ||
| by typ_at_props' | ||
| sublocale receiveSignal: typ_at_props' "receiveSignal t cap b" | ||
| by typ_at_props' |
There was a problem hiding this comment.
out of curiosity, how fast does a block like this run?
(also this is an example of no empty lines between)
clarification question: with sublocale in Arch here, you're saying that you only want the lift rules to be visible in Arch? that doesn't feel right for all of these
There was a problem hiding this comment.
out of curiosity, how fast does a block like this run? (also this is an example of no empty lines between)
These interpretations and sublocales are practically instant, they're below the threshold of my timing panel.
clarification question: with sublocale in Arch here, you're saying that you only want the lift rules to be visible in Arch? that doesn't feel right for all of these
This is the larger locale that contains both generic and arch-specific lifted rules, and so can only be visible from Arch. There is normally an equivalent generic interpretation that contains only the generic rules and is visible globally. This approach follows my understanding of how typ_at_lifts was previously arch-split and handled.
| (simp: crunch_simps) | ||
|
|
||
| lemmas setPriority_typ_ats [wp] = typ_at_lifts [OF setPriority_typ_at'] | ||
| end |
There was a problem hiding this comment.
another reminder to incorporate end tags into repertoire
|
|
||
| lemmas invokeIRQControl_typ_ats[wp] = | ||
| typ_at_lifts [OF performIRQControl_typ_at'] | ||
| end |
There was a problem hiding this comment.
This is why end tags are important, in the diff I have no idea what context the next sublocale commands are in.
There was a problem hiding this comment.
This is in a file that hasn't been arch-split yet, so the context being ended is an anonymous one where we do context begin interpretation Arch. I'm not sure what end tag would be appropriate for that.
Once it is arch-split the context will almost definitely no longer be there, and these sublocale commands will be able to be replaced with global interpretations.
| sublocale Arch < sendIPC: typ_at_props' "sendIPC bl call bdg cg cgr t' ep" | ||
| by typ_at_props' | ||
| sublocale Arch < handleFault: typ_at_props' "handleFault t ex" | ||
| by typ_at_props' |
There was a problem hiding this comment.
Looking at this, and the fact this will probably hit before I get to Syscall arch-split (and maybe some others, I dunno), how does one go about arch-splitting these?
Also, sublocale Arch is something I try to avoid because it is slow. A whole block of them feels like it will be very slow. Can you let me know how long this runs for? Will the sublocale Arch go away as part of arch-splitting? This is new to me.
There was a problem hiding this comment.
When these later files get arch-split my expectation is that in the generic file these cases will be replaced with a global_interpretation of the gen_typ_at_props' locale. We would then make the larger typ_at_props' a sublocale of Arch in the arch files. Again, I think this is basically the same as what would have been needed to arch-split the previous typ_at_lifts lemmas commands. I've also tried to mark each case of these with a FIXME: arch-split which will hopefully help.
The current sublocale Arch commands are a bit slow, but once these files are arch-split then the equivalents will almost definitely already be in Arch and so could just look like sublocale handleFault: typ_at_props' "handleFault t ex", which is quick.
There was a problem hiding this comment.
When I rebase this PR I'm also going to have to go through this exact process for Tcb_R, so that will be a good test case to confirm that it makes sense.
There was a problem hiding this comment.
Having now rebased and done this for Tcb_R, I can confirm that the above process is correct and is relatively straightforward.
One note for the future though, I impressively already forgot about the locale type parameter and it meaning that interpreting gen_typ_at_props' needs a _, which led to a very confusing failure. I'm not sure what to do about this, beyond adding a comment to the definition of gen_typ_at_props' for anyone who clicks through to there.
There was a problem hiding this comment.
A comment at whatever place you get to when you click though would be fairly helpful, I think. The other discovery mechanism would be grep, so it would be good if it mentioned gen_typ_at_props' somewhere.
| for typ_at'[wp]: "\<lambda>s. P (typ_at' T p s)" | ||
|
|
||
| lemmas threadSet_typ_at_lifts[wp] = gen_typ_at_lifts[OF threadSet_typ_at'] | ||
| global_interpretation threadSet: gen_typ_at_props' _ "threadSet tptr f" |
There was a problem hiding this comment.
Yeah, this is definitely confusing to see without the context of this particular PR.
See previous comments about whether we are sure we need the itself parameter. Maybe you should walk us through it... some things appear unintuitive, but have no alternative.
|
Thank you for the reviews and sorry for the delayed response, the comments led me to think of an improved way to structure and describe these changes. In particular, I've changed the commits to better reflect that there are two relatively separate changes going on here, both based on changes that have been made in the rt branch. The first is improving and arch-splitting the typ_at_lift lemmas themselves. This involved doing a better job of centralising all of the relevant lemmas in one location, along with making some of the lemmas into 'strong' versions, which hold for any The second half of the changes is the addition and arch-split of the The way this locale has been arch-split follows how the |
bb2be3f to
5faf329
Compare
|
This is now ready for re-review. I think I've resolved all suggestions that were made in both our online and offline discussions. Once we're happy with this state of it I'll squash, rebase, and update the remaining files that have since been arch-split. |
| assumptions. The following thm statements should fail if this is not true. *) | ||
| assumptions. The following thm statement should fail if this is not true. *) | ||
| private lemmas check_valid_internal = iffD1[OF refl, where P="valid p g q" for p g q] | ||
| thm typ_ats[atomized, THEN check_valid_internal] |
There was a problem hiding this comment.
I tried turning this thm into a lemmas _ = ... but it pollutes the namespace and led to confusing find_theorems results, so I changed it back to thm.
There was a problem hiding this comment.
Ah, thanks for trying it out anyway.
Proof failures are expected in the current state, CRefine won't work until that rebase happens. |
| locale Invariants_H_typ_at_lifts = Invariants_H_cte_ats + | ||
| (* Use f_rvt_itself parameter to fix free type variable in interface lemmas. | ||
| This is the loosest constraint that we have come up with to make this locale work, and is | ||
| able to be used here because nothing within the locale looks at f. *) |
There was a problem hiding this comment.
shouldn't this be indented to the same level as fixes below?
There was a problem hiding this comment.
do we care to say that rvt is the return type of f?
There was a problem hiding this comment.
Both good points, indenting it like that would make it extra clear what the comment is referring to and it's always nice to have a hint about what abbreviations are intended to be short for.
| apply (prop_tac "\<forall>tcb'. valid_tcb' tcb s \<longrightarrow> valid_tcb' tcb s'") | ||
| apply clarsimp | ||
| apply (erule (1) use_valid[OF _ setObject_valid_tcb']) | ||
| apply (erule (1) use_valid[OF _ setObject.gen_typ_ats(18)]) |
There was a problem hiding this comment.
hmm. the (18) here and (14) in KHeap_R doesn't feel like an improvement, and doesn't indicate any longer that we want the tcb version. Either having a lemmas to bind it, or a comment to indicate which one it is in case the number changes (e.g. for port to MCS)
There was a problem hiding this comment.
+1 from me on that, these numbers shifting can be pretty hard to debug. It's fine if it's in some sledgehammer result that can be found automatically again, but otherwise if we can we should avoid them or guard them.
There was a problem hiding this comment.
Yeah, I was a bit hesitant to change to these numbers but also didn't like the ad-hoc lemmas being added for random lemmas out of the typ_ats set. There's a bit of a conflict here, with these proofs wanting to use the rules manually while the typ_ats are more constructed to be used automatically from wp. I didn't really want to try and rework these proofs now though.
I'll have a think to see if I can find a more systematic way of handling these.
There was a problem hiding this comment.
Ok, I have vague ideas for something nicer but that I think would be too much work for not enough benefit, so instead I've given these specific typ_at_lift lemmas actual names to start with and changed this line to
apply (erule (1) use_valid[OF _ valid_tcb'_typ_at_lift[OF setObject_typ_at']])
Not perfect but much more maintainable.
There was a problem hiding this comment.
Yes, that looks much better to me, thank you!
| hyp_refs_of_live' | ||
|
|
||
| (* transfer facts from partial locale (with extra assumptions) into complete locale | ||
| (since we can now satisfy these assumptions) *) |
There was a problem hiding this comment.
this is true in a bit of a i = i + 1; // add 1 to i kind of way, but what were we missing to satisfy these assumptions? Arch proofs? something else? would be good to say that
There was a problem hiding this comment.
Does this help and sound accurate?
(* transfer facts from partial locale (with extra assumptions) into complete locale
(since we can satisfy these assumptions now that the Invariants_H_typ_at_lifts interface has
been interpreted) *)
There was a problem hiding this comment.
I'm still a bit lost, I admit. Let me try again: I understand that we now have something from the interpretation of Invariants_H_typ_at_lifts, which allows us to satisfy gen_typ_at_props'_interface, but is there any coherent name that encompasses what that is that isn't just "assumptions"?
I was thinking it would be something like "After interpretation of Invariants_H_typ_at_lifts, The arch-specific assumptions of gen_typ_at_props'_interface are now satisfiable, meaning the typ_at properties can now be placed in a complete locale with no further type assumption" ... is that close to the truth? Does something like that sound better?
There was a problem hiding this comment.
I think our use of the word assumptions when we wrote this comment is making this seem more complicated than it actually is. I can't think of how to express this with the right terminology, but in my mind what we're working around is that Invariants_H_typ_at_lifts has a fixes that gen_typ_at_props'_interface has to inherit. Then, once Invariants_H_typ_at_lifts has been interpreted, we can resolve that fixes by moving everything into gen_typ_at_props'.
There was a problem hiding this comment.
Oh, that sounds informative! What if the comment was something like:
"Invariants_H_typ_at_lifts has a fixes that gen_typ_at_props'_interface had to inherit. Now that Invariants_H_typ_at_lifts has been instantiated, we can drop that fixes assumption by moving everything into gen_typ_at_props'."
This explains a lot. I think previously you were kind of explaining more what sublocale does than what we were trying to do.
There was a problem hiding this comment.
Thanks, that reads well to me. I think between the comment here and the comments in Invariants_H where these locales are defined there's now enough for future us to work out what's going on here.
| fixes f :: "'b kernel" | ||
| assumes typ': "f \<lbrace>\<lambda>s. P (typ_at' T p' s)\<rbrace>" | ||
| (* Will be a sublocale of gen_typ_at_props' once Invariants_H_typ_at_lifts is interpreted. | ||
| Done this way to avoid b_itself parameter.*) |
There was a problem hiding this comment.
again, would be good to know what is missing here. the mention of b_itself might not be clear to someone not looking at the diff where 'b kernel is mentioned; are we talking about the kernel ext type? if so, then that's worth mentioning
There was a problem hiding this comment.
Whoops, thanks for spotting, I thought I had removed all references to b. This should be f_rvt_itself.
Xaphiosis
left a comment
There was a problem hiding this comment.
I'm very happy with the removal of the gen_typ_at_props' dummy parameter!
My remaining comments are related to increased clarity of comments for future historians.
lsf37
left a comment
There was a problem hiding this comment.
Also very happy with the changes, I don't have anything beyond Raf's comments.
|
|
||
| (* Will be a sublocale of gen_typ_at_props' once Invariants_H_typ_at_lifts is interpreted. | ||
| Done this way to avoid b_itself parameter.*) | ||
| Done this way to avoid f_rvt_itself parameter.*) |
There was a problem hiding this comment.
maybe add so it's "avoid f_rvt_itself parameter in final locale"?
|
Squashed, rebased and new arch-split files updated. Small bits of new content in Syscall_R and Untyped_R. |
|
Looks good and ready to merge from my side. |
Signed-off-by: Corey Lewis <corey.lewis@proofcraft.systems>
These changes are backported from the rt branch. typ_at_lifts has additional lemmas added to it and others are strengthened to also handle the negated versions. Signed-off-by: Corey Lewis <corey.lewis@proofcraft.systems>
Signed-off-by: Corey Lewis <corey.lewis@proofcraft.systems>
Signed-off-by: Corey Lewis <corey.lewis@proofcraft.systems>
Based on changes made in the rt branch. The typ_at_props' locale is for things like typ_at_lifts but since you can interpret it, you also get all lifting rules that might be added later down the track. Signed-off-by: Corey Lewis <corey.lewis@proofcraft.systems>
Updates the proofs to interpret the locales instead of manually instantiating typ_at_lifts with a lemmas command. Signed-off-by: Corey Lewis <corey.lewis@proofcraft.systems>
Signed-off-by: Corey Lewis <corey.lewis@proofcraft.systems>
These changes are based on ones that were previously made in the
rtbranch. Some additional cleanup was done along the way and thetyp_at_props'locale was arch-split and applied to all architectures.The main benefit for master is the improved
typ_at_liftslemmas; thetyp_at_props'locales themselves are not as immediately useful as inrt. However, backporting them does make the two branches more similar and should ease future merges.See the following commits for where some of these changes originally happened in the
rtbranch:6710b9a
64b6edf
79e2e2b
91a2023
78bb847
8a01dd4
336bd0b