Skip to content

Commit

Permalink
[cfe] Handle erroneous enum constant values in exhaustiveness
Browse files Browse the repository at this point in the history
Closes #54267

Change-Id: Ic8e86a352725bd35985fbd4685b1c4d446875949
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/345063
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
  • Loading branch information
johnniwinther authored and Commit Queue committed Jan 8, 2024
1 parent 01a2737 commit fa8e34e
Show file tree
Hide file tree
Showing 19 changed files with 861 additions and 2 deletions.
4 changes: 2 additions & 2 deletions pkg/front_end/lib/src/fasta/kernel/exhaustiveness.dart
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ class CfeEnumOperations
}

@override
EnumValue getEnumElementValue(Field enumField) {
EnumValue? getEnumElementValue(Field enumField) {
// Enum field initializers might not have been replaced by
// [ConstantExpression]s. Either because we haven't visited them yet during
// normal constant evaluation or because they are from outlines that are
Expand All @@ -392,7 +392,7 @@ class CfeEnumOperations
StaticTypeContext context =
new StaticTypeContext(enumField, _constantEvaluator.typeEnvironment);
return constantToEnumValue(_constantEvaluator.coreTypes,
_constantEvaluator.evaluate(context, enumField.initializer!))!;
_constantEvaluator.evaluate(context, enumField.initializer!));
}

@override
Expand Down
15 changes: 15 additions & 0 deletions pkg/front_end/testcases/general/issue54267a.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

enum A {
a(0),
b(1),
final int value;
const A(this.value);
}

int fn(A a) => switch (a) {
A.a => 0,
A.b => 1,
};
76 changes: 76 additions & 0 deletions pkg/front_end/testcases/general/issue54267a.dart.strong.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
library;
//
// Problems in library:
//
// pkg/front_end/testcases/general/issue54267a.dart:8:3: Error: Expected an identifier, but got 'final'.
// Try inserting an identifier before 'final'.
// final int value;
// ^^^^^
//
// pkg/front_end/testcases/general/issue54267a.dart:8:3: Error: Expected '}' before this.
// final int value;
// ^^^^^
//
// pkg/front_end/testcases/general/issue54267a.dart:6:4: Error: Too many positional arguments: 2 allowed, but 3 found.
// Try removing the extra positional arguments.
// a(0),
// ^
// pkg/front_end/testcases/general/issue54267a.dart:5:6: Context: The class 'A' has a constructor that takes no arguments.
// enum A {
// ^
//
// pkg/front_end/testcases/general/issue54267a.dart:7:4: Error: Too many positional arguments: 2 allowed, but 3 found.
// Try removing the extra positional arguments.
// b(1),
// ^
// pkg/front_end/testcases/general/issue54267a.dart:5:6: Context: The class 'A' has a constructor that takes no arguments.
// enum A {
// ^
//
import self as self;
import "dart:core" as core;

