dart-lang / dart-lang/language

Allow subtype constraint generation to strip null off of `Null`, following a similar rule for `dynamic` and `void`

Open
#3,797 0 comments 2 reactions 0 assignees View on GitHub
small-feature
Dominant language
TeX
Stars
2.9k
Forks
239
Avg merge
2d 18h
Merged PRs (30d)
14

Description

This is a proposal in response to the request raised in https://github.com/dart-lang/language/issues/3796. The difficulty which is reported in said issue is that the following program is rejected:

```dart
void main() {
final w1 = W(D());
final w2 = W(E());
final w3 = W(null); // Compile-time error, "Couldn't infer type parameter 'T'".
}

abstract class C> {}
class D extends C {}
class E extends C {}

class W> {
const W(this.obj);
final T? obj;
}
```

We would probably be able to infer the type argument as `Never` by adding one case to one of [the rules](https://github.com/dart-lang/language/blob/main/resources/type-system/inference.md#rules) about subtype constraint generation:

> - If `Q` is `Q0?` the match holds under constraint set `C`:
> - If `P` is `P0?` and `P0` is a subtype match for `Q0` under constraint set `C`.
> - Or if `P` is `dynamic` or `void` and `Object` is a subtype match for `Q0` under constraint set `C`.
> - Or if `P` is `Null` and `Never` is a subtype match for `Q0` under constraint set `C`.    **<--- Add this new case**
> - Or if `P` is a subtype match for `Q0` under **non-empty** constraint set `C`.
> - Or if `P` is a subtype match for `Null` under constraint set `C`.
> - Or if `P` is a subtype match for `Q0` under **empty** constraint set `C`.

This could be a useful behavior, also in practice, in spite of the fact that it introduces the type `Never`. Considering the given example, it does make sense to have an instance of `W` (which will be usable as a `W` for _any_ `T`), in particular because its `obj` is allowed to be "absent" by having type `T?`.

Intuitively, this rule will "strip the null off of `Null`", yielding `Never`, just like the previous rule allows us to strip the null off of `dynamic` and `void`, yielding `Object`.

Contributor guide

Open the contributing guide

Research direction

Start with the subtype constraint generation rules in resources/type-system/inference.md and compare the existing handling of dynamic and void with the proposed Null case. Check the sample W, C, D, and E program against the inference behavior; done means the proposal is resolved and the intended inference of W is specified or accepted.

Written by the indexing model from the issue text.

Assessment

Tech stack
dart
Domain
compilers
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.