Open lexaknyazev opened 2 years ago
As I understand it, the analyzer is sadly correct.
The type of min
is T Function<T extends num>(T, T)
.
The static typeof int.operator+
is num Function(num)
, with some special-cased rules for detecting that adding two integers gives an integer, and adding a double to anything gives a double. With no given context type, and no double values, those rules should not apply here.
That means that, final s = 1 + min(1, 0);
calls min(1, 0)
with a context type of num
, which means that T
gets instantiated to num
.
Then 1 + numValue
has type num
, and s
get the static type num
. Which is not assignable to int
.
Am I missing something? @stereotype441
Couple more observations.
Switching the order of operands fixes the issue:
import 'dart:math';
void main() {
final s = min(1, 0) + 1;
print(List.filled(s, 0));
}
Switching the order should fix the problem. The first operand of +
is the receiver of the operator+
method call, and as such it gets no context type. Without a context type, type inference infers int
as the type argument to min(1, 0)
from the arguments.
(With a context type, it always uses the context type as type argument.)
So, it's only the VM which fails to detect the type error. That's curious, since it should be using the same shared front-end as dart2js, which is what is used in DartPad.
@lrhn
Am I missing something? @stereotype441
Yup, that analysis sounds correct to me.
So, it's only the VM which fails to detect the type error. That's curious, since it should be using the same shared front-end as dart2js, which is what is used in DartPad.
Yeah, that seemed curious to me too. I just tried reproducing the bug with version 2.16.0-134.5.beta (the version where the problem was reported), and for me, the VM gives me this error:
../../tmp/proj/test.dart:5:21: Error: The argument type 'num' can't be assigned to the parameter type 'int'.
print(List.filled(s, 0));
^
Found the reason of the VM's behavior. The file was in a folder with >=2.11.99
SDK config.
The issue could be reproduced on a standalone file by adding // @dart=2.9
to it.
Found the reason of the VM's behavior. The file was in a folder with
>=2.11.99
SDK config.The issue could be reproduced on a standalone file by adding
// @dart=2.9
to it.
Ah, ok. That makes sense. Dart version 2.9 was prior to the introduction of null safety. Back then, an expression of type num
was permitted to be assigned to a variable of type int
, and the type would be checked at runtime, in a manner similar to an as
expression. So when you compile with // @dart=2.9
, it's behaving as though you did this:
import 'dart:math';
void main() {
final s = 1 + min(1, 0);
print(List.filled(s as int, 0));
}
We removed this behavior when we introduced null safety for two reasons: 1. it was responsible for hiding a lot of bugs, and 2. these sorts of implicit type checks would have hidden the need for a lot of null checks (making the null safety feature a lot less valuable). I think it was a good change overall, but yeah, it does have the negative consequence of causing nuisance errors in situations like this one, where a runtime type check would have worked.
Thanks for the explanation.
The simplest way of bypassing the issue seems to be providing an explicit type argument for min
like this:
import 'dart:math';
void main() {
final s = 1 + min<int>(1, 0);
print(List.filled(s, 0));
}
It works but, arguably, min<int>(1, 0)
looks a bit too verbose. Maybe the analyzer or the linter could flag the +
and similar operators when they convert their otherwise int
operands to num
.
This code runs fine but the analyzer gives: