mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 02:27:39 +00:00
dynamic-members.md: Make d.hashCode()
and d.runtimeType()
an error
A rendered version of the document as of patchset 18 is available here: https://gist.github.com/eernstg/fc0094b0230ea18b9507092e50dab537 Change-Id: Iad21bd3e8f31847cfdc0a217249de44d5424e2b4 Reviewed-on: https://dart-review.googlesource.com/72700 Reviewed-by: Lasse R.H. Nielsen <lrn@google.com>
This commit is contained in:
parent
a6bac2ed29
commit
1acf6f768d
|
@ -1,10 +1,10 @@
|
|||
# Typing of members of dynamic
|
||||
|
||||
Author: eernst@.
|
||||
**Author**: eernst@.
|
||||
|
||||
Version: 0.1 (2018-03-13)
|
||||
**Version**: 0.2 (2018-09-04)
|
||||
|
||||
Status: Under discussion.
|
||||
**Status**: Under discussion.
|
||||
|
||||
**This document** is a Dart 2 feature specification of the static typing
|
||||
of instance members of a receiver whose static type is `dynamic`.
|
||||
|
@ -123,20 +123,37 @@ and story.
|
|||
In this section, `Object` denotes the built-in class `Object`, and
|
||||
`dynamic` denotes the built-in type `dynamic`.
|
||||
|
||||
Let `e` be an expression of the form `d.g` where the static type of `d` is
|
||||
`dynamic` and `g` is a getter declared in `Object`; if the return type of
|
||||
`Object.g` is `T` then the static type of `e` is `T`.
|
||||
Let `e` be an expression of the form `d.m`, which is not followed by an
|
||||
argument part, where the static type of `d` is `dynamic`, and `m` is a
|
||||
getter declared in `Object`; if the return type of `Object.m` is `T` then
|
||||
the static type of `e` is `T`.
|
||||
|
||||
*For instance, `d.hashCode` has type `int` and `d.runtimeType` has type
|
||||
`Type`.*
|
||||
|
||||
Let `e` be an expression of the form `d.m` where the static type of `d` is
|
||||
`dynamic` and `m` is a method declared in `Object` whose method signature
|
||||
has type `F` (*which is a function type*). The static type of `e` is then
|
||||
`F`.
|
||||
Let `e` be an expression of the form `d.m`, which is not followed by an
|
||||
argument part, where the static type of `d` is `dynamic`, and `m` is a
|
||||
method declared in `Object` whose method signature has type `F` (*which is
|
||||
a function type*). The static type of `e` is then `F`.
|
||||
|
||||
*For instance, `d.toString` has type `String Function()`.*
|
||||
|
||||
Let `e` be an expression of the form `d.m(arguments)` or
|
||||
`d.m<typeArguments>(arguments)` where the static type of `d` is `dynamic`,
|
||||
`m` is a getter declared in `Object` with return type `F`, `arguments` is
|
||||
an actual argument list, and `typeArguments` is a list of actual type
|
||||
arguments, if present. Static analysis will then process `e` as a function
|
||||
expression invocation where a function of static type `F` is applied to the
|
||||
given argument part.
|
||||
|
||||
*So `d.runtimeType(42)` is a compile-time error, because it is checked as a
|
||||
function expression invocation where an entity of static type `Type` is
|
||||
invoked. Note that it could actually succeed: An overriding implementation
|
||||
of `runtimeType` could return an instance whose dynamic type is a subtype
|
||||
of `Type` that has a `call` method. We decided to make it an error because
|
||||
it is likely to be a mistake, especially in cases like `d.hashCode()` where
|
||||
a developer might have forgotten that `hashCode` is a getter.*
|
||||
|
||||
Let `e` be an expression of the form `d.m(arguments)` where the static type
|
||||
of `d` is `dynamic`, `arguments` is an actual argument list, and `m` is a
|
||||
method declared in `Object` whose method signature has type `F`. If the
|
||||
|
@ -152,36 +169,41 @@ known declaration are not errors, they just get return type `dynamic`.*
|
|||
|
||||
Let `e` be an expression of the form `d.m<typeArguments>(arguments)` where
|
||||
the static type of `d` is `dynamic`, `typeArguments` is a list of actual
|
||||
type arguments, `arguments` is an actual argument list, and `m` is a
|
||||
method declared in `Object` whose method signature has type `F`. The
|
||||
static type of `e` is then `dynamic`.
|
||||
type arguments, `arguments` is an actual argument list. It is a
|
||||
compile-time error if `m` is a non-generic method declared in `Object`.
|
||||
|
||||
*We do not need to address the case `d.m(arguments)` where `m` is a getter
|
||||
declared in `Object` whose return type is a function type or a supertype
|
||||
thereof, because no such getters exist, but such a case would be covered in
|
||||
a generalization to support `dynamic(T)` for all `T`. Similarly, such a
|
||||
generalization would need to handle the case where the method is generic
|
||||
and no type arguments are passed, and the case where the method is
|
||||
generic and a wrong number of type arguments is passed, etc. Such a
|
||||
generalization is expected to be possible without invalidating the rules
|
||||
given in this document.*
|
||||
*No generic methods are declared in `Object`. Hence, we do not specify that
|
||||
there must be the statically required number of actual type arguments, and
|
||||
they must satisfy the bounds. That would otherwise be the consistent
|
||||
approach, because the invocation is guaranteed to fail when any of those
|
||||
requirements are violated, but generalizations of this mechanism would need
|
||||
to include such rules.*
|
||||
|
||||
For an instance method invocation `e` (including invocations of getters,
|
||||
setters, and operators) where the receiver has static type `dynamic` and
|
||||
`e` does not match any of the above cases, the static type of `e` is
|
||||
`dynamic`.
|
||||
|
||||
*Note that it is not possible for an instance method invocation with a
|
||||
receiver of type `dynamic` to be a compile-time error (except, of course,
|
||||
that some expressions like `x[1, 2]` are syntax errors even though they
|
||||
could also be considered "invocations", and except that subexpressions are
|
||||
checked separately, and any given actual argument could be a compile-time
|
||||
error). In general, any argument list shape could be handled via
|
||||
When a `cascadeSection` performs a getter or method invocation that
|
||||
corresponds to one of the cases above, the corresponding static analysis
|
||||
and compile-time errors apply.
|
||||
|
||||
*For instance, `d..foobar(16)..hashCode()` is an error.*
|
||||
|
||||
*Note that only very few forms of instance method invocation with a
|
||||
receiver of type `dynamic` can be a compile-time error. Of course,
|
||||
some expressions like `x[1, 2]` are syntax errors even though they
|
||||
could also be considered "invocations", and subexpressions are checked
|
||||
separately so any given actual argument could be a compile-time
|
||||
error. But almost any given argument list shape could be handled via
|
||||
`noSuchMethod`, and an argument of any type could be accepted because any
|
||||
formal parameter in an overriding declaration could have its type
|
||||
annotation contravariantly changed to `Object`. So it is a natural
|
||||
consequence of the principle mentioned in 'Motivation' that a `dynamic`
|
||||
receiver admits all instance method invocations.*
|
||||
receiver admits almost all instance method invocations. The few cases where
|
||||
an instance method invocation with a receiver of type `dynamic` is an error
|
||||
are either guaranteed to fail at run time, or they are very likely to be
|
||||
developer mistakes.*
|
||||
|
||||
|
||||
## Dynamic Semantics
|
||||
|
@ -198,5 +220,9 @@ document.*
|
|||
|
||||
## Revisions
|
||||
|
||||
- 0.2 (2018-09-04) Adjustment to make `d.hashCode()` and similar
|
||||
expressions an error, cf.
|
||||
[this github issue](https://github.com/dart-lang/sdk/issues/34320).
|
||||
|
||||
- 0.1 (2018-03-13) Initial version, based on discussions in
|
||||
[this github issue](https://github.com/dart-lang/sdk/issues/32414).
|
||||
[this github issue](https://github.com/dart-lang/sdk/issues/32414).
|
||||
|
|
Loading…
Reference in a new issue