Language: Use a lower default language version if there is a .packages file

Created on 10 Mar 2020  路  12Comments  路  Source: dart-lang/language

The current spec for language versioning says that if no package_config.json file is found then libraries default to the latest language version supported by the SDK. Since the package_config.json file is itself new, we may find ourselves in this situation:

  1. User upgrades to the latest Dart SDK which supports NNBD.
  2. Since they have not run pub get yet, they have a .packages file, but not package_config.json.
  3. The SDK doesn't see a package_config.json file, so it treats their libraries as all being at the latest version, which is NNBD.
  4. They get tons of errors because their code is now treated as opted in.

This will be less of an issue if we ship pub support for packages_config.json before NNBD. But even then users who skip that SDK version and jump straight to the version that releases NNBD can be in this state.

Should we consider refining the proposal by saying that if there is no packages_config.json file, but there is a .packages file, then use something like 2.7 as the default language version?

@lrhn @leafpetersen @eernstg

cc @sigmundch

question

Most helpful comment

After discussion on the language team, we have decided to treat loading of a .packages file in a language-versioning aware SDK as follows:

  • If the file has name .packages and there is an adjacent .dart_tool/package_config.json, assume that it's the Pub file layout and load the other file instead.
  • Otherwise load the .packages file as an ini file.
  • For each package in the file:

    • If its directory ends in /lib/, assume that it's the Pub package layout and make the parent directory the package root and the lib/ directory to package URI root.

    • Let the package default version be 2.7 (the last version prior to introducing language versioning).

I'll update package:package_config to do this automatically.

All 12 comments

This does not feel like a technical problem, but more like a usability issue.

I don't think it's technically important what we do in the case where there is a .packages and no .package_config.json. That's only going to happen for a short while anyway, so whatever gives the best migration experience should be fine.

If there is no file at all, we do get the most current version. That's desired behavior for people writing new scripts from scratch.
If there is a package_config.json, we get the newest version for files which are not inside a package.

It seems slightly odd to not get the newest language version for files that are not inside a package just because there is a .packages file (potentially empty!), but if we do that, then that includes all files outside of lib in a package. So even if we pick 2.7 for all files in packages configured by a .packages file (which is kind-of reasonable since it's the last version prior to language versioning), we'll still see errors for files not in the lib dir.

Saying "everything is 2.7 if using a .packages file" could make sense. And that would apply no matter how you point to the .packages file or how it's discovered.
That's not something that can be handled by the package_config package because that only addresses files inside packages, it leaves it up to the user to decide for files outside of packages.

Maybe we should just tell people to run pub get if there is a .packages file and no package_config.json file.

I think it's a usability nightmare if installing Dart 2.10 and then doing a pub run suddenly means that you get run with the semantics of a new language version without having done anything to opt-in to that.

Will pub run tell you to run pub get if you're updated your SDK since the last time it was run? I thought it did.

@jonasfj

Will pub run tell you to run pub get if you're updated your SDK since the last time it was run? I thought it did.

I'd argue we need this more broadly and not just for pub run. I assume many users out there use the dart command line tool out of the box without running pub run. For that reason, I expect both the CFE and analyzer would need to handle this scenario properly.

I believe that our tools need to handle the case that there is a .packages and not a package_config.json explicitly anyway, correct? So it seems easy enough to just hard-code a language version for use whenever you have the former and not the latter.

After discussion on the language team, we have decided to treat loading of a .packages file in a language-versioning aware SDK as follows:

  • If the file has name .packages and there is an adjacent .dart_tool/package_config.json, assume that it's the Pub file layout and load the other file instead.
  • Otherwise load the .packages file as an ini file.
  • For each package in the file:

    • If its directory ends in /lib/, assume that it's the Pub package layout and make the parent directory the package root and the lib/ directory to package URI root.

    • Let the package default version be 2.7 (the last version prior to introducing language versioning).

I'll update package:package_config to do this automatically.

Will pub run tell you to run pub get if you're updated your SDK since the last time it was run? I thought it did.

We check that the current SDK is allowed by the resolution in pubspec.lock. I don't think this is exactly the same.

We recently reverted a change where we would reject the package_config.json if it was generated with a different Dart SDK. But this is the best-effort check that only runs if timestamps are out-of-order.


We do ask users to run pub get if they don't have a .dart_tool/package_config.json, we have been doing this since 2.7.0 -- when we added .dart_tool/package_config.json and language versioning.

@lrhn any news on getting package:package_config updated for this?

I have just published version 1.9.2 with the new behavior.

What do we need to do to roll that to the various tools?

I think it should be sufficient to update the DEPS file in the SDK.

I believe this is now fixed in https://github.com/dart-lang/package_config/commit/74c0bbb8283556ad1208c778a20be3684d1c3a9e and https://github.com/dart-lang/sdk/commit/9ef6c1e1a4039076fa0907a2c730dd45038ff749.

Setup

main.dart contains:

void main(List<String> arguments) {
  int n = null;
  print(n);
}

pubspec.yaml contains (note: this doesn't opt-in to null safety>:

name: app1
description: A simple command-line application.

environment:
  sdk: '>=2.7.0 <3.0.0'

Before change :

$ ~/dev/dartsdk/sdk/out/ReleaseX64NNBD/dart-sdk/bin/pub get
Resolving dependencies... 
Got dependencies!

$ ~/dev/dartsdk/sdk/out/ReleaseX64NNBD/dart-sdk/bin/dart --enable-experiment=non-nullable bin/main.dart 
null

$ rm -rf .dart_tool/

$ ~/dev/dartsdk/sdk/out/ReleaseX64NNBD/dart-sdk/bin/dart --enable-experiment=non-nullable bin/main.dart 
bin/main.dart:2:11: Error: A value of type 'Null?' can't be assigned to a variable of type 'int'.
  int n = null;
          ^

After change :

$ ~/dev/sdkrepo/sdk/xcodebuild/ReleaseX64NNBD/dart-sdk/bin/pub get
Resolving dependencies...
Got dependencies!

$ ~/dev/sdkrepo/sdk/xcodebuild/ReleaseX64NNBD/dart-sdk/bin/dart --enable-experiment=non-nullable bin/main.dart
null

$ rm -rf .dart_tool/

$ ~/dev/sdkrepo/sdk/xcodebuild/ReleaseX64NNBD/dart-sdk/bin/dart --enable-experiment=non-nullable bin/main.dart
null
Was this page helpful?
0 / 5 - 0 ratings

Related issues

lrhn picture lrhn  路  4Comments

moneer-muntazah picture moneer-muntazah  路  3Comments

Cat-sushi picture Cat-sushi  路  3Comments

leonsenft picture leonsenft  路  4Comments

creativecreatorormaybenot picture creativecreatorormaybenot  路  3Comments