-
Notifications
You must be signed in to change notification settings - Fork 260
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
feat: Various small improvements to Python code generation #2081
Conversation
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.
Still thinking through the changes necessary to support let expressions, but in the meantime here are a couple of comments.
Source/DafnyRuntime/DafnyRuntime.py
Outdated
@property | ||
def Elements(self): | ||
return self | ||
|
||
@property | ||
def UniqueElements(self): | ||
return Seq(set(self)) |
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 could just be set(self)
couldn't it? It just has to be something compatible with whatever CreateForeachLoop
emits (i.e. anything iterable).
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 really matter here, but I think it's the type dafny assumes.
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.
UniqueElements
is just something that needs to be called in the target language, it doesn't have to produce a "Dafny value" at this level of abstraction. Just set(self)
will work because it will only be used to compile something like this:
var mySet := set x | x in mySeq
To something like this in Python:
mySet = _dafny.Set()
for x in mySeq.UniqueElements: // <- produced by PythonCompiler.CreateForEachLoop
mySet.add(x)
What you've got is correct too, since _dafny.Seq
is also iterable, I'm just trying to save us an extra object creation. :)
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 will undoubtedly work for python(see it doesn’t matter here) and given that this is only used immediately in comprehensions, like you described, it doesn’t matter in general. That being said, I do like the cleaner interface of returning a sequence, but your overhead argument is compelling, so I’ll adopt it.
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.
Thanks! It's purely an optimization, and normally I wouldn't prioritize it at this stage, but this is a really easy one. :)
@@ -158,3 +179,12 @@ def euclidian_modulus(a, b): | |||
@dataclass | |||
class HaltException(Exception): | |||
message: str | |||
|
|||
def quantifier(vals, frall, pred): |
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.
frall
- intentional to avoid name conflict or typo? :)
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's what Java, C#, and JS call it, but I don't deeply care.
@@ -39,10 +39,31 @@ def _tail_call(): | |||
raise TailCall() | |||
|
|||
class Seq(list): | |||
def __init__(self, __iterable = None, isStr = False): |
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 testing coverage for this is implicitly in Hello.dfy
, I assume, which only worked before because we were just emitting a base Python string?
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.
Yes, we weren't doing anything with the strings other than passing them around, so it was fine.
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.
For the record this version is definitely incomplete, since any value of type seq<char>
is a string according to Dafny, even if it isn't a literal. Here's a test case we should add for the next step:
method Main() {
var manualString := ['H', 'e', 'l', 'l', 'o'];
print manualString; // Still prints "Hello" and not "['H', 'e', 'l', 'l', 'o']"
}
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.
Good point, I'll try to add it in this one.
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.
Nah, let's leave it for the next step. We'll need a more general implementation of a type descriptor anyway (for dynamic type checks like is
), better to do that properly in a separate PR.
if (su != Substituter.EMPTY && TargetLambdasRestrictedToExpressions) { | ||
wStmts = wr.Fork(); | ||
wr = EmitReturnExpr(wr); | ||
} |
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.
Just noting for the record that as I'm better appreciating our solution so far for TargetLambdasRestrictedToExpressions
, I definitely see more speed bumps down the road for edge cases we don't handle correctly, because we're not doing this "post hoc clean up" for every possible method call that might need it. I won't likely see an immediate alternative and don't want to block this proven progress, but I do want to revisit before we go too much 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.
Yes, those changes are unlikely to be comprehensive, but I was hesitant to introduce additional untested changes.
protected override string True { get => "True"; } | ||
protected override string False { get => "False"; } |
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.
🚀
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.
Do compilers do April fools' day?
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.
Oh if we're going to do that, we should do it in the verifier instead. :)
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.
Approved on the condition that the next PR adds a beefy comment on TargetLambdasRestrictedToExpressions
about how we're using wStmts
and why we have to conditionally add return statements in the SinglePassCompiler
superclass. :)
By submitting this pull request, I confirm that my contribution is made under the terms of the MIT license.