-
Notifications
You must be signed in to change notification settings - Fork 1
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
(interpreter) Detect reassignment from incoercible values #188
(interpreter) Detect reassignment from incoercible values #188
Conversation
var output = EvalReturningOutputString(source); | ||
|
||
Assert.Equal("nil", output); | ||
} |
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.
Other use cases are more tricky. For example, should we or should we not allow
nil
assignment by default for reference types? We'll try to decide on this before merging this PR.
In other words, this. ☝️ We need to figure out whether this is what we want or not. Having it like this is the easiest way out, but it should actually be quite simple to forbid all nil
assignments also if we like. We could actually give it a try and see how many tests it breaks. 💡
It's probably much easier to forbid nil
assignment at this early stage in the Perlang development than trying to get rid of it after-the-fact, which experience from other languages has proven to be quite hard (not to say impossible). (Well, C# has made it possible to default to non-nullability by default which is quite an achievement.)
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 following is now in place:
- Reassignments of variables to
nil
emits a warning. - Using
nil
as a variable initializer likewise emits a warning - Bug fix: Using
nil
for local variable inference (var s = nil
) is now properly detected as an invalid condition, causing a compilation error. There is simply no way for the compiler to determine what type the user was intending to use in that case, so it's better to just fail fast. - Passing
nil
as a function parameter also emits a warning.
The PR got a bit more complex because of this. I'll try to extract the infrastructure for emitting warnings into a separate PR in a day or two, since it's an isolated piece of art that doesn't necessarily need to be glued together with the rest like this.
One big caveat at the moment is also the following semantic detail:
- In REPL mode, warnings are treated as warnings and just produce some noise; the code will still run as if the warning wasn't there.
- In script mode, warnings are treated as errors (imagine
-Werror
being enabled withgcc
) and there is no way to turn it off. The latter might be a bit unpleasant and we could try to fix a-Wno-error
-flag or something when we have the infra for warning extracted to an isolated PR.
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.
One big caveat at the moment is also the following semantic detail:
- In REPL mode, warnings are treated as warnings and just produce some noise; the code will still run as if the warning wasn't there.
- In script mode, warnings are treated as errors (imagine
-Werror
being enabled withgcc
) and there is no way to turn it off. The latter might be a bit unpleasant and we could try to fix a-Wno-error
-flag or something when we have the infra for warning extracted to an isolated PR.
This was now fixed. I added a -Wno-error=nil-usage
flag that you can use to demote usage of nil
to just a warning instead of an error.
The REPL still always treats it as a warning which makes sense in my world view of how a REPL should "feel" to the user.
One caveat still: the EvalHelper
methods will consider all warnings warnings by default, not errors. We could change this (and perhaps we should) but it does berak about 5 unit tests. Some of them could easily be fixed but not others. We would probably have to figure out a way to disable/enable warnings for individual tests to accomplish that (perhaps by moving them to be Program
integration tests and passing in the proper -Wno-error
flag). But, that's a different story for another day.
I'll try to extract the infrastructure for emitting warnings into a separate PR in a day or two, since it's an isolated piece of art that doesn't necessarily need to be glued together with the rest like this.
This part I'll try to deal with before we get this merged though.
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.
fff1220
to
eb43349
Compare
54c29ad
to
4e19384
Compare
This is an extract of most of the infrastructure code from #188, to make that PR clearer and more focused on the actual semantic changes.
5e81fd1
to
ed3d19b
Compare
@@ -85,14 +85,32 @@ public static int MainWithCustomConsole(string[] args, IConsole console) | |||
var detailedVersionOption = new Option("-V", "Show detailed version information"); | |||
var evalOption = new Option<string>("-e", "Executes a single-line script") { AllowMultipleArgumentsPerToken = false, ArgumentHelpName = "script" }; | |||
var printOption = new Option<string>("-p", "Parse a single-line script and output a human-readable version of the AST") { ArgumentHelpName = "script" }; | |||
var noWarnAsErrorOption = new Option<string>("-Wno-error", "Treats specified warning as a warning instead of an error.") { ArgumentHelpName = "error" }; | |||
|
|||
var disabledWarningsAsErrorsList = new List<WarningType>(); |
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.
(Silly List
suffix to avoid name clash with non-static field. It's a shame the C# compiler uses the same scope for these, since a static method cannot access the fields anyway. Let's try to do better in Perlang when we implement support for static
methods. 😎)
|
||
if (expr.Value.TypeReference.IsNullObject) | ||
{ | ||
// TODO: Use expr.Value.Token here instead of expr.name, #189 |
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.
@@ -379,6 +384,11 @@ public override VoidObject VisitVarStmt(Stmt.Var stmt) | |||
$"Cannot assign {stmt.Initializer.TypeReference.ClrType.Name} value to {stmt.TypeReference.ClrType.Name}" | |||
)); | |||
} | |||
else if (stmt.Initializer.TypeReference.IsNullObject) | |||
{ | |||
// TODO: Use stmt.Initializer.Token here instead of stmt.name, #189 |
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.
69c6e30
to
159dfa2
Compare
A typical example of an incoercible assignment is this: var i = 1; i = "foo"; ...in other words, an integer value being reassigned a `string` value. Other use cases are more tricky. For example, should we or should we not allow `nil` assignment by default for reference types? We'll try to decide on this before merging this PR.
159dfa2
to
588a089
Compare
A typical example of an incoercible assignment is this:
...in other words, an integer value being reassigned a
string
value.Other use cases are more tricky. For example, should we or should we not allowWe settled on emitting a warning onnil
assignment by default for reference types? We'll try to decide on this before merging this PR.nil
assignment, which is considered an error by default but can be demoted to a warning if necessary.