Skip to content

const_eval_throws_exception error #36511

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

Closed
tvolkert opened this issue Apr 7, 2019 · 8 comments
Closed

const_eval_throws_exception error #36511

tvolkert opened this issue Apr 7, 2019 · 8 comments
Labels
analyzer-constants customer-flutter legacy-area-analyzer Use area-devexp instead. P1 A high priority bug; for example, a single project is unusable or has many test failures type-bug Incorrect behavior (everything from a crash to more subtle misbehavior)
Milestone

Comments

@tvolkert
Copy link
Contributor

tvolkert commented Apr 7, 2019

Consider the work-in-progress changes in flutter/flutter#30646 in which I change Flutter's Row widget to have a const constructor.

In the associated test, I have the following code:

testWidgets('Row is const constructable', (WidgetTester tester) async {
  const Row(
    children: <Widget>[
      Text('Billable Hours'),
    ],
  );
});

When run over that code, the analyzer produces the following error:

  error • Evaluation of this constant expression throws an exception • test/widgets/row_test.dart:32:5 • const_eval_throws_exception

Yet when I run the test, it passes:

$ flutter test test/widgets/row_test.dart 
00:05 +28: All tests passed!                                  
  • Dart VM version: 2.2.1-dev.3.0.flutter-None (Tue Apr 2 13:54:28 2019 +0000) on "macos_x64"
@tvolkert tvolkert added P1 A high priority bug; for example, a single project is unusable or has many test failures legacy-area-analyzer Use area-devexp instead. analyzer-constants customer-flutter type-bug Incorrect behavior (everything from a crash to more subtle misbehavior) labels Apr 7, 2019
@tvolkert
Copy link
Contributor Author

tvolkert commented Apr 7, 2019

/cc @stereotype441 @scheglov

@vsmenon
Copy link
Member

vsmenon commented Apr 8, 2019

Do we know if this is a regression? (2.3 is already past due.)

@stereotype441
Copy link
Member

Found the problem. It is not a regression. Explanation to follow.

@stereotype441
Copy link
Member

Ok, there is an error in @tvolkert's code, which the analyzer successfully detects. Unfortunately, the analyzer does a pretty horrible job of reporting where the error is (which is why I had to spend a few hours this morning sleuthing to even figure it out). To make matters worse, the VM fails to detect the error at all, making it seem like the analyzer is at fault.

The error in @tvolkert's code is located here, in the constructor for the class Flex:

class Flex extends MultiChildRenderObjectWidget {
  const Flex({
    Key key,
    @required this.direction,
    this.mainAxisAlignment = MainAxisAlignment.start,
    this.mainAxisSize = MainAxisSize.max,
    this.crossAxisAlignment = CrossAxisAlignment.center,
    this.textDirection,
    this.verticalDirection = VerticalDirection.down,
    this.textBaseline,
    List<Widget> children = const <Widget>[],
  }) : assert(direction != null),
       assert(mainAxisAlignment != null),
       assert(mainAxisSize != null),
       assert(crossAxisAlignment != null),
       assert(verticalDirection != null),
       assert(crossAxisAlignment != CrossAxisAlignment.baseline || textBaseline != null), // ERROR
       super(key: key, children: children);

The line marked // ERROR is problematic because it attempts to compare two values of type CrossAxisAlignment. You can't do this safely in a const constructor because that assertion has to be able to be evaluated as part of constant evaluation, and constant evaluation won't allow you to do equality comparison on values of non-primitive types. (Note that once "constant update 2018" is enabled, the rules will be relaxed slightly: you'll be able to compare a value of a non-primitive type to null, but you still won't be able to compare two non-primitive values).

The reason the error is being reported at the site of the evaluation of const Row(...) is because Row extends Flex. Unfortunately, the analyzer doesn't report anywhere near enough information to help the user understand what went wrong. It just unhelpfully says that an exception was thrown. I'll file a separate bug report to track that.

The other problem that's happening here is that the VM does not properly detect the bug. It is allowing two enumerated values to be equality compared during constant evaluation without complaint. I'll file a separate bug report to track that.

@stereotype441
Copy link
Member

Ok, I've filed #36526 to track the problem of the analyzer not giving enough information about the location of the error, and #36528 to track the problem of the VM failing to detect the error. Since the analyzer is correct in reporting an error, I'm closing this bug.

@dnfield
Copy link
Contributor

dnfield commented Apr 9, 2019

Is this a case where if we used identical it would work? e.g. !(identical(crossAxisAlignment, CrossAxisAlignment.baseline))?

@stereotype441
Copy link
Member

Is this a case where if we used identical it would work? e.g. !(identical(crossAxisAlignment, CrossAxisAlignment.baseline))?

@dnfield Yes! Sorry, I should have mentioned that. Switching to identical eliminates the error.

@dnfield
Copy link
Contributor

dnfield commented Apr 9, 2019

Thanks! This seems relatedto #29278

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
analyzer-constants customer-flutter legacy-area-analyzer Use area-devexp instead. P1 A high priority bug; for example, a single project is unusable or has many test failures type-bug Incorrect behavior (everything from a crash to more subtle misbehavior)
Projects
None yet
Development

No branches or pull requests

5 participants