Closed iarkh closed 1 month ago
Good catch! ;-) See https://github.com/dart-lang/language/issues/1603 for some thoughts about how to handle this situation.
My proposal for the example in this issue is that it should be allowed to use A()
in a legacy library, because it does not give rise to the creation of a type with a type argument which is a generic function type in the legacy library itself, that type already exists in the opted in library (just like the superclass A<...>
of B
in https://github.com/dart-lang/language/issues/1603), and it is not an error to refer to such a type in a legacy library. But we need to resolve the language issue now, before we can conclude anything about this issue.
I overlooked the fact that there is a set of rules in the 'small-features-21Q1' spec about the treatment of generic function types as type arguments or bounds in legacy libraries.
For A()
as it occurs here, the relevant rule would probably be this one:
It is a compile-time error to use a GFT as a type argument anywhere. This includes: [...] Types produced by expanding references to type aliases into their aliased type.
@lrhn, did you intend this rule to be applicable in the given case (where A
in the instance creation A()
refers to a type alias denoting D<Function<T>()>
)?
I didn't intend it to cover generalized type aliases, since those hadn't landed at the time the text was written. I do think it should cover the situation. There will be no introducing a statically recognizable generic function type as a type argument in a legacy library. no matter how you wrangle the code.
Also, alias expansion should always be equivalent to writing the expanded term directly (if that is valid syntax at all). That includes errors. You should not be able to get around errors by introducing an alias for a type.
To be more concrete: The goal of disallowing legacy libraries from using new language features is to ensure that they can run on old SDKs as is. A program containing only valid pre-2.14 libraries must never be able to introduce a generic function typed type argument. If a legacy library is used in a program where a new language version feature is used, and that causes it to introduce a generic function type as type argument, then that should be fine. The only thing that matters is that legacy libraries by themselves cannot take advantage of the new feature (and therefore break when run on an old SDK).
With that in mind, I'd say that no type argument which is written in a legacy library must be a generic function type. Type aliases are expanded, but if the expansion contains a generic function type argument, that's not a problem. It must have come from the declaration, which is therefore obviously non-legacy. It's only a problem if the expansion itself is a generic function type, and it occurs in a type argument position.
Would that be workable?
@lrhn @eernstg So, what is the position of the language here? Do we accept such programs, or report errors?
co19/LanguageFeatures/Generic-functions-as-type-args/weak/legacy_A02_t02
co19/LanguageFeatures/Generic-functions-as-type-args/weak/legacy_A02_t04
It's surprising that opted_out_lib.dart
is opted in, but said tests are all matched by the following item listing one of the error cases here:
Types produced by expanding references to type aliases into their aliased type
so they should expect an error for each of the lines 42, 47, ... (t_02
) respectively 42, 47, ..., 57 (t_04
).
Closing as stale; we don't support mixed mode any longer.
The following 2.9 dart code imports a non-function type alias with generic function type parameter:
test.dart:
testlib.dart:
Generic functions as type arguments and bounds is a feature which is not supported in the version
2.9
, so dart expectedly throws a compile time error here.Analyzer silently passes here - seems like it should throw a compile error too.
Sample output is: