-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Implement missing warnings for generic methods #25200
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
Comments
I believe artiy warnings during instantiate has been fixed (ElementResolver._resolveGenericMethod). I don't think we check bounds, however. |
Is this covered by StrongTypeSystemImpl.instantiateToBounds + our existing checks? I think we'll implicitly instantiate with the bounds, then later we'll do appropriate type checking against the parameters/return type as we normally would. One case that is not covered is the "override a generic method with a non-generic method" case. |
I believe this check already exists in Analyzer: abstract class Iter {
List/*<S>*/ map(/*=S*/ f(x)) => <dynamic/*=T*/>[];
}
|
Just checking, I believe this can't be expressed right now, until we fix #25179? In other words you can't write: typedef generic S F<S>(S x);
void foo<T extends F>(T t) {} Something to think about when we implement 25179. |
I think that's correct. |
EDIT: this code looks busted so I've unchecked it. In particular this looks wrong: if (overriddenFT.typeFormals.isEmpty) {
overriddenFT = _typeSystem.instantiateToBounds(overriddenFT);
} If overriddenFT has no typeFormals, instantiateToBounds is a no-op... that doesn't look right. I think it meant to use overridingFT. Either way this is a bit worrying and needs further investigation. |
Oh, just noticed: TYPE_ARGUMENT_NOT_MATCHING_BOUNDS is only a warning even in strong mode. I think we should bump it to an error? (easy to do, there's already an error for when it happens in constant evaluation) |
Yes, I think that should be an error. |
edit: this is fixed in f976407. My original message is below for context. BTW @leafpetersen -- I was reading through the code in _isFunctionSubtype ... I think we may currently allow I suspect it's caused by this code: if (!f1.typeFormals.isEmpty) {
if (f2.typeFormals.isEmpty) {
f1 = instantiateToBounds(f1);
return _isFunctionSubtypeOf(f1, f2);
} else {
return _isGenericFunctionSubtypeOf(f1, f2, fuzzyArrows: fuzzyArrows);
}
} In particular, I don't see anything in the method that checks to ensure f2.typeFormals.isEmpty. I expected to find a case like: } else if (f2.typeFormals.isNotEmpty) {
// non-generic functions can't subtype generic ones.
return false;
} _isGenericFunctionSubtypeOf will always return return false if the parameter count is mismatched, but I don't think we'll get there. |
Another issue w/ universal types: the spec type system didn't know how to handle them. This led to breaking some invariants, like this assert in our DownCast.create: // toT <:_R fromT => to <: fromT
// NB: classes with call methods are subtypes of function
// types, but the function type is not assignable to the class
assert(toT.isSubtypeOf(fromT) || fromT.isAssignableTo(toT)); Fix for both issues on the way. |
A few other fixes: * inference of generic function expressions now works. It was broken because they ignored type parameters. * fixes subtype of generic functions in the "normal" type system. These types are only possible if generic methods support is enabled, which can be accessed via a flag. The generic methods DEP is designed to work with the normal Dart type system, too, so we try to keep these code paths working. ("normal" type equality for function types already handled this correctly.) This is also needed because strong mode delegates to normal type system for some cases, e.g. to pick warning vs error. * also refactors structural comparison of two generic function types, along the lines of recent changes, so there is less code duplication. This was my original motivation, but reviewing the code led to the discovery of the other issues. * refactors strong_test_helper. The existing way of matching up errors did not work with generic function expressions like: /*<T>*/(x) => x. Simplified it to just look for the right offset. This also exposed a bug in a test -- previously, it was possible to have an error that wasn't validated. [email protected], [email protected] Review URL: https://codereview.chromium.org/1678313002 .
@leafpetersen Re:
Can you give me an example of a failing case? I tried to come up with one and failed (that is, analyzer correctly produces an error for this case), so I'm not sure what needs to be done for it:
|
I think it would happen for generic methods: import 'dart:math';
Point/*<T>*/ f/*<T extends num>*/(num/*=T*/ x, num/*=T*/ y) {
return new Point(x, y);
}
main() {
print(f/*<String>*/('hello', 'world'));
}
If I get rid of the
|
Of course! I'll look into producing the errors. |
Some errors caught by https://codereview.chromium.org/1927103002/. |
I think Brian fixed this. If we see any more issues we can file a new bug. |
Tracking bug for remaining missing warnings to be implemented in the analyzer for generic methods.
(edit by @jmesserly: Check that bounds (on both classes and generic methods) are not themselves generic function types -- moved to #25179)
The text was updated successfully, but these errors were encountered: