dart-lang / sdk

The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.
https://dart.dev
BSD 3-Clause "New" or "Revised" License
10.24k stars 1.57k forks source link

Type inference from parameter type #37247

Open derolf opened 5 years ago

derolf commented 5 years ago

The problem

Consider the following example:

    typedef Action<T> = void Function(T arg);

    void execute<T>(T arg, Action<T> action) => action(arg);

    void main() {
      execute(42, (value) => print(value.bar));
    }

I would expect the Dart Analyzer to fail at value.bar since T could be inferred to number. Instead, Dart does not infer T to number, but falls back to dynamic.

What are other languages doing?

Equivalent example in TypeScript:

    type Action<T> = (arg: T) => void;

    function execute<T>(arg: T, action: Action<T>) {
        return action(arg);
    }

    function main() {
      execute(42, (value) => console.log(value.bar));
    }

yields error

Property 'bar' does not exist on type 'number'.

Equivalent example in Kotlin:

    typealias Action<T> = (arg: T) -> Unit;

    fun<T> execute(arg: T, action: Action<T>) = action(arg);

    fun main() {
      execute(42) { value -> print(value.bar) };
    }

yields error

Unresolved reference: bar

https://stackoverflow.com/questions/56540905/type-inference-from-parameter-type

eernstg commented 5 years ago

This is a good example of a case where it would have been very useful for inference to choose int as the parameter type for the function literal, like in Kotlin and TypeScript.

However, when inference has chosen the type argument int for the given invocation of execute then the first parameter is type correct, and so is the second one with parameter type dynamic (because void Function(dynamic) is a subtype of void Function(int)).

In order to address the immediate problem, you could use dartanalyzer --no-implicit-dynamic, which you might prefer anyway. (Just guessing ;-)

For the broader question of why inference did not give the parameter value the type int, I believe this is an instance of https://github.com/dart-lang/sdk/issues/25490, which is concerned with information flow from one argument to another one during type inference.

That kind of information flow arises automatically when type inference is done using algorithm W or similar mechanisms based on unification, but type inference using unification in a language with subtyping isn't tractable, so there's a need to go into heuristics, and that hasn't been done yet for Dart.

eernstg commented 5 years ago

@leafpetersen, do you have further comments on this? I added a reference to this issue on #25490, because it's a good example to keep in mind. This issue could then be closed, marking it as a duplicate of #25490.