Skip to content

Analyzer throws error when try to assign a function result to row variable. #33805

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

Open
iarkh opened this issue Jul 10, 2018 · 6 comments
Open
Labels
legacy-area-front-end Legacy: Use area-dart-model instead. type-bug Incorrect behavior (everything from a crash to more subtle misbehavior)

Comments

@iarkh
Copy link
Contributor

iarkh commented Jul 10, 2018

Dart SDK Version: 2.0.0-dev.55.0
OS: Windows 10

The following code sample assign a parametrized function result to the row variable:

class A<X> {}
X testme<X extends A<X>>() { return null; }
main() {
  A a = testme();
}

Dart and dartanalyzer show different results here: test passes without errors or warnings whereas dartanalyzer throws compiler error:

Analyzing test.dart...
  error - Couldn't infer type parameter 'X'.

Tried to infer 'A<dynamic>' for 'X' which doesn't work:
  Type parameter 'X' declared to extend 'A<A<dynamic>>'.
The type 'A<dynamic>' was inferred from:
  Return type declared as 'X'
              used where  'A<dynamic>' is required.

Consider passing explicit type argument(s) to the generic.

 at test.dart:4:9 - strong_mode_could_not_infer
  hint - The value of the local variable 'a' isn't used at test.dart:4:5 - unused_local_variable
1 error and 1 hint found.

I believe both tools should behave in a similar way.

Seems like A a = testme(); is OK and should pass in both cases.

@lrhn
Copy link
Member

lrhn commented Jul 11, 2018

The code should fail to compile.

The recursive (F-)bound on testme cannot be satisfied by any type in the program, so it is impossible to call testme. Even if there was a type satisfying it, say class D implements A<D>{}, inference cannot guess that. The type argument to the testme function is omitted, so the error becomes an inference error (inference cannot find any type argument X that is also an A).

@iarkh
Copy link
Contributor Author

iarkh commented Jul 11, 2018

Isn't it a superbounded type here?
According instantiate-to-bounds spec, omitting type parameter for class A is the same as A<dynamic> and A<dynamic> is a super-bound for A...

@eernstg
Copy link
Member

eernstg commented Jul 11, 2018

It isn't actually a super-bounded type:

Super-bounded types are concerned with the situation where a type argument list is passed to a generic type (a generic class, a parameterized typedef, or FutureOr), and that type argument list violates the declared bound, but we can "repair" the situation by performing certain substitutions.

In your example we are dealing with a type argument list which is passed in a generic function invocation. So the whole thing (testme<A<dynamic>>()) is not a type, and hence we can't even start to make it a super-bounded type—it just has to satisfy the declared bound. As Lasse mentioned, inference can't solve that challenge.

@iarkh
Copy link
Contributor Author

iarkh commented Jul 11, 2018

Ok, so dart should be fixed in this case.
I observe the same behavior for A<A> a = testme();, A<A<A>> a = testme();, A<A<A<A>>> a = testme();, etc. - just suppose that this is the same issue.

@lrhn
Copy link
Member

lrhn commented Jul 11, 2018

Yes, in all these cases, there is no valid and inferable type argument for testme. Using the RHS type is not sufficient to satisfy the type bound for the function type parameter, and the type bound itself is recursive in a way that prevents inference from using the bound itself as a type.

@lrhn lrhn added type-bug Incorrect behavior (everything from a crash to more subtle misbehavior) legacy-area-front-end Legacy: Use area-dart-model instead. labels Jul 11, 2018
@eernstg
Copy link
Member

eernstg commented Jul 11, 2018

Sounds good! Note also #33815 which is the other way round: It shows that the analyzer complains about a super-bounded type given as a type argument that should be allowed.

However, I forgot one thing: The original example admits the type argument Null:

class A<X> {}
X testme<X extends A<X>>() { return null; }
main() {
  A a = testme<Null>();
}

Now, everybody (that is, dart and dartanalyzer) are happy, as they should be! But even though it works, I think the situations where it's useful are too rare to justify any attempt to teach the inference engine to try to solve F-bounded constraints with Null. ;-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
legacy-area-front-end Legacy: Use area-dart-model instead. type-bug Incorrect behavior (everything from a crash to more subtle misbehavior)
Projects
None yet
Development

No branches or pull requests

3 participants