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
CFE missing compile time error: const keys/switch cases should not implement == #32557
Comments
While it's clear why an arbitrary class implementing |
With -dev.59, the Dart Analyzer produces these errors: Analyzing /usr/local/google/home/dgrove/tmp/dart2stable/32557.dart... |
@askeksa-google - I believe this issue doesn't require constant evaluation, but only requires checking the type of the keys in a const map literal context. |
The Dart VM does not produce any error on the above test. |
after some discussion at our dart2js meeting - I recognize that some const evaluation is needed, as a ternary expression yielding an Object as a LUB type would hide the issue. |
Also if the switch case expression is a reference to a constant of static type dynamic, like |
Since the requirement is for the class to not override Conditions in constant expressions need to be completely evaluated to const x = Bool.fromEnvironment("yadda") ? 1 : [1];
const m = {x: 42}; This program compiles and runs with |
There is code in the wild that 'overrides' This is used as a mechanism for suppressing warnings when We we don't want to break this kind of code, care needs to be taken to allow constants that implement One example of this pattern is Protobuf enums: https://github.com/dart-lang/protobuf/blob/master/lib/src/protobuf/protobuf_enum.dart#L51 |
Abstract method declarations are not relevant to this - the requirement is that the class does not have an implementation of The spec for switch says:
For constant map literals, the key expressions must be
(The switch one needs to be tweaked to match the map one, so that any expression evaluating to a constant symbol created by a symbol literal or a constant invocation of The spec is woefully silent on the classes used to implement literals (values not created by calling a constructor). For the record, the intended semantics wrt. this for constant literal values are:
(We make no guarantees that map and list literals are all instances of the same class, though, which matters for switch. It's an annoying restriction). |
Circling back to the original bug:
In dart2js types are not canonicalized, so our TypeImpl implements Because all other tools do allow Type in switch cases, the dart2js-team is inclined to omit the error in the case of TypeImpl. Instead we'll treat this as a bug: types should be canonicalized in dart2js. We have plans to fix that, but until we do, we will need a way to suppress the error when the CFE implements it. |
The issue with using type literals in switch cases is that you cannot use main() {
var type = (<T>() => (<X>() => X)<List<T>>())<dynamic>(); // generates List<dynamic> dynamically.
print(type == List ? "List<dynamic>" : "Not List<dynamic>");
switch (type) {
case List: print("List<dynamic>"); break;
default: print("Not List<dynamic>");
}
print(const {List: "List<dynamic>"}[type] ?? "Not List<dynamic>");
} If you run this code in dartpad (some version of dart2js), it runs and prints:
That's unlikely to be what the user intends. We explicitly did not want types to be canonicalized since there can be arbitrarily many different type objects in a program's life-time. Canonicalization would require you to remember those, which is a memory leak waiting to happen. |
@lrhn are you suggesting that switches on Type should always be a compile-time error? Or that switch statements should use |
Also mention it in the `external const factory Symbol` constructor. This only relevant for constant expressions that may be used as switch case expressions or constant map keys. See #32557. Bug: http://dartbug.com/32557 Change-Id: Ie82799f3f0d39c21c10765338a7dfeb74a582add Reviewed-on: https://dart-review.googlesource.com/c/81242 Commit-Queue: Lasse R.H. Nielsen <lrn@google.com> Reviewed-by: Leaf Petersen <leafp@google.com> Reviewed-by: Erik Ernst <eernst@google.com>
Discussions are ongoing, it might be allowed. But the current specification prevents case clauses from using objects with a concrete PS: Switch statements are already specified to use |
This should be fixed by |
Yeah, the |
This depends on CFE constant evaluation and doesn't block it (constant evaluation). |
Some updates:
@johnniwinther can you confirm that the CFE checks are complete? |
These checks have all been implemented. |
The spec doesn't allow const values that implement
==
to be used as keys in const maps, or as cases on switch statements.The CFE is currently not producing a compile-time error for it.
Here is an example:
Then:
I wanted to file a bug for this issue because it accidentally hides a problem in dart2js, that
Type
cannot be used in these const contexts (see #17207), the sooner we handle this, the lower the chance we'll make a breaking change later on.The text was updated successfully, but these errors were encountered: