dart-lang / dart-lang/language

Consider keeping supertype in joins

Open
#2,856 11 comments 1 reaction 0 assignees View on GitHub
flow-analysis
Dominant language
TeX
Stars
2.9k
Forks
239
Avg merge
2d 18h
Merged PRs (30d)
14

Description

Currently, when flow analysis joins promotion chains in two control flow paths, it keeps only types that are common to both paths. So, for instance, if the declared type of `x` is `Object?`, and one control flow path promotes it to `Object`, then to `num`, then to `int`, whereas the other control flow path promotes it to `num?`, then to `num`, then to `double`, the only promotion that is kept is the promotion to `num`, because it is the only promotion that's common to both promotion chains.

When one promotion chain contains a type that's a subtype of a type in the other promotion chain, this can be surprising for users. For example, the following example came up in https://github.com/dart-lang/sdk/issues/51464:

```dart
void f(num? x) {
switch (x) {
case final a when a is int:
case final a when a is num:
a; // (1)
}
}
```
It seems intuitively like `a` should be promoted to `num` at (1), because `int` is a subtype of `num`. And it would be sound to do so. But flow analysis doesn't promote `a` at all, because the two promotion chains are `num? :> int` and `num? :> num`, and the only common type between those two chains is `num?`.

Should we try to improve this? We could instead say that when joining a promotion chain that ends in `U` with a promotion chain that ends in `V`:
- If `U <: V`, then the resulting promotion chain ends in `V`;
- Otherwise if `V <: U`, then the resulting promotion chain ends in `U`;
- Otherwise both `U` and `V` are dropped and the resulting promotion chain is formed by combining the remainder of the two promotion chains.

(We'd have to flesh out this definition to determine what happens to the rest of the promotion chain, but I don't think that would be too difficult).

The advantage would be that code like the example above would work in the way the user intuitively expects. The disadvantage would be the same disadvantage that comes with any change to type inference: risk of subtle and annoying changes to the behaviour of existing code.

CC @dart-lang/language-team

Contributor guide

Open the contributing guide

Research direction

No files, tests, or entry points are identified in the issue. Start by locating the flow-analysis promotion-chain join logic in the Dart language implementation or specification, then review the linked issue and comment discussion. Done means defining the remaining-chain behavior and assessing whether the proposed subtype-aware join is sound and acceptable for existing code.

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
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.