dart-lang / sdk

The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.
https://dart.dev
BSD 3-Clause "New" or "Revised" License
10.25k stars 1.58k forks source link

Analyzer: `Null` is considered to have too many members #36113

Closed eernstg closed 5 years ago

eernstg commented 5 years ago

Consider the following program:

main() {
  Null n = null;
  n.bitLength;
  n.isEven;
  n.isOdd;
  n.sign;
  n.isFinite;
  n.isInfinite;
  n.isNaN;
  n.isNegative;
  n & 42;
  n << 2;
  n >> 2;
  n ^ 2;
  -n;
  n | 3;
  ~n;
  n % 3;
  n * 3;
  n + 3;
  n - 3;
  n / 3;
  n < 0;
  n <= 0;
  n > 0;
  n >= 0;
  n ~/ 3;
}

With dartanalyzer version 1a88421d39f676572e55c3fc2bfb40c6bd4c4a33, this program gives 'No issues', even though the interface of Null does not contain any of the members in use.

It is rather surprising that Null would have some int methods, but not all of them. By the way, I went through int when I noted that isEven was considered to exist on a receiver of type Null, but abs() and many others are correctly rejected. It could be because abs() is inherited from num and isEven is declared afresh in int, so it might be worthwhile to check all String-only methods (like substring, endsWith, etc), and similarly for other built-in types.

In any case, with a receiver of type Null it is a compile-time error to access a member unless it is declared by Object, so all lines in main starting from n.bitLength should be reported as such.

lrhn commented 5 years ago

Likely a left-over from when the specification said that the static type of null was the bottom type (which itself was a left-over from before Null was a visible type).

This has been changed in the specification for a while now, the static type of null is Null.

leafpetersen commented 5 years ago

This is a dup of https://github.com/dart-lang/sdk/issues/27273

eernstg commented 5 years ago

It is actually not exactly the same issue as #27273. In particular, we get an error from the analyzer with the following program for n.foo(), but not for null.foo() (dartanalyzer from 12d789fa52035017915d84bedf6869629d078e11):

main() {
  Null n = null;
  n.foo(); // Error.
  null.foo(); // OK.
}

Similarly, I verified that we do get errors for methods on double (which are inherited from num), but not for the int methods that I listed. So, as I mentioned, if we add n.abs() to the original example we'll get an error for that.

So there's something special about the receiver type Null as opposed to the receiver null, and there is something special about int methods that aren't inherited from num.

I think this implies that the changes needed to fix #27273 and the changes needed to fix this issue are distinct, so I'll reopen this issue.

leafpetersen commented 5 years ago

This seems to be fixed.