diff --git a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart index f218fb4231b..5d9289db0d8 100644 --- a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart +++ b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart @@ -2631,6 +2631,11 @@ class ConstantEvaluator implements ExpressionVisitor { /// Execute a function body using the [StatementConstantEvaluator]. Constant executeBody(Statement statement) { + if (!enableConstFunctions && !inExtensionTypeConstConstructor) { + throw new UnsupportedError("Statement evaluation is only supported when " + "in extension type const constructors or when the const functions " + "feature is enabled."); + } StatementConstantEvaluator statementEvaluator = new StatementConstantEvaluator(this); ExecutionStatus status = statement.accept(statementEvaluator); @@ -2657,6 +2662,11 @@ class ConstantEvaluator implements ExpressionVisitor { /// Returns [null] on success and an error-"constant" on failure, as such the /// return value should be checked. AbortConstant? executeConstructorBody(Constructor constructor) { + if (!enableConstFunctions && !inExtensionTypeConstConstructor) { + throw new UnsupportedError("Statement evaluation is only supported when " + "in extension type const constructors or when the const functions " + "feature is enabled."); + } final Statement body = constructor.function.body!; StatementConstantEvaluator statementEvaluator = new StatementConstantEvaluator(this); @@ -5477,14 +5487,7 @@ class ConstantEvaluator implements ExpressionVisitor { class StatementConstantEvaluator implements StatementVisitor { ConstantEvaluator exprEvaluator; - StatementConstantEvaluator(this.exprEvaluator) { - if (!exprEvaluator.enableConstFunctions && - !exprEvaluator.inExtensionTypeConstConstructor) { - throw new UnsupportedError("Statement evaluation is only supported when " - "in inline class const constructors or when the const functions " - "feature is enabled."); - } - } + StatementConstantEvaluator(this.exprEvaluator); /// Evaluate the expression using the [ConstantEvaluator]. Constant evaluate(Expression expr) => expr.accept(exprEvaluator); diff --git a/pkg/vm/lib/transformations/unreachable_code_elimination.dart b/pkg/vm/lib/transformations/unreachable_code_elimination.dart index 4eb51030749..f53f574e9bf 100644 --- a/pkg/vm/lib/transformations/unreachable_code_elimination.dart +++ b/pkg/vm/lib/transformations/unreachable_code_elimination.dart @@ -36,25 +36,32 @@ class SimpleUnreachableCodeElimination extends RemovingTransformer { return result; } - bool _isBoolConstant(Expression node) => - node is BoolLiteral || - (node is ConstantExpression && node.constant is BoolConstant); - - bool _getBoolConstantValue(Expression node) { - if (node is BoolLiteral) { - return node.value; - } - if (node is ConstantExpression) { - final constant = node.constant; - if (constant is BoolConstant) { - return constant.value; - } - } - throw 'Expected bool constant: $node'; + bool? _getBoolConstantValue(Expression node) { + if (node is BoolLiteral) return node.value; + if (node is! ConstantExpression) return null; + final constant = node.constant; + return constant is BoolConstant ? constant.value : null; } - Expression _createBoolLiteral(bool value, int fileOffset) => - new BoolLiteral(value)..fileOffset = fileOffset; + Expression _makeConstantExpression(Constant constant, Expression node) { + if (constant is UnevaluatedConstant && + constant.expression is InvalidExpression) { + return constant.expression; + } + ConstantExpression constantExpression = new ConstantExpression( + constant, node.getStaticType(_staticTypeContext!)) + ..fileOffset = node.fileOffset; + if (node is FileUriExpression) { + return new FileUriConstantExpression(constantExpression.constant, + type: constantExpression.type, fileUri: node.fileUri) + ..fileOffset = node.fileOffset; + } + return constantExpression; + } + + Expression _createBoolConstantExpression(bool value, Expression node) => + _makeConstantExpression( + constantEvaluator.canonicalize(BoolConstant(value)), node); Statement _makeEmptyBlockIfEmptyStatement(Statement node, TreeNode parent) => node is EmptyStatement ? (Block([])..parent = parent) : node; @@ -63,8 +70,8 @@ class SimpleUnreachableCodeElimination extends RemovingTransformer { TreeNode visitIfStatement(IfStatement node, TreeNode? removalSentinel) { node.transformOrRemoveChildren(this); final condition = node.condition; - if (_isBoolConstant(condition)) { - final value = _getBoolConstantValue(condition); + final value = _getBoolConstantValue(condition); + if (value != null) { return value ? node.then : (node.otherwise ?? removalSentinel ?? new EmptyStatement()); @@ -78,8 +85,8 @@ class SimpleUnreachableCodeElimination extends RemovingTransformer { ConditionalExpression node, TreeNode? removalSentinel) { node.transformOrRemoveChildren(this); final condition = node.condition; - if (_isBoolConstant(condition)) { - final value = _getBoolConstantValue(condition); + final value = _getBoolConstantValue(condition); + if (value != null) { return value ? node.then : node.otherwise; } return node; @@ -89,9 +96,9 @@ class SimpleUnreachableCodeElimination extends RemovingTransformer { TreeNode visitNot(Not node, TreeNode? removalSentinel) { node.transformOrRemoveChildren(this); final operand = node.operand; - if (_isBoolConstant(operand)) { - return _createBoolLiteral( - !_getBoolConstantValue(operand), node.fileOffset); + final value = _getBoolConstantValue(operand); + if (value != null) { + return _createBoolConstantExpression(!value, node); } return node; } @@ -100,47 +107,111 @@ class SimpleUnreachableCodeElimination extends RemovingTransformer { TreeNode visitLogicalExpression( LogicalExpression node, TreeNode? removalSentinel) { node.transformOrRemoveChildren(this); - final left = node.left; - final right = node.right; - final operatorEnum = node.operatorEnum; - if (_isBoolConstant(left)) { - final leftValue = _getBoolConstantValue(left); - if (_isBoolConstant(right)) { - final rightValue = _getBoolConstantValue(right); - if (operatorEnum == LogicalExpressionOperator.OR) { - return _createBoolLiteral(leftValue || rightValue, node.fileOffset); - } else if (operatorEnum == LogicalExpressionOperator.AND) { - return _createBoolLiteral(leftValue && rightValue, node.fileOffset); - } else { - throw 'Unexpected LogicalExpression operator ${operatorEnum}: $node'; - } - } else { - if (leftValue && operatorEnum == LogicalExpressionOperator.OR) { - return _createBoolLiteral(true, node.fileOffset); - } else if (!leftValue && - operatorEnum == LogicalExpressionOperator.AND) { - return _createBoolLiteral(false, node.fileOffset); + bool? value = _getBoolConstantValue(node.left); + // Because of short-circuiting, these operators cannot be treated as + // symmetric, so a non-constant left and a constant right is left as-is. + if (value == null) return node; + switch (node.operatorEnum) { + case LogicalExpressionOperator.OR: + return value ? node.left : node.right; + case LogicalExpressionOperator.AND: + return value ? node.right : node.left; + } + } + + @override + TreeNode visitSwitchStatement( + SwitchStatement node, TreeNode? removalSentinel) { + node.transformOrRemoveChildren(this); + final tested = node.expression; + if (tested is! ConstantExpression) return node; + + // First, keep any reachable case. As a side effect, any expressions that + // cannot match in the SwitchCases are removed. An expression cannot match + // if it is a non-matching constant expression or it follows a constant + // expression that is guaranteed to match. + final toKeep = {}; + bool foundMatchingCase = false; + for (final c in node.cases) { + if (foundMatchingCase) { + c.expressions.clear(); + continue; + } + c.expressions.retainWhere((e) { + if (foundMatchingCase) return false; + if (e is! ConstantExpression) return true; + foundMatchingCase = e.constant == tested.constant; + return foundMatchingCase; + }); + if (c.isDefault || c.expressions.isNotEmpty) { + toKeep.add(c); + } + } + + if (toKeep.isEmpty) { + if (node.isExhaustive) { + throw 'Expected at least one kept case from exhaustive switch: $node'; + } + return removalSentinel ?? new EmptyStatement(); + } + + // Now iteratively find additional cases to keep by following targets of + // continue statements in kept cases. + final worklist = [...toKeep]; + final collector = ContinueSwitchStatementTargetCollector(node); + while (worklist.isNotEmpty) { + final next = worklist.removeLast(); + final targets = collector.collectTargets(next); + for (final target in targets) { + if (toKeep.add(target)) { + worklist.add(target); } } } + + // Finally, remove any cases not marked for keeping. If only one case + // is kept, then the switch statement can be replaced with its body. + if (toKeep.length == 1) { + return toKeep.first.body; + } + node.cases.retainWhere(toKeep.contains); + if (foundMatchingCase && !node.hasDefault) { + // While the expression may not be explicitly exhaustive for the type + // of the tested expression, it is guaranteed to execute at least one + // of the remaining cases, so the backends don't need to handle the case + // where no listed case is hit for this switch. + // + // If the original program has the matching case directly falls through + // to the default case for some reason: + // + // switch (4) { + // ... + // case 4: + // default: + // ... + // } + // + // this means the default case is kept despite finding a guaranteed to + // match expression, as it contains that matching expression. If that + // happens, then we don't do this, to keep the invariant that + // isExplicitlyExhaustive is false if there is a default case. + node.isExplicitlyExhaustive = true; + } return node; } @override - visitStaticGet(StaticGet node, TreeNode? removalSentinel) { + TreeNode visitStaticGet(StaticGet node, TreeNode? removalSentinel) { node.transformOrRemoveChildren(this); final target = node.target; if (target is Field && target.isConst) { throw 'StaticGet from const field $target should be evaluated by front-end: $node'; } - if (constantEvaluator.transformerShouldEvaluateExpression(node)) { - final context = _staticTypeContext!; - final result = constantEvaluator.evaluate(context, node); - assert(result is! UnevaluatedConstant); - return new ConstantExpression(result, node.getStaticType(context)) - ..fileOffset = node.fileOffset; + if (!constantEvaluator.transformerShouldEvaluateExpression(node)) { + return node; } - return node; + final result = constantEvaluator.evaluate(_staticTypeContext!, node); + return _makeConstantExpression(result, node); } @override @@ -235,3 +306,25 @@ class SimpleUnreachableCodeElimination extends RemovingTransformer { return node; } } + +class ContinueSwitchStatementTargetCollector extends RecursiveVisitor { + final SwitchStatement parent; + late Set collected; + + ContinueSwitchStatementTargetCollector(this.parent); + + Set collectTargets(SwitchCase node) { + collected = {}; + node.accept(this); + return collected; + } + + @override + void visitContinueSwitchStatement(ContinueSwitchStatement node) { + node.visitChildren(this); + // Only keep targets that are within the original node being checked. + if (node.target.parent == parent) { + collected.add(node.target); + } + } +} diff --git a/pkg/vm/lib/transformations/vm_constant_evaluator.dart b/pkg/vm/lib/transformations/vm_constant_evaluator.dart index d563a0fddeb..63ab64ea12b 100644 --- a/pkg/vm/lib/transformations/vm_constant_evaluator.dart +++ b/pkg/vm/lib/transformations/vm_constant_evaluator.dart @@ -13,10 +13,14 @@ import 'package:front_end/src/base/nnbd_mode.dart'; import 'package:front_end/src/fasta/kernel/constant_evaluator.dart' show AbortConstant, + AbortStatus, ConstantEvaluator, ErrorReporter, EvaluationMode, - SimpleErrorReporter; + ProceedStatus, + ReturnStatus, + SimpleErrorReporter, + StatementConstantEvaluator; import '../target_os.dart'; @@ -26,8 +30,10 @@ import '../target_os.dart'; /// [targetOS] represents the target operating system and is used when /// evaluating static fields and getters annotated with "vm:platform-const". /// -/// If [enableConstFunctions] is false, then only getters that return the -/// result of a single expression can be evaluated. +/// To avoid restricting getters annotated with "vm:platform-const" to be just +/// a single return statement whose body is evaluated, we treat annotated +/// getters as const functions. If [enableConstFunctions] is false, then +/// only annotated getters are treated this way. class VMConstantEvaluator extends ConstantEvaluator { final TargetOS? _targetOS; final Map _constantFields = {}; @@ -124,6 +130,19 @@ class VMConstantEvaluator extends ConstantEvaluator { bool transformerShouldEvaluateExpression(Expression node) => _targetOS != null && node is StaticGet && _isPlatformConst(node.target); + Constant _executePlatformConstBody(Statement statement) { + final status = statement.accept(StatementConstantEvaluator(this)); + if (status is AbortStatus) return status.error; + // Happens if there is no return statement in a void Function(...) body. + if (status is ProceedStatus) return canonicalize(NullConstant()); + if (status is ReturnStatus) { + final value = status.value; + return value != null ? value : canonicalize(NullConstant()); + } + // Other statuses denote intermediate states and not final ones. + throw 'No valid constant returned after executing $statement'; + } + @override Constant visitStaticGet(StaticGet node) { assert(_targetOS != null); @@ -153,20 +172,7 @@ class VMConstantEvaluator extends ConstantEvaluator { result = evaluateExpressionInContext(target, target.initializer!); } else if (target is Procedure && target.isGetter) { final body = target.function.body!; - // If const functions are enabled, execute the getter as if it were - // a const function. Otherwise the annotated getter must be a single - // return statement whose expression is evaluated. - if (enableConstFunctions) { - result = executeBody(body); - } else if (body is ReturnStatement) { - if (body.expression == null) { - return canonicalize(NullConstant()); - } - result = evaluateExpressionInContext(target, body.expression!); - } else { - throw "Cannot evaluate method '$nameText' since it contains more " - "than a single return statement."; - } + result = _executePlatformConstBody(body); } if (result is AbortConstant) { throw "The body or initialization of member '$nameText' does not " diff --git a/pkg/vm/testcases/transformations/unreachable_code_elimination/uce_testcases.dart b/pkg/vm/testcases/transformations/unreachable_code_elimination/uce_testcases.dart index 33f4458841a..e8b04e2d632 100644 --- a/pkg/vm/testcases/transformations/unreachable_code_elimination/uce_testcases.dart +++ b/pkg/vm/testcases/transformations/unreachable_code_elimination/uce_testcases.dart @@ -9,6 +9,8 @@ const bool constFalse2 = const bool.fromEnvironment('test.define.notDefined'); bool? foo() => null; +Never throws() => throw 'oops'; + void testSimpleConditions() { if (constTrue) { print('1_yes'); @@ -37,6 +39,12 @@ void testAndConditions() { if (constTrue && constTrue && constFalse) { print('4_no'); } + if (throws() && constTrue) { + print('5_calls_throw'); + } + if (throws() && constFalse) { + print('6_calls_throw'); + } } void testOrConditions() { @@ -52,6 +60,12 @@ void testOrConditions() { if (constFalse || !constTrue || constTrue2) { print('4_yes'); } + if (throws() || constTrue) { + print('5_calls_throw'); + } + if (throws() || constFalse) { + print('6_calls_throw'); + } } void testNotConditions() { @@ -112,6 +126,287 @@ testRemovalOfStatementBodies() { } } +enum TestPlatform { + linux, + macos, + windows, +} + +const switchTestString = "noMatch"; +const switchTestInt = 23; + +testConstantSwitches() { + switch (constTrue) { + case true: + print('1_yes'); + break; + case false: + print('2_no'); + break; + } + switch (constFalse) { + case true: + print('3_yes'); + break; + default: + print('4_not_yes'); + } + switch (TestPlatform.windows) { + case TestPlatform.linux: + print("5_linux"); + break; + case TestPlatform.macos: + print("6_macos"); + break; + case TestPlatform.windows: + print("7_windows"); + break; + } + switch (TestPlatform.macos) { + case TestPlatform.linux: + case TestPlatform.macos: + print("8_not_windows"); + break; + case TestPlatform.windows: + print("9_windows"); + break; + } + switch (TestPlatform.linux) { + case TestPlatform.linux: + continue L1_macos; + L1_macos: + case TestPlatform.macos: + print("10_not_windows"); + break; + case TestPlatform.windows: + print("11_windows"); + break; + } + switch (TestPlatform.windows) { + case TestPlatform.linux: + print("12_linux"); + break; + case TestPlatform.macos: + print("13_macos"); + break; + default: + print("14_default"); + } + switch (TestPlatform.windows) { + case TestPlatform.linux: + print("15_linux"); + break; + case TestPlatform.macos: + print("16_macos"); + break; + case TestPlatform.windows: + continue L2_default; + L2_default: + default: + print("17_default"); + } + // Not explicitly exhaustive as is because there's a default, but once UCE + // is run, the resulting switch should be explicitly exhaustive, as the + // default is removed but we're still guaranteed that a case will be matched. + switch (TestPlatform.macos) { + L3_linux: + case TestPlatform.linux: + print("18_notwindows"); + break; + case TestPlatform.macos: + continue L3_linux; + case TestPlatform.windows: + print("19_windows"); + break; + default: + print("20_default"); + } + // Also should be explicitly exhaustive post-UCE, for the reason above. + switch (TestPlatform.macos) { + L4_linux: + case TestPlatform.linux: + print("21_notwindows"); + break; + case TestPlatform.macos: + if (foo()!) { + continue L4_linux; + } + break; + case TestPlatform.windows: + print("22_windows"); + break; + default: + print("23_default"); + } + switch (switchTestString) { + case "isMatch": + print("24_isMatch"); + break; + case "isNotMatch": + print("25_isNotMatch"); + break; + default: + print("26_default"); + } + switch (switchTestString) { + case "isMatch": + print("27_isMatch"); + break; + L5_isNotMatch: + case "isNotMatch": + print("28_isNotMatch"); + break; + default: + continue L5_isNotMatch; + } + switch (switchTestInt) { + case 0: + print("29_zero"); + break; + case 1: + print("30_one"); + break; + default: + print("31_default"); + } + switch (switchTestInt) { + case 0: + print("32_zero"); + break; + case 23: + print("33_twentythree"); + break; + default: + print("34_default"); + } + switch (switchTestString) { + case "foo": + switch (switchTestInt) { + case 0: + print("35_foo_zero"); + break; + default: + print("36_foo_nonzero"); + } + break; + default: + switch (switchTestInt) { + case 1: + print("37_default_one"); + break; + default: + print("38_default_default"); + } + } + switch (switchTestString) { + L6_foo: + case "foo": + switch (switchTestInt) { + case 0: + print("39_foo_zero"); + break; + default: + print("40_foo_nonzero"); + } + break; + default: + switch (switchTestInt) { + case 1: + print("41_default_one"); + break; + default: + continue L6_foo; + } + } + switch (switchTestString) { + case "foo": + switch (switchTestInt) { + case 0: + continue L7_default; + default: + print("42_foo_nonzero"); + } + break; + L7_default: + default: + switch (switchTestInt) { + case 23: + print("43_default_twentythree"); + break; + default: + print("44_default_default"); + } + } + switch (switchTestString) { + L8_foo: + case "foo": + switch (switchTestInt) { + case 23: + continue L9_default; + default: + print("45_foo_nontwentythree"); + } + break; + L9_default: + default: + switch (switchTestInt) { + case 23: + print("46_default_twentythree"); + break; + default: + continue L8_foo; + } + } + switch (switchTestString) { + L10_foo: + case "foo": + switch (switchTestInt) { + case 23: + continue L11_default; + default: + print("47_foo_nontwentythree"); + } + break; + L11_default: + default: + switch (switchTestInt) { + case 0: + print("48_default_zero"); + break; + default: + continue L10_foo; + } + } + switch (switchTestInt) { + case 23: + print("49_twentythree"); + } + switch (switchTestInt) { + case 0: + print("50_zero"); + } + switch (switchTestInt) { + case 0: + print("51_zero"); + break; + case 23: + default: + print("52_23_and_default"); + } + // Should not be marked as isExplicitlyExhaustive, as the case that has the + // matching constant is also the default. + switch (switchTestInt) { + L12_zero: + case 0: + print("51_zero"); + break; + case 23: + default: + print("52_23_and_default"); + continue L12_zero; + } +} + main(List args) { testSimpleConditions(); testAndConditions(); diff --git a/pkg/vm/testcases/transformations/unreachable_code_elimination/uce_testcases.dart.expect b/pkg/vm/testcases/transformations/unreachable_code_elimination/uce_testcases.dart.expect index b09c0e218a4..50cf34dc08f 100644 --- a/pkg/vm/testcases/transformations/unreachable_code_elimination/uce_testcases.dart.expect +++ b/pkg/vm/testcases/transformations/unreachable_code_elimination/uce_testcases.dart.expect @@ -6,12 +6,27 @@ class TestAssertInitializer extends core::Object { constructor •() → self::TestAssertInitializer : super core::Object::•() {} } -static const field core::bool constTrue = #C1; -static const field core::bool constFalse = #C2; -static const field core::bool constTrue2 = #C1; -static const field core::bool constFalse2 = #C2; +class TestPlatform extends core::_Enum /*isEnum*/ { + static const field core::List values = #C10; + enum-element static const field self::TestPlatform linux = #C3; + enum-element static const field self::TestPlatform macos = #C6; + enum-element static const field self::TestPlatform windows = #C9; + const synthetic constructor •(core::int #index, core::String #name) → self::TestPlatform + : super core::_Enum::•(#index, #name) + ; + method _enumToString() → core::String + return "TestPlatform.${this.{core::_Enum::_name}{core::String}}"; +} +static const field core::bool constTrue = #C11; +static const field core::bool constFalse = #C12; +static const field core::bool constTrue2 = #C11; +static const field core::bool constFalse2 = #C12; +static const field core::String switchTestString = #C13; +static const field core::int switchTestInt = #C14; static method foo() → core::bool? return null; +static method throws() → Never + return throw "oops"; static method testSimpleConditions() → void { { core::print("1_yes"); @@ -21,20 +36,32 @@ static method testSimpleConditions() → void { } } static method testAndConditions() → void { - if(#C1 && self::foo()!) { + if(self::foo()!) { core::print("1_yes"); } + if(self::throws() && #C11) { + core::print("5_calls_throw"); + } + if(self::throws() && #C12) { + core::print("6_calls_throw"); + } } static method testOrConditions() → void { { core::print("1_yes"); } - if(#C2 || self::foo()!) { + if(self::foo()!) { core::print("2_yes"); } { core::print("4_yes"); } + if(self::throws() || #C11) { + core::print("5_calls_throw"); + } + if(self::throws() || #C12) { + core::print("6_calls_throw"); + } } static method testNotConditions() → void { { @@ -71,7 +98,7 @@ static method testRemovalOfStatementBodies() → dynamic { #L1: switch(42) /* core::int */ { #L2: - case #C3: + case #C15: {} } #L3: @@ -81,6 +108,198 @@ static method testRemovalOfStatementBodies() → dynamic { {} } } +static method testConstantSwitches() → dynamic { + #L5: + { + core::print("1_yes"); + break #L5; + } + #L6: + { + core::print("4_not_yes"); + } + #L7: + { + core::print("7_windows"); + break #L7; + } + #L8: + { + core::print("8_not_windows"); + break #L8; + } + #L9: + switch(#C3) /* isExplicitlyExhaustive, self::TestPlatform */ { + #L10: + case #C3: + { + continue #L11; + } + #L11: + { + core::print("10_not_windows"); + break #L9; + } + } + #L12: + { + core::print("14_default"); + } + #L13: + switch(#C9) /* self::TestPlatform */ { + #L14: + case #C9: + { + continue #L15; + } + #L15: + default: + { + core::print("17_default"); + } + } + #L16: + switch(#C6) /* isExplicitlyExhaustive, self::TestPlatform */ { + #L17: + { + core::print("18_notwindows"); + break #L16; + } + #L18: + case #C6: + { + continue #L17; + } + } + #L19: + switch(#C6) /* isExplicitlyExhaustive, self::TestPlatform */ { + #L20: + { + core::print("21_notwindows"); + break #L19; + } + #L21: + case #C6: + { + if(self::foo()!) { + continue #L20; + } + break #L19; + } + } + #L22: + { + core::print("26_default"); + } + #L23: + switch(#C13) /* core::String */ { + #L24: + { + core::print("28_isNotMatch"); + break #L23; + } + #L25: + default: + { + continue #L24; + } + } + #L26: + { + core::print("31_default"); + } + #L27: + { + core::print("33_twentythree"); + break #L27; + } + #L28: + { + #L29: + { + core::print("38_default_default"); + } + } + #L30: + switch(#C13) /* core::String */ { + #L31: + { + #L32: + { + core::print("40_foo_nonzero"); + } + break #L30; + } + #L33: + default: + { + #L34: + { + continue #L31; + } + } + } + #L35: + { + #L36: + { + core::print("43_default_twentythree"); + break #L36; + } + } + #L37: + { + #L38: + { + core::print("46_default_twentythree"); + break #L38; + } + } + #L39: + switch(#C13) /* core::String */ { + #L40: + { + #L41: + { + continue #L42; + } + break #L39; + } + #L42: + default: + { + #L43: + { + continue #L40; + } + } + } + #L44: + { + core::print("49_twentythree"); + } + #L45: + ; + #L46: + { + core::print("52_23_and_default"); + } + #L47: + switch(#C14) /* core::int */ { + #L48: + { + core::print("51_zero"); + break #L47; + } + #L49: + case #C14: + default: + { + core::print("52_23_and_default"); + continue #L48; + } + } +} static method main(core::List args) → dynamic { self::testSimpleConditions(); self::testAndConditions(); @@ -92,7 +311,19 @@ static method main(core::List args) → dynamic { self::testRemovalOfStatementBodies(); } constants { - #C1 = true - #C2 = false - #C3 = 10 + #C1 = 0 + #C2 = "linux" + #C3 = self::TestPlatform {index:#C1, _name:#C2} + #C4 = 1 + #C5 = "macos" + #C6 = self::TestPlatform {index:#C4, _name:#C5} + #C7 = 2 + #C8 = "windows" + #C9 = self::TestPlatform {index:#C7, _name:#C8} + #C10 = [#C3, #C6, #C9] + #C11 = true + #C12 = false + #C13 = "noMatch" + #C14 = 23 + #C15 = 10 } diff --git a/pkg/vm/testcases/transformations/vm_constant_evaluator/platform_testcases.dart b/pkg/vm/testcases/transformations/vm_constant_evaluator/platform_testcases.dart index 8ec39499375..bb3f21414a1 100644 --- a/pkg/vm/testcases/transformations/vm_constant_evaluator/platform_testcases.dart +++ b/pkg/vm/testcases/transformations/vm_constant_evaluator/platform_testcases.dart @@ -70,6 +70,77 @@ void testWindows(int i) { } } +void testSwitchStatements(int i) { + switch (Platform.operatingSystem) { + case "android": + print("is android"); + break; + case "fuchsia": + print("is fuchsia"); + break; + case "ios": + print("is ios"); + break; + case "linux": + print("is linux"); + break; + case "macos": + print("is macos"); + break; + case "windows": + print("is windows"); + break; + default: + throw "Unexpected platform"; + } +} + +enum TestPlatform { + android, + fuchsia, + ios, + linux, + macos, + windows, +} + +@pragma("vm:platform-const") +TestPlatform get defaultTestPlatform { + if (Platform.isAndroid) return TestPlatform.android; + if (Platform.isFuchsia) return TestPlatform.fuchsia; + if (Platform.isIOS) return TestPlatform.ios; + if (Platform.isLinux) return TestPlatform.linux; + if (Platform.isMacOS) return TestPlatform.macos; + if (Platform.isWindows) return TestPlatform.windows; + throw 'Unexpected platform'; +} + +void testPragma(int i) { + print(defaultTestPlatform); + switch (defaultTestPlatform) { + case TestPlatform.android: + print("is android"); + break; + case TestPlatform.fuchsia: + print("is fuchsia"); + break; + case TestPlatform.ios: + print("is ios"); + break; + case TestPlatform.linux: + print("is linux"); + break; + case TestPlatform.macos: + print("is macos"); + break; + case TestPlatform.windows: + print("is windows"); + break; + default: + throw "Unexpected platform"; + } +} + main(List args) { if (args.isEmpty) return; final i = int.parse(args[0]); @@ -79,4 +150,6 @@ main(List args) { testLinux(i); testMacOS(i); testWindows(i); + testSwitchStatements(i); + testPragma(i); } diff --git a/pkg/vm/testcases/transformations/vm_constant_evaluator/platform_testcases.dart.android.expect b/pkg/vm/testcases/transformations/vm_constant_evaluator/platform_testcases.dart.android.expect index 0472b62b058..149bd4a4632 100644 --- a/pkg/vm/testcases/transformations/vm_constant_evaluator/platform_testcases.dart.android.expect +++ b/pkg/vm/testcases/transformations/vm_constant_evaluator/platform_testcases.dart.android.expect @@ -4,36 +4,70 @@ import "dart:core" as core; import "dart:io"; +class TestPlatform extends core::_Enum /*isEnum*/ { + static const field core::List values = #C19; + enum-element static const field self::TestPlatform android = #C3; + enum-element static const field self::TestPlatform fuchsia = #C6; + enum-element static const field self::TestPlatform ios = #C9; + enum-element static const field self::TestPlatform linux = #C12; + enum-element static const field self::TestPlatform macos = #C15; + enum-element static const field self::TestPlatform windows = #C18; + const synthetic constructor •(core::int #index, core::String #name) → self::TestPlatform + : super core::_Enum::•(#index, #name) + ; + method _enumToString() → core::String + return "TestPlatform.${this.{core::_Enum::_name}{core::String}}"; +} static method testAndroid(core::int i) → void { - final core::bool b = #C1; + final core::bool b = #C20; core::print(b); { final core::String os = #C2; core::print(os); - final core::String sep = #C3; + final core::String sep = #C21; core::print(sep); } } static method testFuchsia(core::int i) → void { - final core::bool b = #C4; + final core::bool b = #C22; core::print(b); } static method testIOS(core::int i) → void { - final core::bool b = #C4; + final core::bool b = #C22; core::print(b); } static method testLinux(core::int i) → void { - final core::bool b = #C4; + final core::bool b = #C22; core::print(b); } static method testMacOS(core::int i) → void { - final core::bool b = #C4; + final core::bool b = #C22; core::print(b); } static method testWindows(core::int i) → void { - final core::bool b = #C4; + final core::bool b = #C22; core::print(b); } +static method testSwitchStatements(core::int i) → void { + #L1: + { + core::print("is android"); + break #L1; + } +} +@#C25 +static get defaultTestPlatform() → self::TestPlatform { + return #C3; + throw "Unexpected platform"; +} +static method testPragma(core::int i) → void { + core::print(#C3); + #L2: + { + core::print("is android"); + break #L2; + } +} static method main(core::List args) → dynamic { if(args.{core::Iterable::isEmpty}{core::bool}) return; @@ -44,10 +78,33 @@ static method main(core::List args) → dynamic { self::testLinux(i); self::testMacOS(i); self::testWindows(i); + self::testSwitchStatements(i); + self::testPragma(i); } constants { - #C1 = true + #C1 = 0 #C2 = "android" - #C3 = "/" - #C4 = false + #C3 = self::TestPlatform {index:#C1, _name:#C2} + #C4 = 1 + #C5 = "fuchsia" + #C6 = self::TestPlatform {index:#C4, _name:#C5} + #C7 = 2 + #C8 = "ios" + #C9 = self::TestPlatform {index:#C7, _name:#C8} + #C10 = 3 + #C11 = "linux" + #C12 = self::TestPlatform {index:#C10, _name:#C11} + #C13 = 4 + #C14 = "macos" + #C15 = self::TestPlatform {index:#C13, _name:#C14} + #C16 = 5 + #C17 = "windows" + #C18 = self::TestPlatform {index:#C16, _name:#C17} + #C19 = [#C3, #C6, #C9, #C12, #C15, #C18] + #C20 = true + #C21 = "/" + #C22 = false + #C23 = "vm:platform-const" + #C24 = null + #C25 = core::pragma {name:#C23, options:#C24} } diff --git a/pkg/vm/testcases/transformations/vm_constant_evaluator/platform_testcases.dart.fuchsia.expect b/pkg/vm/testcases/transformations/vm_constant_evaluator/platform_testcases.dart.fuchsia.expect index 017e11d529b..b95d833d875 100644 --- a/pkg/vm/testcases/transformations/vm_constant_evaluator/platform_testcases.dart.fuchsia.expect +++ b/pkg/vm/testcases/transformations/vm_constant_evaluator/platform_testcases.dart.fuchsia.expect @@ -4,36 +4,70 @@ import "dart:core" as core; import "dart:io"; +class TestPlatform extends core::_Enum /*isEnum*/ { + static const field core::List values = #C19; + enum-element static const field self::TestPlatform android = #C3; + enum-element static const field self::TestPlatform fuchsia = #C6; + enum-element static const field self::TestPlatform ios = #C9; + enum-element static const field self::TestPlatform linux = #C12; + enum-element static const field self::TestPlatform macos = #C15; + enum-element static const field self::TestPlatform windows = #C18; + const synthetic constructor •(core::int #index, core::String #name) → self::TestPlatform + : super core::_Enum::•(#index, #name) + ; + method _enumToString() → core::String + return "TestPlatform.${this.{core::_Enum::_name}{core::String}}"; +} static method testAndroid(core::int i) → void { - final core::bool b = #C1; + final core::bool b = #C20; core::print(b); } static method testFuchsia(core::int i) → void { - final core::bool b = #C2; + final core::bool b = #C21; core::print(b); { - final core::String os = #C3; + final core::String os = #C5; core::print(os); - final core::String sep = #C4; + final core::String sep = #C22; core::print(sep); } } static method testIOS(core::int i) → void { - final core::bool b = #C1; + final core::bool b = #C20; core::print(b); } static method testLinux(core::int i) → void { - final core::bool b = #C1; + final core::bool b = #C20; core::print(b); } static method testMacOS(core::int i) → void { - final core::bool b = #C1; + final core::bool b = #C20; core::print(b); } static method testWindows(core::int i) → void { - final core::bool b = #C1; + final core::bool b = #C20; core::print(b); } +static method testSwitchStatements(core::int i) → void { + #L1: + { + core::print("is fuchsia"); + break #L1; + } +} +@#C25 +static get defaultTestPlatform() → self::TestPlatform { + return #C6; + throw "Unexpected platform"; +} +static method testPragma(core::int i) → void { + core::print(#C6); + #L2: + { + core::print("is fuchsia"); + break #L2; + } +} static method main(core::List args) → dynamic { if(args.{core::Iterable::isEmpty}{core::bool}) return; @@ -44,10 +78,33 @@ static method main(core::List args) → dynamic { self::testLinux(i); self::testMacOS(i); self::testWindows(i); + self::testSwitchStatements(i); + self::testPragma(i); } constants { - #C1 = false - #C2 = true - #C3 = "fuchsia" - #C4 = "/" + #C1 = 0 + #C2 = "android" + #C3 = self::TestPlatform {index:#C1, _name:#C2} + #C4 = 1 + #C5 = "fuchsia" + #C6 = self::TestPlatform {index:#C4, _name:#C5} + #C7 = 2 + #C8 = "ios" + #C9 = self::TestPlatform {index:#C7, _name:#C8} + #C10 = 3 + #C11 = "linux" + #C12 = self::TestPlatform {index:#C10, _name:#C11} + #C13 = 4 + #C14 = "macos" + #C15 = self::TestPlatform {index:#C13, _name:#C14} + #C16 = 5 + #C17 = "windows" + #C18 = self::TestPlatform {index:#C16, _name:#C17} + #C19 = [#C3, #C6, #C9, #C12, #C15, #C18] + #C20 = false + #C21 = true + #C22 = "/" + #C23 = "vm:platform-const" + #C24 = null + #C25 = core::pragma {name:#C23, options:#C24} } diff --git a/pkg/vm/testcases/transformations/vm_constant_evaluator/platform_testcases.dart.ios.expect b/pkg/vm/testcases/transformations/vm_constant_evaluator/platform_testcases.dart.ios.expect index d6f57e52c48..21c480b80a8 100644 --- a/pkg/vm/testcases/transformations/vm_constant_evaluator/platform_testcases.dart.ios.expect +++ b/pkg/vm/testcases/transformations/vm_constant_evaluator/platform_testcases.dart.ios.expect @@ -4,36 +4,70 @@ import "dart:core" as core; import "dart:io"; +class TestPlatform extends core::_Enum /*isEnum*/ { + static const field core::List values = #C19; + enum-element static const field self::TestPlatform android = #C3; + enum-element static const field self::TestPlatform fuchsia = #C6; + enum-element static const field self::TestPlatform ios = #C9; + enum-element static const field self::TestPlatform linux = #C12; + enum-element static const field self::TestPlatform macos = #C15; + enum-element static const field self::TestPlatform windows = #C18; + const synthetic constructor •(core::int #index, core::String #name) → self::TestPlatform + : super core::_Enum::•(#index, #name) + ; + method _enumToString() → core::String + return "TestPlatform.${this.{core::_Enum::_name}{core::String}}"; +} static method testAndroid(core::int i) → void { - final core::bool b = #C1; + final core::bool b = #C20; core::print(b); } static method testFuchsia(core::int i) → void { - final core::bool b = #C1; + final core::bool b = #C20; core::print(b); } static method testIOS(core::int i) → void { - final core::bool b = #C2; + final core::bool b = #C21; core::print(b); { - final core::String os = #C3; + final core::String os = #C8; core::print(os); - final core::String sep = #C4; + final core::String sep = #C22; core::print(sep); } } static method testLinux(core::int i) → void { - final core::bool b = #C1; + final core::bool b = #C20; core::print(b); } static method testMacOS(core::int i) → void { - final core::bool b = #C1; + final core::bool b = #C20; core::print(b); } static method testWindows(core::int i) → void { - final core::bool b = #C1; + final core::bool b = #C20; core::print(b); } +static method testSwitchStatements(core::int i) → void { + #L1: + { + core::print("is ios"); + break #L1; + } +} +@#C25 +static get defaultTestPlatform() → self::TestPlatform { + return #C9; + throw "Unexpected platform"; +} +static method testPragma(core::int i) → void { + core::print(#C9); + #L2: + { + core::print("is ios"); + break #L2; + } +} static method main(core::List args) → dynamic { if(args.{core::Iterable::isEmpty}{core::bool}) return; @@ -44,10 +78,33 @@ static method main(core::List args) → dynamic { self::testLinux(i); self::testMacOS(i); self::testWindows(i); + self::testSwitchStatements(i); + self::testPragma(i); } constants { - #C1 = false - #C2 = true - #C3 = "ios" - #C4 = "/" + #C1 = 0 + #C2 = "android" + #C3 = self::TestPlatform {index:#C1, _name:#C2} + #C4 = 1 + #C5 = "fuchsia" + #C6 = self::TestPlatform {index:#C4, _name:#C5} + #C7 = 2 + #C8 = "ios" + #C9 = self::TestPlatform {index:#C7, _name:#C8} + #C10 = 3 + #C11 = "linux" + #C12 = self::TestPlatform {index:#C10, _name:#C11} + #C13 = 4 + #C14 = "macos" + #C15 = self::TestPlatform {index:#C13, _name:#C14} + #C16 = 5 + #C17 = "windows" + #C18 = self::TestPlatform {index:#C16, _name:#C17} + #C19 = [#C3, #C6, #C9, #C12, #C15, #C18] + #C20 = false + #C21 = true + #C22 = "/" + #C23 = "vm:platform-const" + #C24 = null + #C25 = core::pragma {name:#C23, options:#C24} } diff --git a/pkg/vm/testcases/transformations/vm_constant_evaluator/platform_testcases.dart.linux.expect b/pkg/vm/testcases/transformations/vm_constant_evaluator/platform_testcases.dart.linux.expect index c10ed5a698b..95c3bbebf32 100644 --- a/pkg/vm/testcases/transformations/vm_constant_evaluator/platform_testcases.dart.linux.expect +++ b/pkg/vm/testcases/transformations/vm_constant_evaluator/platform_testcases.dart.linux.expect @@ -4,36 +4,70 @@ import "dart:core" as core; import "dart:io"; +class TestPlatform extends core::_Enum /*isEnum*/ { + static const field core::List values = #C19; + enum-element static const field self::TestPlatform android = #C3; + enum-element static const field self::TestPlatform fuchsia = #C6; + enum-element static const field self::TestPlatform ios = #C9; + enum-element static const field self::TestPlatform linux = #C12; + enum-element static const field self::TestPlatform macos = #C15; + enum-element static const field self::TestPlatform windows = #C18; + const synthetic constructor •(core::int #index, core::String #name) → self::TestPlatform + : super core::_Enum::•(#index, #name) + ; + method _enumToString() → core::String + return "TestPlatform.${this.{core::_Enum::_name}{core::String}}"; +} static method testAndroid(core::int i) → void { - final core::bool b = #C1; + final core::bool b = #C20; core::print(b); } static method testFuchsia(core::int i) → void { - final core::bool b = #C1; + final core::bool b = #C20; core::print(b); } static method testIOS(core::int i) → void { - final core::bool b = #C1; + final core::bool b = #C20; core::print(b); } static method testLinux(core::int i) → void { - final core::bool b = #C2; + final core::bool b = #C21; core::print(b); { - final core::String os = #C3; + final core::String os = #C11; core::print(os); - final core::String sep = #C4; + final core::String sep = #C22; core::print(sep); } } static method testMacOS(core::int i) → void { - final core::bool b = #C1; + final core::bool b = #C20; core::print(b); } static method testWindows(core::int i) → void { - final core::bool b = #C1; + final core::bool b = #C20; core::print(b); } +static method testSwitchStatements(core::int i) → void { + #L1: + { + core::print("is linux"); + break #L1; + } +} +@#C25 +static get defaultTestPlatform() → self::TestPlatform { + return #C12; + throw "Unexpected platform"; +} +static method testPragma(core::int i) → void { + core::print(#C12); + #L2: + { + core::print("is linux"); + break #L2; + } +} static method main(core::List args) → dynamic { if(args.{core::Iterable::isEmpty}{core::bool}) return; @@ -44,10 +78,33 @@ static method main(core::List args) → dynamic { self::testLinux(i); self::testMacOS(i); self::testWindows(i); + self::testSwitchStatements(i); + self::testPragma(i); } constants { - #C1 = false - #C2 = true - #C3 = "linux" - #C4 = "/" + #C1 = 0 + #C2 = "android" + #C3 = self::TestPlatform {index:#C1, _name:#C2} + #C4 = 1 + #C5 = "fuchsia" + #C6 = self::TestPlatform {index:#C4, _name:#C5} + #C7 = 2 + #C8 = "ios" + #C9 = self::TestPlatform {index:#C7, _name:#C8} + #C10 = 3 + #C11 = "linux" + #C12 = self::TestPlatform {index:#C10, _name:#C11} + #C13 = 4 + #C14 = "macos" + #C15 = self::TestPlatform {index:#C13, _name:#C14} + #C16 = 5 + #C17 = "windows" + #C18 = self::TestPlatform {index:#C16, _name:#C17} + #C19 = [#C3, #C6, #C9, #C12, #C15, #C18] + #C20 = false + #C21 = true + #C22 = "/" + #C23 = "vm:platform-const" + #C24 = null + #C25 = core::pragma {name:#C23, options:#C24} } diff --git a/pkg/vm/testcases/transformations/vm_constant_evaluator/platform_testcases.dart.macos.expect b/pkg/vm/testcases/transformations/vm_constant_evaluator/platform_testcases.dart.macos.expect index aa886e6ef10..26513c18b02 100644 --- a/pkg/vm/testcases/transformations/vm_constant_evaluator/platform_testcases.dart.macos.expect +++ b/pkg/vm/testcases/transformations/vm_constant_evaluator/platform_testcases.dart.macos.expect @@ -4,36 +4,70 @@ import "dart:core" as core; import "dart:io"; +class TestPlatform extends core::_Enum /*isEnum*/ { + static const field core::List values = #C19; + enum-element static const field self::TestPlatform android = #C3; + enum-element static const field self::TestPlatform fuchsia = #C6; + enum-element static const field self::TestPlatform ios = #C9; + enum-element static const field self::TestPlatform linux = #C12; + enum-element static const field self::TestPlatform macos = #C15; + enum-element static const field self::TestPlatform windows = #C18; + const synthetic constructor •(core::int #index, core::String #name) → self::TestPlatform + : super core::_Enum::•(#index, #name) + ; + method _enumToString() → core::String + return "TestPlatform.${this.{core::_Enum::_name}{core::String}}"; +} static method testAndroid(core::int i) → void { - final core::bool b = #C1; + final core::bool b = #C20; core::print(b); } static method testFuchsia(core::int i) → void { - final core::bool b = #C1; + final core::bool b = #C20; core::print(b); } static method testIOS(core::int i) → void { - final core::bool b = #C1; + final core::bool b = #C20; core::print(b); } static method testLinux(core::int i) → void { - final core::bool b = #C1; + final core::bool b = #C20; core::print(b); } static method testMacOS(core::int i) → void { - final core::bool b = #C2; + final core::bool b = #C21; core::print(b); { - final core::String os = #C3; + final core::String os = #C14; core::print(os); - final core::String sep = #C4; + final core::String sep = #C22; core::print(sep); } } static method testWindows(core::int i) → void { - final core::bool b = #C1; + final core::bool b = #C20; core::print(b); } +static method testSwitchStatements(core::int i) → void { + #L1: + { + core::print("is macos"); + break #L1; + } +} +@#C25 +static get defaultTestPlatform() → self::TestPlatform { + return #C15; + throw "Unexpected platform"; +} +static method testPragma(core::int i) → void { + core::print(#C15); + #L2: + { + core::print("is macos"); + break #L2; + } +} static method main(core::List args) → dynamic { if(args.{core::Iterable::isEmpty}{core::bool}) return; @@ -44,10 +78,33 @@ static method main(core::List args) → dynamic { self::testLinux(i); self::testMacOS(i); self::testWindows(i); + self::testSwitchStatements(i); + self::testPragma(i); } constants { - #C1 = false - #C2 = true - #C3 = "macos" - #C4 = "/" + #C1 = 0 + #C2 = "android" + #C3 = self::TestPlatform {index:#C1, _name:#C2} + #C4 = 1 + #C5 = "fuchsia" + #C6 = self::TestPlatform {index:#C4, _name:#C5} + #C7 = 2 + #C8 = "ios" + #C9 = self::TestPlatform {index:#C7, _name:#C8} + #C10 = 3 + #C11 = "linux" + #C12 = self::TestPlatform {index:#C10, _name:#C11} + #C13 = 4 + #C14 = "macos" + #C15 = self::TestPlatform {index:#C13, _name:#C14} + #C16 = 5 + #C17 = "windows" + #C18 = self::TestPlatform {index:#C16, _name:#C17} + #C19 = [#C3, #C6, #C9, #C12, #C15, #C18] + #C20 = false + #C21 = true + #C22 = "/" + #C23 = "vm:platform-const" + #C24 = null + #C25 = core::pragma {name:#C23, options:#C24} } diff --git a/pkg/vm/testcases/transformations/vm_constant_evaluator/platform_testcases.dart.windows.expect b/pkg/vm/testcases/transformations/vm_constant_evaluator/platform_testcases.dart.windows.expect index 4dcd047365d..f1086024a36 100644 --- a/pkg/vm/testcases/transformations/vm_constant_evaluator/platform_testcases.dart.windows.expect +++ b/pkg/vm/testcases/transformations/vm_constant_evaluator/platform_testcases.dart.windows.expect @@ -4,36 +4,70 @@ import "dart:core" as core; import "dart:io"; +class TestPlatform extends core::_Enum /*isEnum*/ { + static const field core::List values = #C19; + enum-element static const field self::TestPlatform android = #C3; + enum-element static const field self::TestPlatform fuchsia = #C6; + enum-element static const field self::TestPlatform ios = #C9; + enum-element static const field self::TestPlatform linux = #C12; + enum-element static const field self::TestPlatform macos = #C15; + enum-element static const field self::TestPlatform windows = #C18; + const synthetic constructor •(core::int #index, core::String #name) → self::TestPlatform + : super core::_Enum::•(#index, #name) + ; + method _enumToString() → core::String + return "TestPlatform.${this.{core::_Enum::_name}{core::String}}"; +} static method testAndroid(core::int i) → void { - final core::bool b = #C1; + final core::bool b = #C20; core::print(b); } static method testFuchsia(core::int i) → void { - final core::bool b = #C1; + final core::bool b = #C20; core::print(b); } static method testIOS(core::int i) → void { - final core::bool b = #C1; + final core::bool b = #C20; core::print(b); } static method testLinux(core::int i) → void { - final core::bool b = #C1; + final core::bool b = #C20; core::print(b); } static method testMacOS(core::int i) → void { - final core::bool b = #C1; + final core::bool b = #C20; core::print(b); } static method testWindows(core::int i) → void { - final core::bool b = #C2; + final core::bool b = #C21; core::print(b); { - final core::String os = #C3; + final core::String os = #C17; core::print(os); - final core::String sep = #C4; + final core::String sep = #C22; core::print(sep); } } +static method testSwitchStatements(core::int i) → void { + #L1: + { + core::print("is windows"); + break #L1; + } +} +@#C25 +static get defaultTestPlatform() → self::TestPlatform { + return #C18; + throw "Unexpected platform"; +} +static method testPragma(core::int i) → void { + core::print(#C18); + #L2: + { + core::print("is windows"); + break #L2; + } +} static method main(core::List args) → dynamic { if(args.{core::Iterable::isEmpty}{core::bool}) return; @@ -44,10 +78,33 @@ static method main(core::List args) → dynamic { self::testLinux(i); self::testMacOS(i); self::testWindows(i); + self::testSwitchStatements(i); + self::testPragma(i); } constants { - #C1 = false - #C2 = true - #C3 = "windows" - #C4 = "\\" + #C1 = 0 + #C2 = "android" + #C3 = self::TestPlatform {index:#C1, _name:#C2} + #C4 = 1 + #C5 = "fuchsia" + #C6 = self::TestPlatform {index:#C4, _name:#C5} + #C7 = 2 + #C8 = "ios" + #C9 = self::TestPlatform {index:#C7, _name:#C8} + #C10 = 3 + #C11 = "linux" + #C12 = self::TestPlatform {index:#C10, _name:#C11} + #C13 = 4 + #C14 = "macos" + #C15 = self::TestPlatform {index:#C13, _name:#C14} + #C16 = 5 + #C17 = "windows" + #C18 = self::TestPlatform {index:#C16, _name:#C17} + #C19 = [#C3, #C6, #C9, #C12, #C15, #C18] + #C20 = false + #C21 = true + #C22 = "\\" + #C23 = "vm:platform-const" + #C24 = null + #C25 = core::pragma {name:#C23, options:#C24} }