Skip to content
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

Dart2js release build may make generic parameters dynamic #41449

Closed
rrousselGit opened this issue Apr 11, 2020 · 34 comments
Closed

Dart2js release build may make generic parameters dynamic #41449

rrousselGit opened this issue Apr 11, 2020 · 34 comments
Assignees
Labels
area-web Use area-web for Dart web related issues, including the DDC and dart2js compilers and JS interop. web-dart2js

Comments

@rrousselGit
Copy link

From rrousselGit/provider#406

@mono0926 found a compilation issue with Dart2js when running:

flutter run -t chrome --release

where the build output behaves differently from debug builds and VM builds.

The issue happens with the following code:

typedef Locator = void Function<T>();

class Bar {
  Bar({this.read}) {
    read<int>();
  }

  final Locator read;
}

void main() {
  Bar(read: <T>() {
    print(T);
    return null;
  });
}

The expected behavior of this code is to print int in the console, which it does in debug builds and VM release builds.
But when running this code with flutter -t chrome --release, this will print dynamic

This causes InheritedWIdgets from Flutter to fail to be resolved

@rrousselGit
Copy link
Author

This was tested on the up-to-date master channel of Flutter (1.18.0-5.0.pre-57), which uses Dart 2.8.0-dev.20.0

@vsmenon vsmenon added area-web Use area-web for Dart web related issues, including the DDC and dart2js compilers and JS interop. web-dart2js labels Apr 13, 2020
@vsmenon
Copy link
Member

vsmenon commented Apr 13, 2020

fyi - @rakudrama @fishythefish

@fishythefish
Copy link
Member

Hmm, looks like we're discarding the type argument in the backend somewhere:

V.main_closure.prototype = {
  call$1$0: function($T) {
    H.printString(H.createRuntimeType($T).toString$0(0));
  },
  call$0: function() {
    return this.call$1$0(type$.dynamic);
  },
  $signature: 0
};

This is the case even if the Bar constructor is simply Bar(this.read); and main itself invokes .read<int>(), but the problem vanishes if the Locator is a local instead of a member.

@rakudrama
Copy link
Member

At the very beginning the SSA code is missing the type argument.
With the command-line option --disable-rti-optimization, it prints int.
The type is probably being dropped on the basis of some 'rti-need' bug.

@sma
Copy link

sma commented Jun 5, 2020

This bug stopps us from release a web app. Is there any workaround other then removing Provider from the whole app?

@fishythefish
Copy link
Member

Taking a deeper look at this now since this is causing NNBD tests to fail.

dart-bot pushed a commit that referenced this issue Jun 24, 2020
function property.

Change-Id: I387977e2f1fb7732d94331b7a97cceeec767aaae
Bug: #41449
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/151301
Reviewed-by: Stephen Adams <sra@google.com>
Commit-Queue: Mayank Patke <fishythefish@google.com>
@whesse
Copy link
Contributor

whesse commented Jun 26, 2020

The fix for this is causing test failures on dartdevc firefox
https://dart-review.googlesource.com/c/sdk/+/151301
introduced failures on firefox:

dartdevk-checked-linux-release-firefox
Pass -> RuntimeError (expected Pass)
✔ language_2/regress/regress22443_test
Timeout -> RuntimeError (expected Pass)
✔ language_2/regress/regress23244_test

@whesse whesse reopened this Jun 26, 2020
@fishythefish
Copy link
Member

@whesse I'm a little confused by that, since this fix only touches pkg/compiler (the dart2js backend, not DDC), and the tests you mentioned don't seem to have anything to do with this issue.

The logs (22443, 23244) are inscrutable to me, so I don't know if this is just flakiness or not. @nshahan, do you know what's going on here?

@nshahan
Copy link
Contributor

nshahan commented Jun 26, 2020

There are parts of the test infrastructure that get compiled by dart2js and then used to run tests for DDC so it is technically possible for a dart2js only change to break a DDC bot but that should appear to be an infra failure.

These failure logs show DDC stack traces so I'm not sure how your change could be the cause. @whesse Is it possible that they are flakes or did we update the version of firefox running on the bots around the same time this change landed?

@whesse
Copy link
Contributor

whesse commented Jun 26, 2020

I checked on it, by looking in the results.json for the build after the one they were reported on.
They were detected to be flaky in that next build, so they stopped being reported on the results feed, and the previous failure was not marked as "superceded" (inactive, replaced by a more recent change).

This failure has happened a number of times before, and confuses everyone and wastes their time.
The fix is to report a change in flaky status to the results feed, and mark earlier failures on now flaky tests as inactive.
I see now that fixing this is urgent, because it wastes so many users' time when it happens.
dart-lang/dart_ci#98

@whesse whesse closed this as completed Jun 26, 2020
@matthewtsmith
Copy link

I'm not sure when this will be available in the beta channel but for those using StateNotifier/Provider/LocatorMixin who need a workaround I was able to solve it by using the following:

  Repository get repository {
    var reader = read;
    return reader();
  }

