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

Generic inference in function #49884

Closed
r0kan opened this issue Sep 1, 2022 · 5 comments
Closed

Generic inference in function #49884

r0kan opened this issue Sep 1, 2022 · 5 comments
Labels
area-analyzer Use area-analyzer for Dart analyzer issues, including the analysis server and code completion.

Comments

@r0kan
Copy link

r0kan commented Sep 1, 2022

Consider the following example:

class BaseHandlerHolder<TData, THandler extends Function> {}

typedef SpecificHandler<TData> = void Function(TData data);

class SpecificHandlerHolder<TData, THandler extends SpecificHandler<TData>>
    extends BaseHandlerHolder<TData, THandler> {}

void useHandler<TData, THandler extends Function>({
  required BaseHandlerHolder<TData, THandler> holder,
  required THandler handler,
}) {}

void Function(THandler handler) useHandler2<TData, THandler extends Function>(
    BaseHandlerHolder<TData, THandler> holder) {
  return (THandler handler) {};
}

void main() {
  final specificHolder = SpecificHandlerHolder<int, void Function(int data)>();
  useHandler(holder: specificHolder, handler: (data) {});
  useHandler2(specificHolder)((data) {});
}

In the first function (useHandler), the data type is dynamic while in the second function (useHandler2) data type is int.

Why does type inference not work in the first case?

Dart SDK version: 2.18.0 (stable)
MacOSX

@eernstg
Copy link
Member

eernstg commented Sep 1, 2022

Good question! I think this might be a bug in type inference. The inferred type arguments in the invocation of useHandler are int and void Function(int), so it's type correct to pass a void Function(dynamic), but I would still expect inference to choose the type of the parameter named data to be int. @stereotype441?

@stereotype441
Copy link
Member

The reason type inference isn't filling in int for data in the useHandler case is because we would have to flow type information from the holder argument to the handler argument. In many cases we can do that (see the horizontal inference feature), but in order to do so, there has to be enough type information in the generic type of the method being called so that horizontal inference can figure out the dependencies between the arguments.

According to the spec, horizontal inference decides there's a dependency edge from argument A to argument B if and only if the type of the invocation target is generic, and the following relationship exists among A, B, and at least one of the invocation target’s type parameters T:

  1. A is a function literal expression,

  2. AND the parameter in the invocation target corresponding to A is function typed,

  3. AND T is a free variable in the type of at least one of the parameters of that function type,

  4. AND the corresponding parameter in A does not have a type annotation,

  5. AND EITHER:

    • The parameter in the invocation target corresponding to B is function typed, and T is a free variable in its return type

    • OR the parameter in the invocation target corresponding to B is not function typed, and T is a free variable in its type.

There's a little bit of ambiguity here. In condition 2, does a type parameter type count if its bound is a function type? The way I implemented it (in both the analyzer and front end) is that no, a type parameter type whose bound is a function type doesn't count. This is the reason horizontal inference is failing in this example--the handler parameter has type THandler which is a type parameter type, not a function type.

We could change that so that a type parameter type was ok if its bound was a function type, but even if we did, since the bound of THandler is Function (the supertype of all function types), its parameter types aren't known, so there is no way to satisfy condition 3.

@r0kan
Copy link
Author

r0kan commented Sep 1, 2022

Thanks for the answer. I was waiting for 2.18 and thought type inference would work in that case. Everything turned out to be more difficult )

@devoncarew devoncarew added the area-analyzer Use area-analyzer for Dart analyzer issues, including the analysis server and code completion. label Sep 1, 2022
@bwilkerson
Copy link
Member

@stereotype441 Should we close this issue as working-as-intended?

@stereotype441
Copy link
Member

@stereotype441 Should we close this issue as working-as-intended?

Sure. Closing now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-analyzer Use area-analyzer for Dart analyzer issues, including the analysis server and code completion.
Projects
None yet
Development

No branches or pull requests

5 participants