Skip to content
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

Add null-safety specification of super-bounded types #1133

Merged
merged 5 commits into from
Sep 11, 2020
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 108 additions & 3 deletions accepted/future-releases/nnbd/feature-specification.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ Status: Draft

## CHANGELOG

2020.08.05
- Specify updates to super-bounded type rules for null safety.

2020.07.09
- Specify combined member signature and spread element typing
with null-safety.
with null safety.

2020.06.02
- Fix the diff to the spec for potentially constant instance checks
Expand Down Expand Up @@ -699,11 +702,32 @@ the element, key, and value type of `...e` and `...?e` is `Never`.
*When the static type _S_ of `e` is strictly non-nullable, such as when _S_
is `Never`, `...?e` is a warning, but it may still occur.*

### Instantiate to bounds
### Instantiation to bound

The computation of instantiation to bounds is changed to substitute `Never` for
The computation of instantiation to bound is changed to substitute `Never` for
type variables appearing in contravariant positions instead of `Null`.

### Super-bounded types

Null safety requires three changes to the section 'Super-Bounded Types' in
the language specification.

The definition of a top type is changed: _T_ is a top type if and only if
`Object?` is a subtype of _T_. Note that the helper predicate **TOP**
provides a syntactic characterization of the same concept.

The definition of a super-bounded type is changed such that occurrences of
`Null` are replaced by types involving `Never`, and `Object` is replaced by
`Object?`. Moreover, top types in invariant positions and in positions that
have no variance (*unused type parameters in a type alias*) are given the
same treatment as top types in covariant positions. This causes one
sentence to change, with the following result:

Let _T'_ be the result of replacing every occurrence in _T_ of a type _S_
in a contravariant position where _S <: Never_ by `Object?`, and every
eernstg marked this conversation as resolved.
Show resolved Hide resolved
occurrence in _T_ of a top type in a position which is not contravariant by
eernstg marked this conversation as resolved.
Show resolved Hide resolved
`Never`.

### Least and greatest closure