As this comment mentions, making read a local var seems to resolve the issue.

@rrousselGit
Copy link
Author

rrousselGit commented Jul 12, 2020

I'm not sure why this is closed as the bug is still happening on the latest version of Dart/Flutter

Dart SDK version: 2.9.0-21.0.dev.flutter-06cb010247 (be) (Tue Jul 7 08:14:51 2020 +0000) on "macos_x64"

@fishythefish
Copy link
Member

My apologies - I closed the issue when my fix landed and our tests started passing, but it looks like there's still another bug lurking around when --omit-implicit-checks is passed. I'll add another test and investigate.

@fishythefish fishythefish reopened this Jul 13, 2020
@fishythefish
Copy link
Member

The initial fix for this was pretty quick, but revealed a deeper issue causing other tests (mainly async ones) to fail. I have a more complete fix that I'm working on landing now.

@ochmist
Copy link

ochmist commented Aug 13, 2020

Hello guys, any news on this? This is blocking us from releasing a web app on:

Flutter (Channel master, 1.21.0-10.0.pre.18, on Mac OS X 10.15.6 19G73, locale en-US)

Thanks in advance.

@sigmundch
Copy link
Member

HI @ochmist - the fix landed in 5671730, which is part of Dart's 2.10.0-1.0.dev release and newer releases.

I am not sure on which flutter release this version was rolled into. When I try flutter doctor -v, I see already a newer version of the Dart sdk in the master channel:

[✓] Flutter (Channel master, 1.21.0-10.0.pre.41, on Linux, locale en_US.UTF-8)
    • Flutter version 1.21.0-10.0.pre.41 at /usr/local/google/home/sigmund/dart/flutter/flutter
    • Framework revision 49fac9a885 (2 days ago), 2020-08-11 11:44:03 -0700
    • Engine revision 9b4ce4e3a0
    • Dart version 2.10.0 (build 2.10.0-11.0.dev)

So the fix should be there. Is the Dart version in your case further behind? Is this resolved after upgrading to the latest flutter?

@ochmist
Copy link

ochmist commented Aug 14, 2020

Hi @sigmundch, Confirmed that this works well after flutter upgrade. Thank you very much.

@venkatd
Copy link

venkatd commented Aug 25, 2020

@ochmist what flutter version is working for you (flutter doctor result)? We are also using StateNotifier and our web app is crashing due to this bug.Thanks!

@matthewtsmith could you please elaborate on the change you made? I wasn't able to understand the suggestion and how to apply it to our code.

@ochmist
Copy link

ochmist commented Aug 26, 2020

Actually, after the upgrade it ended up working for a while but breaking soon after. I noticed that once of my dependencies was still outdated and the crash was happening in there.

@fishythefish
Copy link
Member

To clarify, do you have a repro that still fails with the latest SDK, or is this just a toolchain issue?

@takeru
Copy link

takeru commented Nov 11, 2020

I tried flutter web + riverpod.

This code doesn't work.

