dart-lang / dart-lang/language
Problem: Generated code does not contain Language Version overrides
- Dominant language
- TeX
- Stars
- 2.9k
- Forks
- 239
- Avg merge
- 2d 18h
- Merged PRs (30d)
- 14
Description
According to the [Dart Language Versioning spec](https://github.com/dart-lang/language/blob/master/accepted/future-releases/language-versioning/language-versioning.md), [individual libraries can override](https://github.com/dart-lang/language/blob/master/accepted/future-releases/language-versioning/language-versioning.md#individual-library-language-version-override) the language version specified by the `sdk` minimum constraint in a `pubspec.yaml` file by writing a comment at the top of a file:
```dart
#! /bin/dart
// This library is yadda, yadda, exceptional, yadda.
// @dart = 2.1
library yadda;
```
and, if I am reading it right, under ["Non-`package:` Libraries](https://github.com/dart-lang/language/blob/master/accepted/future-releases/language-versioning/language-versioning.md#non-package-libraries), "Any tool [...] should treat a file in the same pub package as having the same default language level as the actual package files [...]". So this would include _generated_ files, such as files generated by the [**build_runner** package](https://pub.dev/packages/build_runner). This may pose a problem when a version of Dart is released which makes available an experimental flag which interprets a library in a different, breaking way than the previous version.
OK, let's get concrete. Let's say that the NNBD feature first "ships" (meaning the experimental flag is _true_ by default, I think, which enables the SDK constraint and library overrides to dictate NNBD-ness) in Dart 2.5, and a developer working on a package, **foo**, which depends on the [**intl_translation**](https://pub.dev/packages/intl_translation) package. All of the latest versions of **intl_translation** claim to work with the Dart SDK `>=2.0.0-dev.33.0 <3.0.0`, a perfectly sane and advised version range.
1. When the developer had Dart 2.4 installed, and ran `pub get`, version 0.17.4 was locked into their `pubspec.lock` file.
2. Now that the developer has installed Dart 2.5, and is excited to try out NNBD, they run `pub get`, and pub does not automatically try to upgrade **intl_translation** (the current version satisfies all constraints).
3. They do a little `pub run test` before trying NNBD; everything looks good.
4. They change the **foo** package's SDK constraint to be `>=2.5.0 <3.0.0`, which opts-in to NNBD across _all files in their package_.
5. Then they regenerate their **intl_translation** messages with `pub run intl_translation:generate_from_arb ...`, which generates `lib/foo_all_messages.dart`. **This file has no Language Version Override.**
6. They run their tests, which encounter compile-time errors compiling `lib/foo_all_messages.dart`, which may feature code like `String a = null;`.
The [**built_value**](https://pub.dev/packages/built_value) code generator presents a slightly different example: it generates parts of non-generated libraries. The developer of a package which uses **built_value** writes a library like:
```dart
import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';
import 'package:built_collection/built_collection.dart';
part 'person.g.dart';
abstract class Person implements Built { ... }
```
and the **built_value** package generates the `person.g.dart` file via the **build_runner** package. According to the spec,
> Part files cannot be marked, they are always treated the same way as the library they belong to.
which will lead to the same compile-time errors while trying to compile `person.g.dart`. (Even if https://github.com/dart-lang/language/issues/318 is accepted, the part files will be opted-in by default, and when the developer of **foo** tries to override Language Version in `person.dart`, the `person.g.dart` file will not have a `@dart` comment, invalidating the library even earlier.)
### Some Solutions
1. If the authors of **built_value**, **intl_translation**, **angular**, etc. have published packages that generate files with a Language Version override, like `// @dart 2.1`, then the developer can possibly run `pub upgrade` to fix their problem (possibly not, if constraint solving, for some other reason, does not allow the new versions with Language Version overrides). Otherwise, they _thought_ they could experiment with NNBD before their "dependencies" opted-in to NNBD, but they actually cannot, until new packages are published.
2. Features "like NNBD" could ship in major version numbers like 3.0.0. I think that by "like NNBD," I mean features that interpret previously-valid code differently from previous versions of Dart, e.g. if we scrap existing enums for a new enum syntax, or remove `dynamic`, etc.
Actually, only _the first_ feature like NNBD would have to be shipped in a major version like 3.0.0, and after that, all code-generating packages will be shipping code actively opting-in or -out of versions. The problem exists because packages _currently published_ are missing Library Version overrides.
3. Pub package authors could be allowed to _alter_ SDK constraints of _existing_, _published_ packages, rewriting all of their previous SDK constraints to `<2.5.0` instead of `<3.0.0`.
Contributor guide
Research direction
Start with the Dart Language Versioning spec sections on individual library overrides and non-package libraries, then compare the generated-file examples involving build_runner, intl_translation, and built_value. Determine what language-version behavior should apply to generated and part files, and document or implement an agreed solution for the compatibility problem described.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- dart
- Domain
- compilers
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100