The definitions of least and greatest closure are changed in null safe libraries
Expand Down Expand Up @@ -898,6 +922,87 @@ These are extended as
per
[separate proposal](https://github.com/dart-lang/language/blob/master/resources/type-system/flow-analysis.md).

## Helper predicates

The following helper predicates are used to classify types. They are syntactic
in nature such that termination is obvious. In particular, they do not rely on
subtyping.

The **TOP** predicate is true for any type which is in the equivalence class of
top types.

- **TOP**(`T?`) is true iff **TOP**(`T`) or **OBJECT**(`T`)
- **TOP**(`T*`) is true iff **TOP**(`T`) or **OBJECT**(`T`)
- **TOP**(`dynamic`) is true
- **TOP**(`void`) is true
- **TOP**(`FutureOr<T>`) is **TOP**(T)
- **TOP**(T) is false otherwise

**TOP**(`T`) is true if and only if `T` is a supertype of `Object?`.

The **OBJECT** predicate is true for any type which is in the equivalence class
of `Object`.

- **OBJECT**(`Object`) is true
- **OBJECT**(`FutureOr<T>`) is **OBJECT**(T)
- **OBJECT**(`T`) is false otherwise

**OBJECT**(`T`) is true if and only if `T` is a subtype and a supertype of
`Object`.

The **BOTTOM** predicate is true for things in the equivalence class of `Never`.

- **BOTTOM**(`Never`) is true
- **BOTTOM**(`X&T`) is true iff **BOTTOM**(`T`)
- **BOTTOM**(`X extends T`) is true iff **BOTTOM**(`T`)
- **BOTTOM**(`T`) is false otherwise

**BOTTOM**(`T`) is true if and only if `T` is a subtype of `Never`.

The **NULL** predicate is true for things in the equivalence class of `Null`

- **NULL**(`Null`) is true
- **NULL**(`T?`) is true iff **NULL**(`T`) or **BOTTOM**(`T`)
- **NULL**(`T*`) is true iff **NULL**(`T`) or **BOTTOM**(`T`)
- **NULL**(`T`) is false otherwise

**NULL**(`T`) is true if and only if `T` is a subtype and a supertype of `Null`.

The **MORETOP** predicate defines a total order on top and `Object` types.

- **MORETOP**(`void`, `T`) = true
- **MORETOP**(`T`, `void`) = false
- **MORETOP**(`dynamic`, `T`) = true
- **MORETOP**(`T`, `dynamic`) = false
- **MORETOP**(`Object`, `T`) = true
- **MORETOP**(`T`, `Object`) = false
- **MORETOP**(`T*`, `S*`) = **MORETOP**(`T`, `S`)
- **MORETOP**(`T`, `S*`) = true
- **MORETOP**(`T*`, `S`) = false
- **MORETOP**(`T?`, `S?`) = **MORETOP**(`T`, `S`)
- **MORETOP**(`T`, `S?`) = true
- **MORETOP**(`T?`, `S`) = false
- **MORETOP**(`FutureOr<T>`, `FutureOr<S>`) = **MORETOP**(T, S)

The **MOREBOTTOM** predicate defines an (almost) total order on bottom and
`Null` types. This does not currently consistently order two different type
variables with the same bound.

- **MOREBOTTOM**(`Never`, `T`) = true
- **MOREBOTTOM**(`T`, `Never`) = false
- **MOREBOTTOM**(`Null`, `T`) = true
- **MOREBOTTOM**(`T`, `Null`) = false
- **MOREBOTTOM**(`T?`, `S?`) = **MOREBOTTOM**(`T`, `S`)
- **MOREBOTTOM**(`T`, `S?`) = true
- **MOREBOTTOM**(`T?`, `S`) = false
- **MOREBOTTOM**(`T*`, `S*`) = **MOREBOTTOM**(`T`, `S`)
- **MOREBOTTOM**(`T`, `S*`) = true
- **MOREBOTTOM**(`T*`, `S`) = false
- **MOREBOTTOM**(`X&T`, `Y&S`) = **MOREBOTTOM**(`T`, `S`)
- **MOREBOTTOM**(`X&T`, `S`) = true
- **MOREBOTTOM**(`S`, `X&T`) = false
- **MOREBOTTOM**(`X extends T`, `Y extends S`) = **MOREBOTTOM**(`T`, `S`)

## Runtime semantics

### Weak and strong semantics
Expand Down
82 changes: 14 additions & 68 deletions resources/type-system/upper-lower-bounds.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ leafp@google.com

## CHANGELOG

2020.08.13
- Move helper predicates to the null safety specification.

2020.07.21
- **CHANGE** Specify treatment of mixed hierarchies.

Expand All @@ -14,7 +17,7 @@ This documents the currently implemented upper and lower bound computation,
modified to account for explicit nullability and the accompanying type system
changes (including the legacy types). In the interest of backwards
compatibility, it does not try to fix the various issues with the existing
algorithm.
algorithm.

## Types

Expand All @@ -36,72 +39,15 @@ We assume that type aliases have been expanded, and that all types are named

## Helper predicates

The **TOP** predicate is true for any type which is in the equivalence class of
top types.

- **TOP**(`T?`) is true iff **TOP**(`T`) or **OBJECT**(`T`)
- **TOP**(`T*`) is true iff **TOP**(`T`) or **OBJECT**(`T`)
- **TOP**(`dynamic`) is true
- **TOP**(`void`) is true
- **TOP**(`FutureOr<T>`) is **TOP**(T)
- **TOP**(T) is false otherwise

The **OBJECT** predicate is true for any type which is in the equivalence class
of `Object`.

- **OBJECT**(`Object`) is true
- **OBJECT**(`FutureOr<T>`) is **OBJECT**(T)
- **OBJECT**(T) is false otherwise

The **BOTTOM** predicate is true for things in the equivalence class of `Never`.

- **BOTTOM**(`Never`) is true
- **BOTTOM**(`X&T`) is true iff **BOTTOM**(`T`)
- **BOTTOM**(`X extends T`) is true iff **BOTTOM**(`T`)
- **BOTTOM**(`T`) is false otherwise

The **NULL** predicate is true for things in the equivalence class of `Null`

- **NULL**(`Null`) is true
- **NULL**(`T?`) is true iff **NULL**(`T`) or **BOTTOM**(`T`)
- **NULL**(`T*`) is true iff **NULL**(`T`) or **BOTTOM**(`T`)
- **NULL**(`T`) is false otherwise

The **MORETOP** predicate defines a total order on top and `Object` types.

- **MORETOP**(`void`, `T`) = true
- **MORETOP**(`T`, `void`) = false
- **MORETOP**(`dynamic`, `T`) = true
- **MORETOP**(`T`, `dynamic`) = false
- **MORETOP**(`Object`, `T`) = true
- **MORETOP**(`T`, `Object`) = false
- **MORETOP**(`T*`, `S*`) = **MORETOP**(`T`, `S`)
- **MORETOP**(`T`, `S*`) = true
- **MORETOP**(`T*`, `S`) = false
- **MORETOP**(`T?`, `S?`) = **MORETOP**(`T`, `S`)
- **MORETOP**(`T`, `S?`) = true
- **MORETOP**(`T?`, `S`) = false
- **MORETOP**(`FutureOr<T>`, `FutureOr<S>`) = **MORETOP**(T, S)

The **MOREBOTTOM** predicate defines an (almost) total order on bottom and
`Null` types. This does not currently consistently order two different type
variables with the same bound.

- **MOREBOTTOM**(`Never`, `T`) = true
- **MOREBOTTOM**(`T`, `Never`) = false
- **MOREBOTTOM**(`Null`, `T`) = true
- **MOREBOTTOM**(`T`, `Null`) = false
- **MOREBOTTOM**(`T?`, `S?`) = **MOREBOTTOM**(`T`, `S`)
- **MOREBOTTOM**(`T`, `S?`) = true
- **MOREBOTTOM**(`T?`, `S`) = false
- **MOREBOTTOM**(`T*`, `S*`) = **MOREBOTTOM**(`T`, `S`)
- **MOREBOTTOM**(`T`, `S*`) = true
- **MOREBOTTOM**(`T*`, `S`) = false
- **MOREBOTTOM**(`X&T`, `Y&S`) = **MOREBOTTOM**(`T`, `S`)
- **MOREBOTTOM**(`X&T`, `S`) = true
- **MOREBOTTOM**(`S`, `X&T`) = false
- **MOREBOTTOM**(`X extends T`, `Y extends S`) = **MOREBOTTOM**(`T`, `S`)

This document relies on several type classification helper predicates
which are specified in the
[null safety specification](https://github.com/dart-lang/language/blob/master/accepted/future-releases/nnbd/feature-specification.md):
**TOP**, which is true for all top types;
**OBJECT**, which is true for types equivalent to `Object`;
**BOTTOM**, which is true for types equivalent to `Never`;
**NULL**, which is true for types equivalent to `Null`;
**MORETOP**, which is a total order on top and `Object` types; and
**MOREBOTTOM**, which is an (almost) total order on bottom and `Null` types.

## Upper bounds

Expand Down Expand Up @@ -420,7 +366,7 @@ that are not identical are `T0` and `S0` respectively, and **MORETOP**(`T0`,
`S0`).

A similar treatment would need to be done for the bottom types as well, since
there are two equivalences there.
there are two equivalences there.
- `X extends T` is equivalent to `Null` if `T` is equivalent to `Null`.
- `FutureOr<Null>` is equivalent `Future<Null>`.

Expand Down