Supporting dyn soundly #1047
Replies: 4 comments 3 replies
-
I think there is a sound refinement of this that is useful: with a
the axiom for
where the precondition
One way to think about this is to (conceptually) split the dictionary into two dictionaries, a |
Beta Was this translation helpful? Give feedback.
-
One additional consideration is that in Rust, for an object-safe
Here, the code is able to call
With these, code can still use In addition, we have to make sure that
For this, I propose making the SMT encoding of trait bounds slightly more aware of (As an alternative, we might consider having the syntax macro add |
Beta Was this translation helpful? Give feedback.
-
@tjhance: consider "call credits", for higher order recursive functions. Also consider termination credits. |
Beta Was this translation helpful? Give feedback.
-
@Chris-Hawblitzel: we have a sound design for |
Beta Was this translation helpful? Give feedback.
-
We've been discussing
dyn
for Verus recently, and I wanted to write down some notes aboutdyn
's soundness when used in specifications and proofs. I thinkdyn
should be sound, but there's at least one thing we have to be careful about: operations ondyn
should be consideredexec
orproof
mode operations, notspec
mode operations. Otherwise, there would be a danger of fabricating fake implementations of impossible trait bounds (this would be similar to Dafny issue dafny-lang/dafny#851 ). I believe this should be a straightforward restriction that fits in naturally with Verus's mode system.To see the potential issue in more detail, consider our model encoding of traits as dictionary datatypes, where we model a trait like this:
with a dictionary datatype like this:
In this model, a bound
A: T
on typeA
:is treated like a dictionary parameter:
It's important that program cannot fabricate dictionaries, because not all dictionary types can be implemented. For example, if a trait has a method
proof fn bad() ensures false;
, then no dictionary value can implement this method, and if we accidentally assume a dictionary implementing this method, the program could callbad
and prove false. So in Verus mode terminology, we have to treat dictionaries as having modeproof
/tracked
, not modespec
/ghost
, since Verus allows fabrication of values for modespec
/ghost
but prohibits fabrication for modeproof
/tracked
:This matters for
dyn
, because the typedyn T
is essentially an existential type or dependent product type that contains a typeSelf
, a dictionaryDictionary_T<Self>
, and a value of typeSelf
:Here, it's important that we treat the bound
Dictionary_T<Self>
asproof
/tracked
, not asspec
/ghost
. This means that aDyn_T
value is only useful if it has modeexec
orproof
/tracked
. If the program created aspec
/ghost
Dyn_T
value, we would have to assume that it had been fabricated (e.g. usingarbitrary()
) and we should not allow its dictionary to be used to instantiate boundsA: T
. Therefore, the mode system should insist that any operations (in particular, method invocations) on adyn T
value require thedyn T
value to have modeexec
orproof/tracked
. This should be required even forspec
methods onT
, since we intend to support ensures clauses onspec
methods and we already support polymorphic broadcast lemmas (with trait bounds) triggered byspec
functions.(We could consider an exception for traits that consist entirely of spec methods and have no ensures clauses; I haven't thought much about this and I don't know if it would be useful. A more general exception would be if the program could prove the trait dictionary was an inhabited type, though again, I don't know if this is actually useful.)
Beta Was this translation helpful? Give feedback.
All reactions