class A extends core::_Enum /*isEnum*/ {
static const field core::List<self::A> values = invalid-expression "pkg/front_end/testcases/general/issue54267a.dart:6:4: Error: Too many positional arguments: 2 allowed, but 3 found.
Try removing the extra positional arguments.
a(0),
^";
enum-element static const field invalid-type a = invalid-expression "pkg/front_end/testcases/general/issue54267a.dart:6:4: Error: Too many positional arguments: 2 allowed, but 3 found.
Try removing the extra positional arguments.
a(0),
^";
enum-element static const field invalid-type b = invalid-expression "pkg/front_end/testcases/general/issue54267a.dart:7:4: Error: Too many positional arguments: 2 allowed, but 3 found.
Try removing the extra positional arguments.
b(1),
^";
const synthetic constructor •(core::int #index, core::String #name) → self::A
: super core::_Enum::•(#index, #name)
;
method _enumToString() → core::String
return "A.${this.{core::_Enum::_name}{core::String}}";
}
static method fn(self::A a) → core::int
return block {
core::int #t1;
#L1:
switch(a) /* isExplicitlyExhaustive, self::A */ {
#L2:
case invalid-expression "pkg/front_end/testcases/general/issue54267a.dart:6:4: Error: Too many positional arguments: 2 allowed, but 3 found.
Try removing the extra positional arguments.
a(0),
^":
{
#t1 = 0;
break #L1;
}
#L3:
case invalid-expression "pkg/front_end/testcases/general/issue54267a.dart:7:4: Error: Too many positional arguments: 2 allowed, but 3 found.
Try removing the extra positional arguments.
b(1),
^":
{
#t1 = 1;
break #L1;
}
}
} =>#t1;
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
library;
//
// Problems in library:
//
// pkg/front_end/testcases/general/issue54267a.dart:8:3: Error: Expected an identifier, but got 'final'.
// Try inserting an identifier before 'final'.
// final int value;
// ^^^^^
//
// pkg/front_end/testcases/general/issue54267a.dart:8:3: Error: Expected '}' before this.
// final int value;
// ^^^^^
//
// pkg/front_end/testcases/general/issue54267a.dart:6:4: Error: Too many positional arguments: 2 allowed, but 3 found.
// Try removing the extra positional arguments.
// a(0),
// ^
// pkg/front_end/testcases/general/issue54267a.dart:5:6: Context: The class 'A' has a constructor that takes no arguments.
// enum A {
// ^
//
// pkg/front_end/testcases/general/issue54267a.dart:7:4: Error: Too many positional arguments: 2 allowed, but 3 found.
// Try removing the extra positional arguments.
// b(1),
// ^
// pkg/front_end/testcases/general/issue54267a.dart:5:6: Context: The class 'A' has a constructor that takes no arguments.
// enum A {
// ^
//
import self as self;
import "dart:core" as core;

class A extends core::_Enum /*isEnum*/ {
static const field core::List<self::A> values = invalid-expression "pkg/front_end/testcases/general/issue54267a.dart:6:4: Error: Too many positional arguments: 2 allowed, but 3 found.
Try removing the extra positional arguments.
a(0),
^";
enum-element static const field invalid-type a = invalid-expression "pkg/front_end/testcases/general/issue54267a.dart:6:4: Error: Too many positional arguments: 2 allowed, but 3 found.
Try removing the extra positional arguments.
a(0),
^";
enum-element static const field invalid-type b = invalid-expression "pkg/front_end/testcases/general/issue54267a.dart:7:4: Error: Too many positional arguments: 2 allowed, but 3 found.
Try removing the extra positional arguments.
b(1),
^";
const synthetic constructor •(core::int #index, core::String #name) → self::A
: super core::_Enum::•(#index, #name)
;
method _enumToString() → core::String
return "A.${this.{core::_Enum::_name}{core::String}}";
}
static method fn(self::A a) → core::int
return block {
core::int #t1;
#L1:
switch(a) /* isExplicitlyExhaustive, self::A */ {
#L2:
case invalid-expression "pkg/front_end/testcases/general/issue54267a.dart:6:4: Error: Too many positional arguments: 2 allowed, but 3 found.
Try removing the extra positional arguments.
a(0),
^":
{
#t1 = 0;
break #L1;
}
#L3:
case invalid-expression "pkg/front_end/testcases/general/issue54267a.dart:7:4: Error: Too many positional arguments: 2 allowed, but 3 found.
Try removing the extra positional arguments.
b(1),
^":
{
#t1 = 1;
break #L1;
}
}
} =>#t1;
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
enum A { a(0), b(1), final int value; const A(this.value); }
int fn(A a) => switch (a) { A.a => 0, A.b => 1, };
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
enum A { a(0), b(1), final int value; const A(this.value); }
int fn(A a) => switch (a) { A.a => 0, A.b => 1, };
80 changes: 80 additions & 0 deletions pkg/front_end/testcases/general/issue54267a.dart.weak.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
library;
//
// Problems in library:
//
// pkg/front_end/testcases/general/issue54267a.dart:8:3: Error: Expected an identifier, but got 'final'.
// Try inserting an identifier before 'final'.
// final int value;
// ^^^^^
//
// pkg/front_end/testcases/general/issue54267a.dart:8:3: Error: Expected '}' before this.
// final int value;
// ^^^^^
//
// pkg/front_end/testcases/general/issue54267a.dart:6:4: Error: Too many positional arguments: 2 allowed, but 3 found.
// Try removing the extra positional arguments.
// a(0),
// ^
// pkg/front_end/testcases/general/issue54267a.dart:5:6: Context: The class 'A' has a constructor that takes no arguments.
// enum A {
// ^
//
// pkg/front_end/testcases/general/issue54267a.dart:7:4: Error: Too many positional arguments: 2 allowed, but 3 found.
// Try removing the extra positional arguments.
// b(1),
// ^
// pkg/front_end/testcases/general/issue54267a.dart:5:6: Context: The class 'A' has a constructor that takes no arguments.
// enum A {
// ^
//
import self as self;
import "dart:core" as core;
import "dart:_internal" as _in;

class A extends core::_Enum /*isEnum*/ {
static const field core::List<self::A> values = invalid-expression "pkg/front_end/testcases/general/issue54267a.dart:6:4: Error: Too many positional arguments: 2 allowed, but 3 found.
Try removing the extra positional arguments.
a(0),
^";
enum-element static const field invalid-type a = invalid-expression "pkg/front_end/testcases/general/issue54267a.dart:6:4: Error: Too many positional arguments: 2 allowed, but 3 found.
Try removing the extra positional arguments.
a(0),
^";
enum-element static const field invalid-type b = invalid-expression "pkg/front_end/testcases/general/issue54267a.dart:7:4: Error: Too many positional arguments: 2 allowed, but 3 found.
Try removing the extra positional arguments.
b(1),
^";
const synthetic constructor •(core::int #index, core::String #name) → self::A
: super core::_Enum::•(#index, #name)
;
method _enumToString() → core::String
return "A.${this.{core::_Enum::_name}{core::String}}";
}
static method fn(self::A a) → core::int
return block {
core::int #t1;
#L1:
switch(a) /* isExplicitlyExhaustive, self::A */ {
#L2:
case invalid-expression "pkg/front_end/testcases/general/issue54267a.dart:6:4: Error: Too many positional arguments: 2 allowed, but 3 found.
Try removing the extra positional arguments.
a(0),
^":
{
#t1 = 0;
break #L1;
}
#L3:
case invalid-expression "pkg/front_end/testcases/general/issue54267a.dart:7:4: Error: Too many positional arguments: 2 allowed, but 3 found.
Try removing the extra positional arguments.
b(1),
^":
{
#t1 = 1;
break #L1;
}
#L4:
default:
throw new _in::ReachabilityError::•("`null` encountered as case in a switch expression with a non-nullable type.");
}
} =>#t1;
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
library;
//
// Problems in library:
//
// pkg/front_end/testcases/general/issue54267a.dart:8:3: Error: Expected an identifier, but got 'final'.
// Try inserting an identifier before 'final'.
// final int value;
// ^^^^^
//
// pkg/front_end/testcases/general/issue54267a.dart:8:3: Error: Expected '}' before this.
// final int value;
// ^^^^^
//
// pkg/front_end/testcases/general/issue54267a.dart:6:4: Error: Too many positional arguments: 2 allowed, but 3 found.
// Try removing the extra positional arguments.
// a(0),
// ^
// pkg/front_end/testcases/general/issue54267a.dart:5:6: Context: The class 'A' has a constructor that takes no arguments.
// enum A {
// ^
//
// pkg/front_end/testcases/general/issue54267a.dart:7:4: Error: Too many positional arguments: 2 allowed, but 3 found.
// Try removing the extra positional arguments.
// b(1),
// ^
// pkg/front_end/testcases/general/issue54267a.dart:5:6: Context: The class 'A' has a constructor that takes no arguments.
// enum A {
// ^
//
import self as self;
import "dart:core" as core;
import "dart:_internal" as _in;

class A extends core::_Enum /*isEnum*/ {
static const field core::List<self::A> values = invalid-expression "pkg/front_end/testcases/general/issue54267a.dart:6:4: Error: Too many positional arguments: 2 allowed, but 3 found.
Try removing the extra positional arguments.
a(0),
^";
enum-element static const field invalid-type a = invalid-expression "pkg/front_end/testcases/general/issue54267a.dart:6:4: Error: Too many positional arguments: 2 allowed, but 3 found.
Try removing the extra positional arguments.
a(0),
^";
enum-element static const field invalid-type b = invalid-expression "pkg/front_end/testcases/general/issue54267a.dart:7:4: Error: Too many positional arguments: 2 allowed, but 3 found.
Try removing the extra positional arguments.
b(1),
^";
const synthetic constructor •(core::int #index, core::String #name) → self::A
: super core::_Enum::•(#index, #name)
;
method _enumToString() → core::String
return "A.${this.{core::_Enum::_name}{core::String}}";
}
static method fn(self::A a) → core::int
return block {
core::int #t1;
#L1:
switch(a) /* isExplicitlyExhaustive, self::A */ {
#L2:
case invalid-expression "pkg/front_end/testcases/general/issue54267a.dart:6:4: Error: Too many positional arguments: 2 allowed, but 3 found.
Try removing the extra positional arguments.
a(0),
^":
{
#t1 = 0;
break #L1;
}
#L3:
case invalid-expression "pkg/front_end/testcases/general/issue54267a.dart:7:4: Error: Too many positional arguments: 2 allowed, but 3 found.
Try removing the extra positional arguments.
b(1),
^":
{
#t1 = 1;
break #L1;
}
#L4:
default:
throw new _in::ReachabilityError::•("`null` encountered as case in a switch expression with a non-nullable type.");
}
} =>#t1;
Loading

0 comments on commit fa8e34e

Please sign in to comment.