Skip to content

Lots of new strong-mode hints related to generic functions #25040

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

Closed
zoechi opened this issue Nov 25, 2015 · 12 comments
Closed

Lots of new strong-mode hints related to generic functions #25040

zoechi opened this issue Nov 25, 2015 · 12 comments
Assignees
Labels
legacy-area-analyzer Use area-devexp instead. P2 A bug or feature request we're likely to work on

Comments

@zoechi
Copy link
Contributor

zoechi commented Nov 25, 2015

'123-456'
    .split('-')
    .map((String t) => int.parse(t.trim()))
//       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    .toList()

Information:(92, 22) The argument type '(String) → T' cannot be assigned to the parameter type '(String) → int'

int val = 10;
math.min(100, val);

Information:(115, 22) The argument type 'int' cannot be assigned to the parameter type 'T'

I wasn't yet able to figure out how to apply generic type comments to satisfy these checks.

@leafpetersen
Copy link
Member

Yeah, something's going wrong there. It's interesting that those are showing up as hints and not warnings. I'll take a look today and see if I can figure out what's happening.

@zoechi
Copy link
Contributor Author

zoechi commented Nov 25, 2015

Is it possible to add type annotations as comments on the calls site as well. I only saw examples of them on the function declaration site. How would they look like? I tried a few things but could't find anything that showed any effect.

@leafpetersen
Copy link
Member

Yes, it is possible to do so. Your example would look like this:

import 'dart:math' as math;
void main () {
  int val = 10;
  math.min/*<int>*/(10, val);
}

This doesn't solve your issue though.

Note also that generic methods are not yet integrated into the errors and warnings code, so you won't get all of the errors that you might expect. This may be why you are seeing those hints - a bad interaction between the implemented and unimplemented parts of this. I don't understand yet why our tests aren't catching this though.

@leafpetersen
Copy link
Member

There seems to be a problem with using generics though prefixed identifiers. If you remove the qualification on the import and use min unprefixed, the hints go away. I'll keep looking for the root cause.

@zoechi
Copy link
Contributor Author

zoechi commented Nov 25, 2015

Great, thanks for the info!

@zoechi
Copy link
Contributor Author

zoechi commented Nov 25, 2015

I failed to figure out what's the difference between /*<T>*/ and /*=T*/ which was also added at different places.
Could you please shed some light on this?

@leafpetersen
Copy link
Member

Sure. We'll write this up soon when it's ready for broader use, but since you're already experimenting, here's a quick explanation.

In a method or function declaration, /*<S, T>*/ after the function name declares that the function takes two type parameters named S and T. You can have bounds using the usual syntax, and any number of parameters.

In a method or function invocation, /*<int, String>*/ passes int as the first type parameter, and String as the second parameter.

In a class type declaration, constructor call, or generic method invocation, < dynamic /*=T*/> use T instead of dynamic for the instantiation. So for example List<dynamic /*=T*/> will be treated by the analyzer as if it was written List<T>.

In a variable declaration, writing dynamic /*=T*/ acts as if you had written the type T instead of dynamic. You can have arbitrary types after the =, and you can use other things than dynamic. You can also replace var in the same way. In parameter lists where leaving off a type entirely is valid, you can simply use /*=T*/.

Example:

// mapi maps List<S> to List<T> with a mapper that also takes an index. 
List<dynamic /*=T*/> mapi/*<S, T>*/(List<dynamic /*=S*/> inList, /*=T*/ mapper(int i, /*=S*/ x)) {
   var outList = <dynamic /*=T*/>[];
   for(int i = 0; i < inList.length;i++) {
      var /*=T*/ e = mapper(i,inList[i] );
      outList.add(e);
  }
  return outList;
}```

A couple of caveats.  
 - This is not fully implemented yet.  You won't get all of the errors and warnings you would expect. 
 - Inference is only partially landed. You will have to be fairly explicit with your types.
 - This is not intended to be a long term solution.  The syntax is chosen to make it easy to convert to the real syntax once (if) we can land that.
 - Only DDC will reifiy generics using the comment syntax.  For all other platforms (VM, dart2js), the comments will be ignored.

@zoechi
Copy link
Contributor Author

zoechi commented Nov 25, 2015

Tanks a lot :)

@leafpetersen
Copy link
Member

This seems to have fixed the prefixed top level function issue (the math.min example), but doesn't fix the other case. I'll keep looking into that one.

@leafpetersen
Copy link
Member

The map example may be an interaction with inferred return types. Replacing the lambda with a local bound function eliminates the erroneous hint.

@leafpetersen
Copy link
Member

The remaining issue here is fixed by 095310b .

@zoechi
Copy link
Contributor Author

zoechi commented Dec 7, 2015

Great! Can't wait to try it :)

@kevmoo kevmoo added P2 A bug or feature request we're likely to work on and removed Priority-Medium labels Mar 1, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
legacy-area-analyzer Use area-devexp instead. P2 A bug or feature request we're likely to work on
Projects
None yet
Development

No branches or pull requests

5 participants