sdk icon indicating copy to clipboard operation
sdk copied to clipboard

Static analysis for a `@returnType` annotation for Function types

Open srawlins opened this issue 3 years ago • 5 comments

This request is specifically for the Angular team, but can be used generally. The problem is as follows: given a function with the following signature:

void foo(Function cb)

there is no way to specify that cb must return a non-nullable type. For whatever reason, the type of cb cannot be function-typed (like int Function(bool)), and the most narrow type that can be specified is Function. The return value can be null-checked at runtime, but it would be much better to catch this statically. One idea is an annotation like so:

  • void foo(@returnType<Object> Function cb) or
  • void foo(@ReturnType(Object) Function cb)

With recent language versions of Dart, either of these could specify a function type or a type with type arguments:

  • void foo(@returnType<int Function(bool)> Function cb)
  • void foo(@returnType(int Function(bool)) Function cb)
  • void foo(@ReturnType<List<String>> Function cb)
  • void foo(@ReturnType(List<String>) Function cb)

I think I prefer the @returnType<Object> API.

The rules for this annotation are:

  • It can only annotate a parameter (or field?)
  • The type of the variable (parameter, field, ...) that it annotates must be exactly Function
  • Given an annotation like @returnType<X>, any argument given for this parameter must be function-typed and the return type on the function-type must be assignable to X.
    • Alternatively, we could also allow an argument which is a direct reference to a variable (parameter, ...) which is itself annotated with @returnType. I think the decision about allowing this is just how difficult it is to implement.

Open questions:

  • The format of the annotation; two options listed above
  • Are fields important? Easier to only allow it on parameters to start?
  • What about inheritance? If a method D.f overrides a method C.f, with a parameter annotated with @returnType, must the corresponding parameter in D.f also be explicitly annotated?
  • For the assignability bit, would dynamic be allowed, as the only type which can be explicitly cast to other types? Explicitly ban dynamic except for @returnType<dynamic>?

CC @leonsenft @jakemac53 who helped design this yesterday.

srawlins avatar Jan 20 '22 18:01 srawlins

  • What about inheritance? If a method D.f overrides a method C.f, with a parameter annotated with @returnType, must the corresponding parameter in D.f also be explicitly annotated?

Given normal override rules I would say no, it's allowed to expand the type to a more general type (ie: Function) in this case. If it wanted to call super though then it would have to duplicate the annotation.

jakemac53 avatar Jan 20 '22 18:01 jakemac53

Would or could such an annotation affect type flow analysis?

For example, would you need to still null check the return value from an annotated function?

int square(@returnType<int Function()> Function cb) {
  final value = cb()!; // Would the ! still be necessary, or could it be omitted?
  return cb * cb;
}

Or would this simply produce an error at the call site of square()?

leonsenft avatar Jan 20 '22 19:01 leonsenft

Would or could such an annotation affect type flow analysis?

Nope.

For example, would you need to still null check the return value from an annotated function?

Yes, if it does today. (E.g. if the default return type is dynamic, which I think it is. Then value would be dynamic without the ! and cb * cb would be dynamic invocation.

srawlins avatar Jan 20 '22 19:01 srawlins

Does this still make sense? Perhaps if there was no other user, and it wasn't needed so far, let's close the issue?

matanlurey avatar Jun 29 '24 00:06 matanlurey

I think this request still makes sense. Our team keeps issues open even if we have no plans to implement it, for searching, tracking, and discussion purposes. But we can make it P4 if Angular has chugged along OK without it, and no one else has chimed in that it would be useful.

srawlins avatar Jun 29 '24 15:06 srawlins