final xxxxProvider = StateNotifierProvider.autoDispose.family<FooController, Bar>((ref, foo) {

Then, I built without minify. https://stackoverflow.com/questions/59710360

flutter build web --profile --dart-define=Dart2jsOptimization=O0

I can see this log in chrome console.

Uncaught TypeError: Instance of 'AutoDisposeProviderElement<StateNotifier<dynamic>, StateNotifier<dynamic>>': type 'AutoDisposeProviderElement<StateNotifier<dynamic>, StateNotifier<dynamic>>' is not a subtype of type 'ProviderElement<Object, FooController>'

But this workaround saved me.
rrousselGit/riverpod@5d6d1b1#diff-d98faf2ba46cc2fa0f6e56d1bf216afe6b380aabc34ba3b4f74ae7d83cecb52fR36

final $family = StateNotifierProvider.autoDispose.family;
final xxxxProvider = $family<FooController, Bar>((ref, foo) {

@creativecreatorormaybenot
Copy link
Contributor

@fishythefish Can you confirm that this is fixed in the latest SDK?

Seems like it is not (from what @ochmist & @takeru reported). Also, we are still experiencing this issue as well.

@creativecreatorormaybenot
Copy link
Contributor

(still happens in 2.12.0-133.2.beta)

@fishythefish
Copy link
Member

@creativecreatorormaybenot Sorry, I missed this notification earlier. I can't reproduce this issue in the latest SDK when I compile the original example. Do you have a different minimal repro that continues to fail? (I don't work on flutter, so the less flutter-specific, the easier it is for me.)

@creativecreatorormaybenot
Copy link
Contributor

@fishythefish Using riverpod (Dart library):

final providerFamily = StateNotifierProvider.autoDispose.family<Foo, Params>((ref, params) {
  return Foo();
});

class Foo extends StateNotifier<int> {
  Foo(): super(0);
}

class Params {}

void main() {
  final container = ProviderContainer();

  container.listen(providerFamily); // crashes
}

Fixed by:

final _family = StateNotifierProvider.autoDispose.family;
final providerFamily =
    _family<Foo, Params>((ref, params) {
  return Foo();
});

// ...

I do not have the time to test it right now. This is a simplified version of what we have in our app, so if the bug depends on some kind of edge case, it might not reproduce it, however, I think it should do so. Let me know if you have any problems reproducing the bug, then I will get back to you later with a fully tested one - I simply wanted to shoot this one at you in order to help asap.

@fishythefish
Copy link
Member

container doesn't have a ref getter, so I can't compile this code.

@rrousselGit
Copy link
Author

rrousselGit commented Jan 12, 2021

container.listen(providerFamily) should crash

Alternatively you can do:

final providerFamily = StateNotifierProvider.autoDispose.family<Foo, Params>((ref, params) {
  return Foo();
});

final refProvider = Provider((ref) => ref);

void main() {
  final container = ProviderContainer();

  final ref = container.read(refProvider);

 ref.watch(providerFamily);
}

which should crash too

@fishythefish
Copy link
Member

Both your examples seem to be unrelated to this issue - I'm getting a compile-time type error in each case, not a runtime error or crash due to dart2js. (Both the common front-end to the compiler and dart analyzer report this).

@creativecreatorormaybenot
Copy link
Contributor

@fishythefish Sorry for posting the code prior to testing it - I thought it would be helpful and that the concept would be enough. Here are the full steps for reproducing the bug:

  • Dart SDK version: 2.12.0-133.2.beta (beta)
  • dart create -t web-simple bug
  • Add a riverpod: 0.12.1 dependency
  • Edit web/main.dart to be the following:
import 'package:riverpod/riverpod.dart';

final providerFamily = StateNotifierProvider.autoDispose.family<Foo, Params>((ref, params) {
  return Foo();
});

class Foo extends StateNotifier<int> {
  Foo(): super(0);
}

class Params {}

void main() {
  final container = ProviderContainer();
  container.listen(providerFamily(Params())); // crashes in dart2js only
  print('console.log');
}
  • webdev serve & run on localhost - succeeds ("console.log" in the JS console in dev tools)
  • webdev build & cd build & http-server & run on localhost - fails (error in the JS console)
Uncaught Error: undefined
    a http://localhost:8080/main.dart.js:141
    dI http://localhost:8080/main.dart.js:533
    f_ http://localhost:8080/main.dart.js:532
    f1 http://localhost:8080/main.dart.js:507
    $2$1 http://localhost:8080/main.dart.js:2649
    $1 http://localhost:8080/main.dart.js:2650
    b9 http://localhost:8080/main.dart.js:2644
    <anonymous> http://localhost:8080/main.dart.js:3016
    c http://localhost:8080/main.dart.js:27
    dY http://localhost:8080/main.dart.js:1638
    <anonymous> http://localhost:8080/main.dart.js:3025
    <anonymous> http://localhost:8080/main.dart.js:3020
    dartProgram http://localhost:8080/main.dart.js:3023
    <anonymous> http://localhost:8080/main.dart.js:3025
main.dart.js:141:3

@fishythefish
Copy link
Member

Thanks for your patience, @creativecreatorormaybenot. It does look like we're performing an incorrect RTI optimization somewhere and erasing needed type variables. I'm reopening the issue and will investigate when I get a chance.

@fishythefish fishythefish reopened this Jan 13, 2021
@fishythefish fishythefish self-assigned this Feb 8, 2021
dart-bot pushed a commit that referenced this issue Feb 8, 2021
Bug: #41449
Change-Id: I5526d3f6d15945bdf2ba0f790e1c803471b139c6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/183120
Reviewed-by: Stephen Adams <sra@google.com>
@fishythefish
Copy link
Member

Turns out it was the same issue as before with essentially the same fix, but dart2js needed to do some additional work to properly track call methods. The fix is landed in the SDK, although I'm not sure when it'll roll into Flutter. Please let me know if you continue to see this bug arise.

@enyo
Copy link

enyo commented Jun 9, 2021

@fishythefish just upgraded from flutter 2.0.2 to 2.2.1 and am still getting the same error.

EDIT: Oops! I'm sorry. It was actually an annoying cloudfare cache that prevent the update from loading. 2.2.1 does not have this issue anymore 🥳

@venkatd
Copy link

venkatd commented Jul 9, 2021

@fishythefish thanks for resolving this. How do I get the fix? If I set my Dart version constraints to >= 2.13 would that resolve it?

@fishythefish
Copy link
Member

fishythefish commented Jul 9, 2021

@venkatd Yes, Dart 2.13 should have all the fixes in it. On the Flutter side, I believe this means 2.2 or higher should have the fix as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-web Use area-web for Dart web related issues, including the DDC and dart2js compilers and JS interop. web-dart2js
Projects
None yet
Development

No branches or pull requests