The bulk of the intricacies in Dart type inference occur in the
handling of selector chains, which encompasses the following
constructs (examples in parentheses):
- Static method invocations (`Foo.m()`)
- Implicit instance creation (`Foo()`)
- Implicit `this` invocation (`m()`)
- Explicit extension invocation (`Ext(...).m(...)`)
- Super invocation (`super.m(...)`)
- Method invocation (`....m(...)` or `...?.m(...)`)
- Explicit extension call invocation (`Ext(...)(...)`)
- Super call invocation (`super(...)`)
- Call invocation (`...(...)`)
- Static method tearoff (`Foo.m`)
- Constructor tearoff (`Foo.new`)
- Explicit extension tearoff or property get (`Ext(...).p`)
- Super method tearoff or property get (`super.p`)
- Method tearoff or property get (`....p` or `...?.p`)
- Implicit this method tearoff with type arguments (`m<...>`)
- Type instantiation (`Foo<...>`)
- Explicit extension index operation (`Ext(...)[...]`)
- Super index operation (`super[...]`)
- Index operation (`...[...]` or `...?[...]`)
- Null check (`...!`)
Since this is a lot of constructs, I'm going to break them up into
several PRs to simplify review. This first PR establishes the general
framework for how to differentiate among the above forms, and then it
specifies the behavior of just four of them: static method
invocations, implicit `this` invocations, non-null-aware method
invocations, and call invocations. The rest of the forms are left as
TODOs, and will be addressed in follow-up PRs.
In order to specify these four forms, it was necessary to add some
introductory material:
- Bound resolution, which converts type parameters into their
bounds. (This concept exists in the analyzer and CFE, but I wasn't
able to find it in the spec so I added it after the "Subtype
constraint generation" section.)
- Argument part inference, the general process by which type inference
is applied to the <argumentPart> portion of any invocation. Much of
this section was adapted from the horizontal inference spec
(https://github.com/dart-lang/language/blob/main/accepted/2.18/horizontal-inference/feature-specification.md).
- Argument partitioning, the mechanism used by horizontal inference to
choose the order in which to type infer arguments that are function
expressions. This was also adapted from the horizontal inference
spec.
- Method invocation inference, which contains the common subroutines
of type inference used for implicit `this` invocations, method
invocations, and call invocations. In a later PR I intend to also
use this logic to specify how user-definable operator invocations
are type inferred.