mirror of
https://github.com/dart-lang/sdk
synced 2024-10-06 15:39:54 +00:00
[cfe] Desugar pattern variable assignments
Part of https://github.com/dart-lang/sdk/issues/49749 Change-Id: Ibae19d0e64f023aea047b007d73f3cee9910d259 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/277683 Reviewed-by: Johnni Winther <johnniwinther@google.com> Commit-Queue: Chloe Stefantsova <cstefantsova@google.com>
This commit is contained in:
parent
8e07d492dd
commit
9383820f15
|
@ -8483,8 +8483,17 @@ class BodyBuilder extends StackListenerImpl
|
|||
Pattern pattern;
|
||||
if (variable.lexeme == "_") {
|
||||
pattern = new WildcardPattern(patternType, variable.charOffset);
|
||||
} else if (inAssignmentPattern) {
|
||||
Expression variableUse =
|
||||
toValue(scopeLookup(scope, variable.lexeme, variable));
|
||||
if (variableUse is VariableGet) {
|
||||
pattern = new AssignedVariablePattern(variableUse.variable,
|
||||
offset: variable.charOffset);
|
||||
} else {
|
||||
// Recover by using [WildcardPattern] instead.
|
||||
pattern = new WildcardPattern(patternType, variable.charOffset);
|
||||
}
|
||||
} else {
|
||||
// TODO(paulberry): use inAssignmentPattern.
|
||||
pattern = new VariablePattern(
|
||||
patternType,
|
||||
variable.lexeme,
|
||||
|
@ -8552,7 +8561,24 @@ class BodyBuilder extends StackListenerImpl
|
|||
// TODO(johnniwinther,cstefantsova): Handle metadata.
|
||||
pop(NullValue.Metadata) as List<Expression>?;
|
||||
push(new PatternVariableDeclaration(pattern, initializer,
|
||||
offset: keyword.charOffset, isFinal: isFinal));
|
||||
fileOffset: keyword.charOffset, isFinal: isFinal));
|
||||
}
|
||||
|
||||
@override
|
||||
void handlePatternAssignment(Token equals) {
|
||||
debugEvent("PatternAssignment");
|
||||
assert(checkState(equals, [
|
||||
unionOfKinds([
|
||||
ValueKinds.Expression,
|
||||
ValueKinds.Generator,
|
||||
ValueKinds.ProblemBuilder,
|
||||
]),
|
||||
ValueKinds.Pattern
|
||||
]));
|
||||
Expression expression = popForValue();
|
||||
Pattern pattern = toPattern(pop());
|
||||
push(new PatternAssignment(pattern, expression,
|
||||
fileOffset: equals.charOffset));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -386,6 +386,14 @@ class Forest {
|
|||
..fileEndOffset = fileEndOffset;
|
||||
}
|
||||
|
||||
/// Return a representation of a block expression.
|
||||
BlockExpression createBlockExpression(
|
||||
int fileOffset, Block body, Expression value) {
|
||||
// ignore: unnecessary_null_comparison
|
||||
assert(fileOffset != null);
|
||||
return new BlockExpression(body, value)..fileOffset = fileOffset;
|
||||
}
|
||||
|
||||
/// Return a representation of a break statement.
|
||||
Statement createBreakStatement(int fileOffset, Object? label) {
|
||||
// ignore: unnecessary_null_comparison
|
||||
|
|
|
@ -5020,8 +5020,8 @@ class PatternVariableDeclaration extends InternalStatement {
|
|||
final bool isFinal;
|
||||
|
||||
PatternVariableDeclaration(this.pattern, this.initializer,
|
||||
{required int offset, required this.isFinal}) {
|
||||
fileOffset = offset;
|
||||
{required int fileOffset, required this.isFinal}) {
|
||||
super.fileOffset = fileOffset;
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -5048,6 +5048,72 @@ class PatternVariableDeclaration extends InternalStatement {
|
|||
}
|
||||
}
|
||||
|
||||
class PatternAssignment extends InternalExpression {
|
||||
final Pattern pattern;
|
||||
final Expression expression;
|
||||
|
||||
PatternAssignment(this.pattern, this.expression, {required int fileOffset}) {
|
||||
super.fileOffset = fileOffset;
|
||||
}
|
||||
|
||||
@override
|
||||
ExpressionInferenceResult acceptInference(
|
||||
InferenceVisitorImpl visitor, DartType typeContext) {
|
||||
return visitor.visitPatternAssignment(this, typeContext);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return "PatternAssignment(${toStringInternal()})";
|
||||
}
|
||||
}
|
||||
|
||||
class AssignedVariablePattern extends Pattern {
|
||||
final VariableDeclaration variable;
|
||||
|
||||
AssignedVariablePattern(this.variable, {required int offset}) : super(offset);
|
||||
|
||||
@override
|
||||
PatternInferenceResult acceptInference(InferenceVisitorImpl visitor,
|
||||
{required SharedMatchContext context}) {
|
||||
return visitor.visitAssignedVariablePattern(this, context: context);
|
||||
}
|
||||
|
||||
@override
|
||||
List<VariableDeclaration> get declaredVariables => [variable];
|
||||
|
||||
@override
|
||||
void toTextInternal(AstPrinter printer) {
|
||||
printer.write(variable.name!);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return "AssignedVariablePattern(${toStringInternal()})";
|
||||
}
|
||||
|
||||
@override
|
||||
PatternTransformationResult transform(
|
||||
Expression matchedExpression,
|
||||
DartType matchedType,
|
||||
Expression variableInitializingContext,
|
||||
InferenceVisitorBase inferenceVisitor) {
|
||||
// condition: let _ = `variable` = `matchedExpression` in true
|
||||
return new PatternTransformationResult([
|
||||
new PatternTransformationElement(
|
||||
kind: PatternTransformationElementKind.regular,
|
||||
condition: inferenceVisitor.engine.forest.createLet(
|
||||
inferenceVisitor.engine.forest.createVariableDeclarationForValue(
|
||||
inferenceVisitor.engine.forest.createVariableSet(
|
||||
fileOffset, variable, matchedExpression)),
|
||||
inferenceVisitor.engine.forest
|
||||
.createBoolLiteral(fileOffset, true))
|
||||
..fileOffset = fileOffset,
|
||||
variableInitializers: [])
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
final Pattern dummyPattern = new ExpressionPattern(dummyExpression);
|
||||
|
||||
/// Internal statement for a if-case statements:
|
||||
|
@ -5617,7 +5683,7 @@ class VariablePattern extends Pattern {
|
|||
|
||||
@override
|
||||
String toString() {
|
||||
return "VariableBinder(${toStringInternal()})";
|
||||
return "VariablePattern(${toStringInternal()})";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9304,6 +9304,82 @@ class InferenceVisitorImpl extends InferenceVisitorBase
|
|||
return const PatternInferenceResult();
|
||||
}
|
||||
|
||||
ExpressionInferenceResult visitPatternAssignment(
|
||||
PatternAssignment node, DartType typeContext) {
|
||||
Expression expression = node.expression;
|
||||
ExpressionTypeAnalysisResult<DartType> analysisResult =
|
||||
analyzePatternAssignment(node, node.pattern, expression);
|
||||
Node? rewrite = popRewrite();
|
||||
if (!identical(expression, rewrite)) {
|
||||
expression = rewrite as Expression;
|
||||
}
|
||||
|
||||
// TODO(cstefantsova): Do we need a more precise type for the variable?
|
||||
VariableDeclaration matchedExpressionVariable = engine.forest
|
||||
.createVariableDeclarationForValue(expression,
|
||||
type: const DynamicType());
|
||||
VariableDeclaration isPatternMatchingFailed = engine.forest
|
||||
.createVariableDeclarationForValue(
|
||||
engine.forest.createBoolLiteral(node.fileOffset, true),
|
||||
type: coreTypes.boolNonNullableRawType);
|
||||
|
||||
// patternMatchedSet: `isPatternMatchingFailed` = false;
|
||||
// ==> VAR = true;
|
||||
Statement patternMatchedSet = engine.forest.createExpressionStatement(
|
||||
node.fileOffset,
|
||||
engine.forest.createVariableSet(
|
||||
node.fileOffset,
|
||||
isPatternMatchingFailed,
|
||||
engine.forest.createBoolLiteral(node.fileOffset, false)));
|
||||
|
||||
PatternTransformationResult transformationResult = node.pattern.transform(
|
||||
engine.forest
|
||||
.createVariableGet(node.fileOffset, matchedExpressionVariable),
|
||||
const DynamicType(),
|
||||
engine.forest
|
||||
.createVariableGet(node.fileOffset, matchedExpressionVariable),
|
||||
this);
|
||||
|
||||
List<Statement> replacementStatements = _transformationResultToStatements(
|
||||
node.fileOffset, transformationResult, [patternMatchedSet]);
|
||||
|
||||
replacementStatements = [
|
||||
matchedExpressionVariable,
|
||||
isPatternMatchingFailed,
|
||||
...replacementStatements,
|
||||
// TODO(cstefantsova): Figure out the right exception to throw.
|
||||
engine.forest.createIfStatement(
|
||||
node.fileOffset,
|
||||
engine.forest
|
||||
.createVariableGet(node.fileOffset, isPatternMatchingFailed),
|
||||
engine.forest.createExpressionStatement(
|
||||
node.fileOffset,
|
||||
new Throw(
|
||||
new ConstructorInvocation(
|
||||
coreTypes.reachabilityErrorConstructor,
|
||||
engine.forest.createArguments(node.fileOffset, []))
|
||||
..fileOffset = node.fileOffset)
|
||||
..fileOffset = node.fileOffset),
|
||||
null),
|
||||
];
|
||||
|
||||
Expression replacement = engine.forest.createBlockExpression(
|
||||
node.fileOffset,
|
||||
engine.forest.createBlock(
|
||||
node.fileOffset, node.fileOffset, replacementStatements),
|
||||
engine.forest
|
||||
.createVariableGet(node.fileOffset, matchedExpressionVariable));
|
||||
return new ExpressionInferenceResult(
|
||||
analysisResult.resolveShorting(), replacement);
|
||||
}
|
||||
|
||||
PatternInferenceResult visitAssignedVariablePattern(
|
||||
AssignedVariablePattern node,
|
||||
{required SharedMatchContext context}) {
|
||||
analyzeAssignedVariablePattern(context, node, node.variable);
|
||||
return const PatternInferenceResult();
|
||||
}
|
||||
|
||||
@override
|
||||
shared.RecordType<DartType>? asRecordType(DartType type) {
|
||||
if (type is RecordType) {
|
||||
|
|
|
@ -1318,14 +1318,14 @@ void _testPatternVariableDeclaration() {
|
|||
testStatement(
|
||||
new PatternVariableDeclaration(
|
||||
new ExpressionPattern(new IntLiteral(0)), new IntLiteral(1),
|
||||
isFinal: false, offset: TreeNode.noOffset),
|
||||
isFinal: false, fileOffset: TreeNode.noOffset),
|
||||
'''
|
||||
var 0 = 1;''');
|
||||
|
||||
testStatement(
|
||||
new PatternVariableDeclaration(
|
||||
new ExpressionPattern(new IntLiteral(0)), new IntLiteral(1),
|
||||
isFinal: true, offset: TreeNode.noOffset),
|
||||
isFinal: true, fileOffset: TreeNode.noOffset),
|
||||
'''
|
||||
final 0 = 1;''');
|
||||
}
|
||||
|
|
43
pkg/front_end/testcases/patterns/simple_assignments.dart
Normal file
43
pkg/front_end/testcases/patterns/simple_assignments.dart
Normal file
|
@ -0,0 +1,43 @@
|
|||
// Copyright (c) 2022, 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.
|
||||
|
||||
test1(dynamic x) {
|
||||
int a;
|
||||
[a] = x;
|
||||
return a;
|
||||
}
|
||||
|
||||
test2(dynamic x) {
|
||||
int a, b, c;
|
||||
[c, ...] = [a && b, ...] = x;
|
||||
return a + b + c;
|
||||
}
|
||||
|
||||
main() {
|
||||
expectEquals(test1([1]), 1);
|
||||
expectThrows(() => test1([]));
|
||||
expectThrows(() => test1([1, 2, 3]));
|
||||
expectThrows(() => test1("foo"));
|
||||
expectThrows(() => test1(null));
|
||||
|
||||
expectEquals(test2([1]), 3);
|
||||
expectThrows(() => test2(1));
|
||||
}
|
||||
|
||||
expectEquals(x, y) {
|
||||
if (x != y) {
|
||||
throw "Expected ${x} to be equal to ${y}.";
|
||||
}
|
||||
}
|
||||
|
||||
expectThrows(void Function() f) {
|
||||
bool hasThrown = true;
|
||||
try {
|
||||
f();
|
||||
hasThrown = false;
|
||||
} catch (e) {}
|
||||
if (!hasThrown) {
|
||||
throw "Expected the function to throw.";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "dart:_internal" as _in;
|
||||
|
||||
static method test1(dynamic x) → dynamic {
|
||||
core::int a;
|
||||
block {
|
||||
final dynamic #t1 = x;
|
||||
final core::bool #t2 = true;
|
||||
final dynamic #t3 = #t1;
|
||||
if(#t3 is core::List<dynamic> && #t3{core::List<dynamic>}.{core::List::length}{core::int}.{core::num::==}(1){(core::Object) → core::bool}) {
|
||||
final dynamic #t4 = #t3{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
|
||||
if(let final dynamic #t5 = a = #t4 in true) {
|
||||
#t2 = false;
|
||||
}
|
||||
}
|
||||
if(#t2)
|
||||
throw new _in::ReachabilityError::•();
|
||||
} =>#t1;
|
||||
return a;
|
||||
}
|
||||
static method test2(dynamic x) → dynamic {
|
||||
core::int a;
|
||||
core::int b;
|
||||
core::int c;
|
||||
block {
|
||||
final dynamic #t6 = block {
|
||||
final dynamic #t7 = x;
|
||||
final core::bool #t8 = true;
|
||||
final dynamic #t9 = #t7;
|
||||
if(#t9 is core::List<dynamic> && #t9{core::List<dynamic>}.{core::List::length}{core::int}.{core::num::>=}(1){(core::num) → core::bool}) {
|
||||
final dynamic #t10 = #t9{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
|
||||
final dynamic #t11 = #t10;
|
||||
if((let final dynamic #t12 = a = #t11 in true) && (let final dynamic #t13 = b = #t11 in true)) {
|
||||
#t8 = false;
|
||||
}
|
||||
}
|
||||
if(#t8)
|
||||
throw new _in::ReachabilityError::•();
|
||||
} =>#t7;
|
||||
final core::bool #t14 = true;
|
||||
final dynamic #t15 = #t6;
|
||||
if(#t15 is core::List<dynamic> && #t15{core::List<dynamic>}.{core::List::length}{core::int}.{core::num::>=}(1){(core::num) → core::bool}) {
|
||||
final dynamic #t16 = #t15{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
|
||||
if(let final dynamic #t17 = c = #t16 in true) {
|
||||
#t14 = false;
|
||||
}
|
||||
}
|
||||
if(#t14)
|
||||
throw new _in::ReachabilityError::•();
|
||||
} =>#t6;
|
||||
return a.{core::num::+}(b){(core::num) → core::int}.{core::num::+}(c){(core::num) → core::int};
|
||||
}
|
||||
static method main() → dynamic {
|
||||
self::expectEquals(self::test1(<core::int>[1]), 1);
|
||||
self::expectThrows(() → void => self::test1(<dynamic>[]));
|
||||
self::expectThrows(() → void => self::test1(<core::int>[1, 2, 3]));
|
||||
self::expectThrows(() → void => self::test1("foo"));
|
||||
self::expectThrows(() → void => self::test1(null));
|
||||
self::expectEquals(self::test2(<core::int>[1]), 3);
|
||||
self::expectThrows(() → void => self::test2(1));
|
||||
}
|
||||
static method expectEquals(dynamic x, dynamic y) → dynamic {
|
||||
if(!(x =={core::Object::==}{(core::Object) → core::bool} y)) {
|
||||
throw "Expected ${x} to be equal to ${y}.";
|
||||
}
|
||||
}
|
||||
static method expectThrows(() → void f) → dynamic {
|
||||
core::bool hasThrown = true;
|
||||
try {
|
||||
f(){() → void};
|
||||
hasThrown = false;
|
||||
}
|
||||
on core::Object catch(final core::Object e) {
|
||||
}
|
||||
if(!hasThrown) {
|
||||
throw "Expected the function to throw.";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "dart:_internal" as _in;
|
||||
|
||||
static method test1(dynamic x) → dynamic {
|
||||
core::int a;
|
||||
block {
|
||||
final dynamic #t1 = x;
|
||||
final core::bool #t2 = true;
|
||||
final dynamic #t3 = #t1;
|
||||
if(#t3 is core::List<dynamic> && #t3{core::List<dynamic>}.{core::List::length}{core::int}.{core::num::==}(1){(core::Object) → core::bool}) {
|
||||
final dynamic #t4 = #t3{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
|
||||
if(let final dynamic #t5 = a = #t4 in true) {
|
||||
#t2 = false;
|
||||
}
|
||||
}
|
||||
if(#t2)
|
||||
throw new _in::ReachabilityError::•();
|
||||
} =>#t1;
|
||||
return a;
|
||||
}
|
||||
static method test2(dynamic x) → dynamic {
|
||||
core::int a;
|
||||
core::int b;
|
||||
core::int c;
|
||||
block {
|
||||
final dynamic #t6 = block {
|
||||
final dynamic #t7 = x;
|
||||
final core::bool #t8 = true;
|
||||
final dynamic #t9 = #t7;
|
||||
if(#t9 is core::List<dynamic> && #t9{core::List<dynamic>}.{core::List::length}{core::int}.{core::num::>=}(1){(core::num) → core::bool}) {
|
||||
final dynamic #t10 = #t9{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
|
||||
final dynamic #t11 = #t10;
|
||||
if((let final dynamic #t12 = a = #t11 in true) && (let final dynamic #t13 = b = #t11 in true)) {
|
||||
#t8 = false;
|
||||
}
|
||||
}
|
||||
if(#t8)
|
||||
throw new _in::ReachabilityError::•();
|
||||
} =>#t7;
|
||||
final core::bool #t14 = true;
|
||||
final dynamic #t15 = #t6;
|
||||
if(#t15 is core::List<dynamic> && #t15{core::List<dynamic>}.{core::List::length}{core::int}.{core::num::>=}(1){(core::num) → core::bool}) {
|
||||
final dynamic #t16 = #t15{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
|
||||
if(let final dynamic #t17 = c = #t16 in true) {
|
||||
#t14 = false;
|
||||
}
|
||||
}
|
||||
if(#t14)
|
||||
throw new _in::ReachabilityError::•();
|
||||
} =>#t6;
|
||||
return a.{core::num::+}(b){(core::num) → core::int}.{core::num::+}(c){(core::num) → core::int};
|
||||
}
|
||||
static method main() → dynamic {
|
||||
self::expectEquals(self::test1(core::_GrowableList::_literal1<core::int>(1)), 1);
|
||||
self::expectThrows(() → void => self::test1(core::_GrowableList::•<dynamic>(0)));
|
||||
self::expectThrows(() → void => self::test1(core::_GrowableList::_literal3<core::int>(1, 2, 3)));
|
||||
self::expectThrows(() → void => self::test1("foo"));
|
||||
self::expectThrows(() → void => self::test1(null));
|
||||
self::expectEquals(self::test2(core::_GrowableList::_literal1<core::int>(1)), 3);
|
||||
self::expectThrows(() → void => self::test2(1));
|
||||
}
|
||||
static method expectEquals(dynamic x, dynamic y) → dynamic {
|
||||
if(!(x =={core::Object::==}{(core::Object) → core::bool} y)) {
|
||||
throw "Expected ${x} to be equal to ${y}.";
|
||||
}
|
||||
}
|
||||
static method expectThrows(() → void f) → dynamic {
|
||||
core::bool hasThrown = true;
|
||||
try {
|
||||
f(){() → void};
|
||||
hasThrown = false;
|
||||
}
|
||||
on core::Object catch(final core::Object e) {
|
||||
}
|
||||
if(!hasThrown) {
|
||||
throw "Expected the function to throw.";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
test1(dynamic x) {}
|
||||
test2(dynamic x) {}
|
||||
main() {}
|
||||
expectEquals(x, y) {}
|
||||
expectThrows(void Function() f) {}
|
|
@ -0,0 +1,5 @@
|
|||
expectEquals(x, y) {}
|
||||
expectThrows(void Function() f) {}
|
||||
main() {}
|
||||
test1(dynamic x) {}
|
||||
test2(dynamic x) {}
|
|
@ -0,0 +1,80 @@
|
|||
library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "dart:_internal" as _in;
|
||||
|
||||
static method test1(dynamic x) → dynamic {
|
||||
core::int a;
|
||||
block {
|
||||
final dynamic #t1 = x;
|
||||
final core::bool #t2 = true;
|
||||
final dynamic #t3 = #t1;
|
||||
if(#t3 is core::List<dynamic> && #t3{core::List<dynamic>}.{core::List::length}{core::int}.{core::num::==}(1){(core::Object) → core::bool}) {
|
||||
final dynamic #t4 = #t3{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
|
||||
if(let final dynamic #t5 = a = #t4 in true) {
|
||||
#t2 = false;
|
||||
}
|
||||
}
|
||||
if(#t2)
|
||||
throw new _in::ReachabilityError::•();
|
||||
} =>#t1;
|
||||
return a;
|
||||
}
|
||||
static method test2(dynamic x) → dynamic {
|
||||
core::int a;
|
||||
core::int b;
|
||||
core::int c;
|
||||
block {
|
||||
final dynamic #t6 = block {
|
||||
final dynamic #t7 = x;
|
||||
final core::bool #t8 = true;
|
||||
final dynamic #t9 = #t7;
|
||||
if(#t9 is core::List<dynamic> && #t9{core::List<dynamic>}.{core::List::length}{core::int}.{core::num::>=}(1){(core::num) → core::bool}) {
|
||||
final dynamic #t10 = #t9{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
|
||||
final dynamic #t11 = #t10;
|
||||
if((let final dynamic #t12 = a = #t11 in true) && (let final dynamic #t13 = b = #t11 in true)) {
|
||||
#t8 = false;
|
||||
}
|
||||
}
|
||||
if(#t8)
|
||||
throw new _in::ReachabilityError::•();
|
||||
} =>#t7;
|
||||
final core::bool #t14 = true;
|
||||
final dynamic #t15 = #t6;
|
||||
if(#t15 is core::List<dynamic> && #t15{core::List<dynamic>}.{core::List::length}{core::int}.{core::num::>=}(1){(core::num) → core::bool}) {
|
||||
final dynamic #t16 = #t15{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
|
||||
if(let final dynamic #t17 = c = #t16 in true) {
|
||||
#t14 = false;
|
||||
}
|
||||
}
|
||||
if(#t14)
|
||||
throw new _in::ReachabilityError::•();
|
||||
} =>#t6;
|
||||
return a.{core::num::+}(b){(core::num) → core::int}.{core::num::+}(c){(core::num) → core::int};
|
||||
}
|
||||
static method main() → dynamic {
|
||||
self::expectEquals(self::test1(<core::int>[1]), 1);
|
||||
self::expectThrows(() → void => self::test1(<dynamic>[]));
|
||||
self::expectThrows(() → void => self::test1(<core::int>[1, 2, 3]));
|
||||
self::expectThrows(() → void => self::test1("foo"));
|
||||
self::expectThrows(() → void => self::test1(null));
|
||||
self::expectEquals(self::test2(<core::int>[1]), 3);
|
||||
self::expectThrows(() → void => self::test2(1));
|
||||
}
|
||||
static method expectEquals(dynamic x, dynamic y) → dynamic {
|
||||
if(!(x =={core::Object::==}{(core::Object) → core::bool} y)) {
|
||||
throw "Expected ${x} to be equal to ${y}.";
|
||||
}
|
||||
}
|
||||
static method expectThrows(() → void f) → dynamic {
|
||||
core::bool hasThrown = true;
|
||||
try {
|
||||
f(){() → void};
|
||||
hasThrown = false;
|
||||
}
|
||||
on core::Object catch(final core::Object e) {
|
||||
}
|
||||
if(!hasThrown) {
|
||||
throw "Expected the function to throw.";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "dart:_internal" as _in;
|
||||
|
||||
static method test1(dynamic x) → dynamic {
|
||||
core::int a;
|
||||
block {
|
||||
final dynamic #t1 = x;
|
||||
final core::bool #t2 = true;
|
||||
final dynamic #t3 = #t1;
|
||||
if(#t3 is core::List<dynamic> && #t3{core::List<dynamic>}.{core::List::length}{core::int}.{core::num::==}(1){(core::Object) → core::bool}) {
|
||||
final dynamic #t4 = #t3{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
|
||||
if(let final dynamic #t5 = a = #t4 in true) {
|
||||
#t2 = false;
|
||||
}
|
||||
}
|
||||
if(#t2)
|
||||
throw new _in::ReachabilityError::•();
|
||||
} =>#t1;
|
||||
return a;
|
||||
}
|
||||
static method test2(dynamic x) → dynamic {
|
||||
core::int a;
|
||||
core::int b;
|
||||
core::int c;
|
||||
block {
|
||||
final dynamic #t6 = block {
|
||||
final dynamic #t7 = x;
|
||||
final core::bool #t8 = true;
|
||||
final dynamic #t9 = #t7;
|
||||
if(#t9 is core::List<dynamic> && #t9{core::List<dynamic>}.{core::List::length}{core::int}.{core::num::>=}(1){(core::num) → core::bool}) {
|
||||
final dynamic #t10 = #t9{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
|
||||
final dynamic #t11 = #t10;
|
||||
if((let final dynamic #t12 = a = #t11 in true) && (let final dynamic #t13 = b = #t11 in true)) {
|
||||
#t8 = false;
|
||||
}
|
||||
}
|
||||
if(#t8)
|
||||
throw new _in::ReachabilityError::•();
|
||||
} =>#t7;
|
||||
final core::bool #t14 = true;
|
||||
final dynamic #t15 = #t6;
|
||||
if(#t15 is core::List<dynamic> && #t15{core::List<dynamic>}.{core::List::length}{core::int}.{core::num::>=}(1){(core::num) → core::bool}) {
|
||||
final dynamic #t16 = #t15{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
|
||||
if(let final dynamic #t17 = c = #t16 in true) {
|
||||
#t14 = false;
|
||||
}
|
||||
}
|
||||
if(#t14)
|
||||
throw new _in::ReachabilityError::•();
|
||||
} =>#t6;
|
||||
return a.{core::num::+}(b){(core::num) → core::int}.{core::num::+}(c){(core::num) → core::int};
|
||||
}
|
||||
static method main() → dynamic {
|
||||
self::expectEquals(self::test1(<core::int>[1]), 1);
|
||||
self::expectThrows(() → void => self::test1(<dynamic>[]));
|
||||
self::expectThrows(() → void => self::test1(<core::int>[1, 2, 3]));
|
||||
self::expectThrows(() → void => self::test1("foo"));
|
||||
self::expectThrows(() → void => self::test1(null));
|
||||
self::expectEquals(self::test2(<core::int>[1]), 3);
|
||||
self::expectThrows(() → void => self::test2(1));
|
||||
}
|
||||
static method expectEquals(dynamic x, dynamic y) → dynamic {
|
||||
if(!(x =={core::Object::==}{(core::Object) → core::bool} y)) {
|
||||
throw "Expected ${x} to be equal to ${y}.";
|
||||
}
|
||||
}
|
||||
static method expectThrows(() → void f) → dynamic {
|
||||
core::bool hasThrown = true;
|
||||
try {
|
||||
f(){() → void};
|
||||
hasThrown = false;
|
||||
}
|
||||
on core::Object catch(final core::Object e) {
|
||||
}
|
||||
if(!hasThrown) {
|
||||
throw "Expected the function to throw.";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
|
||||
static method test1(dynamic x) → dynamic
|
||||
;
|
||||
static method test2(dynamic x) → dynamic
|
||||
;
|
||||
static method main() → dynamic
|
||||
;
|
||||
static method expectEquals(dynamic x, dynamic y) → dynamic
|
||||
;
|
||||
static method expectThrows(() → void f) → dynamic
|
||||
;
|
|
@ -0,0 +1,80 @@
|
|||
library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "dart:_internal" as _in;
|
||||
|
||||
static method test1(dynamic x) → dynamic {
|
||||
core::int a;
|
||||
block {
|
||||
final dynamic #t1 = x;
|
||||
final core::bool #t2 = true;
|
||||
final dynamic #t3 = #t1;
|
||||
if(#t3 is core::List<dynamic> && #t3{core::List<dynamic>}.{core::List::length}{core::int}.{core::num::==}(1){(core::Object) → core::bool}) {
|
||||
final dynamic #t4 = #t3{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
|
||||
if(let final dynamic #t5 = a = #t4 in true) {
|
||||
#t2 = false;
|
||||
}
|
||||
}
|
||||
if(#t2)
|
||||
throw new _in::ReachabilityError::•();
|
||||
} =>#t1;
|
||||
return a;
|
||||
}
|
||||
static method test2(dynamic x) → dynamic {
|
||||
core::int a;
|
||||
core::int b;
|
||||
core::int c;
|
||||
block {
|
||||
final dynamic #t6 = block {
|
||||
final dynamic #t7 = x;
|
||||
final core::bool #t8 = true;
|
||||
final dynamic #t9 = #t7;
|
||||
if(#t9 is core::List<dynamic> && #t9{core::List<dynamic>}.{core::List::length}{core::int}.{core::num::>=}(1){(core::num) → core::bool}) {
|
||||
final dynamic #t10 = #t9{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
|
||||
final dynamic #t11 = #t10;
|
||||
if((let final dynamic #t12 = a = #t11 in true) && (let final dynamic #t13 = b = #t11 in true)) {
|
||||
#t8 = false;
|
||||
}
|
||||
}
|
||||
if(#t8)
|
||||
throw new _in::ReachabilityError::•();
|
||||
} =>#t7;
|
||||
final core::bool #t14 = true;
|
||||
final dynamic #t15 = #t6;
|
||||
if(#t15 is core::List<dynamic> && #t15{core::List<dynamic>}.{core::List::length}{core::int}.{core::num::>=}(1){(core::num) → core::bool}) {
|
||||
final dynamic #t16 = #t15{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
|
||||
if(let final dynamic #t17 = c = #t16 in true) {
|
||||
#t14 = false;
|
||||
}
|
||||
}
|
||||
if(#t14)
|
||||
throw new _in::ReachabilityError::•();
|
||||
} =>#t6;
|
||||
return a.{core::num::+}(b){(core::num) → core::int}.{core::num::+}(c){(core::num) → core::int};
|
||||
}
|
||||
static method main() → dynamic {
|
||||
self::expectEquals(self::test1(core::_GrowableList::_literal1<core::int>(1)), 1);
|
||||
self::expectThrows(() → void => self::test1(core::_GrowableList::•<dynamic>(0)));
|
||||
self::expectThrows(() → void => self::test1(core::_GrowableList::_literal3<core::int>(1, 2, 3)));
|
||||
self::expectThrows(() → void => self::test1("foo"));
|
||||
self::expectThrows(() → void => self::test1(null));
|
||||
self::expectEquals(self::test2(core::_GrowableList::_literal1<core::int>(1)), 3);
|
||||
self::expectThrows(() → void => self::test2(1));
|
||||
}
|
||||
static method expectEquals(dynamic x, dynamic y) → dynamic {
|
||||
if(!(x =={core::Object::==}{(core::Object) → core::bool} y)) {
|
||||
throw "Expected ${x} to be equal to ${y}.";
|
||||
}
|
||||
}
|
||||
static method expectThrows(() → void f) → dynamic {
|
||||
core::bool hasThrown = true;
|
||||
try {
|
||||
f(){() → void};
|
||||
hasThrown = false;
|
||||
}
|
||||
on core::Object catch(final core::Object e) {
|
||||
}
|
||||
if(!hasThrown) {
|
||||
throw "Expected the function to throw.";
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue