mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 13:18:09 +00:00
[cfe] Add support for c-style pattern-for elements in lists
Part of https://github.com/dart-lang/sdk/issues/49749 Change-Id: Iafc0239535dd89d0ff4bfa99bd10cdb3978b42ea Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/284224 Reviewed-by: Johnni Winther <johnniwinther@google.com> Commit-Queue: Chloe Stefantsova <cstefantsova@google.com>
This commit is contained in:
parent
3424cc8db7
commit
3ab2dfaaaa
|
@ -4118,12 +4118,33 @@ class BodyBuilder extends StackListenerImpl
|
|||
|
||||
@override
|
||||
void endForControlFlow(Token token) {
|
||||
assert(checkState(token, <ValueKind>[
|
||||
/* entry = */ unionOfKinds(<ValueKind>[
|
||||
ValueKinds.Generator,
|
||||
ValueKinds.ExpressionOrNull,
|
||||
ValueKinds.Statement,
|
||||
ValueKinds.ParserRecovery,
|
||||
ValueKinds.MapLiteralEntry,
|
||||
]),
|
||||
/* update expression count = */ ValueKinds.Integer,
|
||||
/* left separator = */ ValueKinds.Token,
|
||||
/* left parenthesis = */ ValueKinds.Token,
|
||||
/* for keyword = */ ValueKinds.Token,
|
||||
]));
|
||||
debugEvent("ForControlFlow");
|
||||
Object? entry = pop();
|
||||
int updateExpressionCount = pop() as int;
|
||||
pop(); // left separator
|
||||
pop(); // left parenthesis
|
||||
Token forToken = pop() as Token;
|
||||
|
||||
assert(checkState(token, <ValueKind>[
|
||||
/* updates = */ ...repeatedKind(
|
||||
unionOfKinds(
|
||||
<ValueKind>[ValueKinds.Expression, ValueKinds.Generator]),
|
||||
updateExpressionCount),
|
||||
/* condition = */ ValueKinds.Statement,
|
||||
]));
|
||||
List<Expression> updates = popListForEffect(updateExpressionCount);
|
||||
Statement conditionStatement = popStatement(); // condition
|
||||
|
||||
|
@ -4142,6 +4163,7 @@ class BodyBuilder extends StackListenerImpl
|
|||
|
||||
// This is matched by the call to [beginNode] in
|
||||
// [handleForInitializerEmptyStatement],
|
||||
// [handleForInitializerPatternVariableAssignment],
|
||||
// [handleForInitializerExpressionStatement], and
|
||||
// [handleForInitializerLocalVariableDeclaration].
|
||||
AssignedVariablesNodeInfo assignedVariablesNodeInfo =
|
||||
|
@ -4169,9 +4191,18 @@ class BodyBuilder extends StackListenerImpl
|
|||
typeInferrer.assignedVariables.endNode(result);
|
||||
push(result);
|
||||
} else {
|
||||
ForElement result = forest.createForElement(offsetForToken(forToken),
|
||||
variables, condition, updates, toValue(entry));
|
||||
typeInferrer.assignedVariables.endNode(result);
|
||||
TreeNode result;
|
||||
ForElement forElement = result = forest.createForElement(
|
||||
offsetForToken(forToken),
|
||||
variables,
|
||||
condition,
|
||||
updates,
|
||||
toValue(entry));
|
||||
if (variableOrExpression is PatternVariableDeclaration) {
|
||||
result = forest.createPatternForElement(
|
||||
offsetForToken(forToken), variableOrExpression, forElement);
|
||||
}
|
||||
typeInferrer.assignedVariables.endNode(forElement);
|
||||
push(result);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -310,6 +310,16 @@ class Forest {
|
|||
..fileOffset = fileOffset;
|
||||
}
|
||||
|
||||
PatternForElement createPatternForElement(
|
||||
int fileOffset,
|
||||
PatternVariableDeclaration patternVariableDeclaration,
|
||||
ForElement forElement) {
|
||||
// ignore: unnecessary_null_comparison
|
||||
assert(fileOffset != null);
|
||||
return new PatternForElement(patternVariableDeclaration, forElement)
|
||||
..fileOffset = fileOffset;
|
||||
}
|
||||
|
||||
ForMapEntry createForMapEntry(
|
||||
int fileOffset,
|
||||
List<VariableDeclaration> variables,
|
||||
|
|
|
@ -4201,9 +4201,9 @@ class WildcardPattern extends Pattern {
|
|||
}
|
||||
|
||||
class PatternVariableDeclaration extends InternalStatement {
|
||||
final Pattern pattern;
|
||||
final Expression initializer;
|
||||
final bool isFinal;
|
||||
Pattern pattern;
|
||||
Expression initializer;
|
||||
bool isFinal;
|
||||
|
||||
PatternVariableDeclaration(this.pattern, this.initializer,
|
||||
{required int fileOffset, required this.isFinal}) {
|
||||
|
@ -4914,3 +4914,48 @@ class IfCaseMapEntry extends TreeNode
|
|||
return "IfCaseMapEntry(${toStringInternal()})";
|
||||
}
|
||||
}
|
||||
|
||||
class PatternForElement extends InternalExpression with ControlFlowElement {
|
||||
PatternVariableDeclaration patternVariableDeclaration;
|
||||
ForElement forElement;
|
||||
late List<Statement> replacement;
|
||||
|
||||
PatternForElement(this.patternVariableDeclaration, this.forElement);
|
||||
|
||||
@override
|
||||
ExpressionInferenceResult acceptInference(
|
||||
InferenceVisitorImpl visitor, DartType typeContext) {
|
||||
throw new UnsupportedError("PatternForElement.acceptInference");
|
||||
}
|
||||
|
||||
@override
|
||||
void toTextInternal(AstPrinter printer) {
|
||||
printer.write('for (');
|
||||
for (int index = 0; index < forElement.variables.length; index++) {
|
||||
if (index > 0) {
|
||||
printer.write(', ');
|
||||
}
|
||||
printer.writeVariableDeclaration(forElement.variables[index],
|
||||
includeModifiersAndType: index == 0);
|
||||
}
|
||||
printer.write('; ');
|
||||
if (forElement.condition != null) {
|
||||
printer.writeExpression(forElement.condition!);
|
||||
}
|
||||
printer.write('; ');
|
||||
printer.writeExpressions(forElement.updates);
|
||||
printer.write(') ');
|
||||
printer.writeExpression(forElement.body);
|
||||
}
|
||||
|
||||
@override
|
||||
MapLiteralEntry? toMapLiteralEntry(
|
||||
void Function(TreeNode from, TreeNode to) onConvertElement) {
|
||||
throw new UnimplementedError("toMapLiteralEntry");
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return "PatternForElement(${toStringInternal()})";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2348,6 +2348,87 @@ class InferenceVisitorImpl extends InferenceVisitorBase
|
|||
}
|
||||
flowAnalysis.for_end();
|
||||
return new ExpressionInferenceResult(bodyResult.inferredType, element);
|
||||
} else if (element is PatternForElement) {
|
||||
int? stackBase;
|
||||
assert(checkStackBase(element, stackBase = stackHeight));
|
||||
|
||||
PatternVariableDeclaration patternVariableDeclaration =
|
||||
element.patternVariableDeclaration;
|
||||
analyzePatternVariableDeclaration(
|
||||
patternVariableDeclaration,
|
||||
patternVariableDeclaration.pattern,
|
||||
patternVariableDeclaration.initializer,
|
||||
isFinal: patternVariableDeclaration.isFinal,
|
||||
isLate: false);
|
||||
|
||||
assert(checkStack(element, stackBase, [
|
||||
/* pattern = */ ValueKinds.Pattern,
|
||||
/* initializer = */ ValueKinds.Expression,
|
||||
]));
|
||||
|
||||
Object? rewrite = popRewrite(NullValues.Expression);
|
||||
if (!identical(patternVariableDeclaration.pattern, rewrite)) {
|
||||
patternVariableDeclaration.pattern = (rewrite as Pattern)
|
||||
..parent = patternVariableDeclaration;
|
||||
}
|
||||
|
||||
rewrite = popRewrite();
|
||||
if (!identical(patternVariableDeclaration.initializer, rewrite)) {
|
||||
patternVariableDeclaration.initializer = (rewrite as Expression)
|
||||
..parent = patternVariableDeclaration;
|
||||
}
|
||||
|
||||
MatchingCache matchingCache = createMatchingCache();
|
||||
MatchingExpressionVisitor matchingExpressionVisitor =
|
||||
new MatchingExpressionVisitor(matchingCache);
|
||||
// TODO(cstefantsova): Do we need a more precise type for the variable?
|
||||
DartType matchedType = const DynamicType();
|
||||
CacheableExpression matchedExpression =
|
||||
matchingCache.createRootExpression(
|
||||
patternVariableDeclaration.initializer, matchedType);
|
||||
|
||||
DelayedExpression matchingExpression = matchingExpressionVisitor
|
||||
.visitPattern(patternVariableDeclaration.pattern, matchedExpression);
|
||||
|
||||
matchingExpression.registerUse();
|
||||
|
||||
Expression readMatchingExpression =
|
||||
matchingExpression.createExpression(typeSchemaEnvironment);
|
||||
|
||||
List<Statement> replacementStatements = [
|
||||
...matchingCache.declarations,
|
||||
// TODO(cstefantsova): Figure out the right exception to throw.
|
||||
createIfStatement(
|
||||
createNot(readMatchingExpression),
|
||||
createExpressionStatement(createThrow(createConstructorInvocation(
|
||||
coreTypes.reachabilityErrorConstructor,
|
||||
createArguments([], fileOffset: element.fileOffset),
|
||||
fileOffset: element.fileOffset))),
|
||||
fileOffset: element.fileOffset),
|
||||
];
|
||||
if (replacementStatements.length > 1) {
|
||||
// If we need local declarations, create a new block to avoid naming
|
||||
// collision with declarations in the same parent block.
|
||||
replacementStatements = [
|
||||
createBlock(replacementStatements, fileOffset: element.fileOffset)
|
||||
];
|
||||
}
|
||||
replacementStatements = [
|
||||
...patternVariableDeclaration.pattern.declaredVariables,
|
||||
...replacementStatements,
|
||||
];
|
||||
element.replacement = replacementStatements;
|
||||
|
||||
ExpressionInferenceResult inferenceResult = inferElement(
|
||||
element.forElement,
|
||||
inferredTypeArgument,
|
||||
inferredSpreadTypes,
|
||||
inferredConditionTypes);
|
||||
element.forElement = (inferenceResult.expression as ForElement)
|
||||
..parent = element;
|
||||
|
||||
return new ExpressionInferenceResult(
|
||||
inferenceResult.inferredType, element);
|
||||
} else if (element is ForInElement) {
|
||||
ForInResult result;
|
||||
if (element.variable.name == null) {
|
||||
|
@ -2661,6 +2742,10 @@ class InferenceVisitorImpl extends InferenceVisitorBase
|
|||
} else if (element is ForElement) {
|
||||
_translateForElement(element, receiverType, elementType, result, body,
|
||||
isSet: isSet);
|
||||
} else if (element is PatternForElement) {
|
||||
_translatePatternForElement(
|
||||
element, receiverType, elementType, result, body,
|
||||
isSet: isSet);
|
||||
} else if (element is ForInElement) {
|
||||
_translateForInElement(element, receiverType, elementType, result, body,
|
||||
isSet: isSet);
|
||||
|
@ -2753,6 +2838,30 @@ class InferenceVisitorImpl extends InferenceVisitorBase
|
|||
body.add(loop);
|
||||
}
|
||||
|
||||
void _translatePatternForElement(
|
||||
PatternForElement element,
|
||||
InterfaceType receiverType,
|
||||
DartType elementType,
|
||||
VariableDeclaration result,
|
||||
List<Statement> body,
|
||||
{required bool isSet}) {
|
||||
List<Statement> statements = <Statement>[];
|
||||
_translateElement(
|
||||
element.forElement.body, receiverType, elementType, result, statements,
|
||||
isSet: isSet);
|
||||
Statement loopBody =
|
||||
statements.length == 1 ? statements.first : _createBlock(statements);
|
||||
ForStatement loop = _createForStatement(
|
||||
element.fileOffset,
|
||||
element.forElement.variables,
|
||||
element.forElement.condition,
|
||||
element.forElement.updates,
|
||||
loopBody);
|
||||
libraryBuilder.loader.dataForTesting?.registerAlias(element, loop);
|
||||
body.addAll(element.replacement);
|
||||
body.add(loop);
|
||||
}
|
||||
|
||||
void _translateForInElement(ForInElement element, InterfaceType receiverType,
|
||||
DartType elementType, VariableDeclaration result, List<Statement> body,
|
||||
{required bool isSet}) {
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright (c) 2023, 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) => [for (var [int i, int n] = x; i < n; i++) i];
|
||||
|
||||
main() {
|
||||
expectEquals(
|
||||
listToString(test1([0, 3])),
|
||||
listToString([0, 1, 2]),
|
||||
);
|
||||
expectEquals(
|
||||
listToString(test1([0, 0])),
|
||||
listToString([]),
|
||||
);
|
||||
expectThrows(() => test1({}));
|
||||
}
|
||||
|
||||
expectEquals(x, y) {
|
||||
if (x != y) {
|
||||
throw "Expected '${x}' to be equal to '${y}'.";
|
||||
}
|
||||
}
|
||||
|
||||
listToString(List list) => "[${list.map((e) => '${e}').join(',')}]";
|
||||
|
||||
expectThrows(void Function() f) {
|
||||
bool hasThrown = true;
|
||||
try {
|
||||
f();
|
||||
hasThrown = false;
|
||||
} catch (e) {}
|
||||
if (!hasThrown) {
|
||||
throw "Expected the function to throw.";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "dart:_internal" as _in;
|
||||
|
||||
static method test1(dynamic x) → dynamic
|
||||
return block {
|
||||
final core::List<core::int> #t1 = <core::int>[];
|
||||
core::int i;
|
||||
core::int n;
|
||||
{
|
||||
final dynamic #0#0 = x;
|
||||
late final dynamic #0#6 = #0#0{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
|
||||
late final dynamic #0#7 = #0#0{core::List<dynamic>}.{core::List::[]}(1){(core::int) → dynamic};
|
||||
if(!(#0#0 is{ForNonNullableByDefault} core::List<dynamic> && #0#0{core::List<dynamic>}.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (#0#6 is{ForNonNullableByDefault} core::int && (let final dynamic #t2 = i = #0#6{core::int} in true)) && (#0#7 is{ForNonNullableByDefault} core::int && (let final dynamic #t3 = n = #0#7{core::int} in true))))
|
||||
throw new _in::ReachabilityError::•();
|
||||
}
|
||||
for (core::int i = i, core::int n = n; i.{core::num::<}(n){(core::num) → core::bool}; i = i.{core::num::+}(1){(core::num) → core::int})
|
||||
#t1.{core::List::add}{Invariant}(i){(core::int) → void};
|
||||
} =>#t1;
|
||||
static method main() → dynamic {
|
||||
self::expectEquals(self::listToString(self::test1(<core::int>[0, 3]) as{TypeError,ForDynamic,ForNonNullableByDefault} core::List<dynamic>), self::listToString(<dynamic>[0, 1, 2]));
|
||||
self::expectEquals(self::listToString(self::test1(<core::int>[0, 0]) as{TypeError,ForDynamic,ForNonNullableByDefault} core::List<dynamic>), self::listToString(<dynamic>[]));
|
||||
self::expectThrows(() → void => self::test1(<dynamic, dynamic>{}));
|
||||
}
|
||||
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 listToString(core::List<dynamic> list) → dynamic
|
||||
return "[${list.{core::Iterable::map}<core::String>((dynamic e) → core::String => "${e}"){((dynamic) → core::String) → core::Iterable<core::String>}.{core::Iterable::join}(","){([core::String]) → core::String}}]";
|
||||
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.";
|
||||
}
|
||||
}
|
||||
|
||||
constants {
|
||||
#C1 = 2
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "dart:_internal" as _in;
|
||||
|
||||
static method test1(dynamic x) → dynamic
|
||||
return block {
|
||||
final core::List<core::int> #t1 = core::_GrowableList::•<core::int>(0);
|
||||
core::int i;
|
||||
core::int n;
|
||||
{
|
||||
final dynamic #0#0 = x;
|
||||
function ##0#6#initializer() → dynamic
|
||||
return #0#0{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
|
||||
late final dynamic #0#6 = ##0#6#initializer(){() → dynamic};
|
||||
function ##0#7#initializer() → dynamic
|
||||
return #0#0{core::List<dynamic>}.{core::List::[]}(1){(core::int) → dynamic};
|
||||
late final dynamic #0#7 = ##0#7#initializer(){() → dynamic};
|
||||
if(!(#0#0 is{ForNonNullableByDefault} core::List<dynamic> && #0#0{core::List<dynamic>}.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (#0#6 is{ForNonNullableByDefault} core::int && (let final core::int #t2 = i = #0#6{core::int} in true)) && (#0#7 is{ForNonNullableByDefault} core::int && (let final core::int #t3 = n = #0#7{core::int} in true))))
|
||||
throw new _in::ReachabilityError::•();
|
||||
}
|
||||
for (core::int i = i, core::int n = n; i.{core::num::<}(n){(core::num) → core::bool}; i = i.{core::num::+}(1){(core::num) → core::int})
|
||||
#t1.{core::List::add}{Invariant}(i){(core::int) → void};
|
||||
} =>#t1;
|
||||
static method main() → dynamic {
|
||||
self::expectEquals(self::listToString(self::test1(core::_GrowableList::_literal2<core::int>(0, 3)) as{TypeError,ForDynamic,ForNonNullableByDefault} core::List<dynamic>), self::listToString(core::_GrowableList::_literal3<dynamic>(0, 1, 2)));
|
||||
self::expectEquals(self::listToString(self::test1(core::_GrowableList::_literal2<core::int>(0, 0)) as{TypeError,ForDynamic,ForNonNullableByDefault} core::List<dynamic>), self::listToString(core::_GrowableList::•<dynamic>(0)));
|
||||
self::expectThrows(() → void => self::test1(<dynamic, dynamic>{}));
|
||||
}
|
||||
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 listToString(core::List<dynamic> list) → dynamic
|
||||
return "[${list.{core::Iterable::map}<core::String>((dynamic e) → core::String => "${e}"){((dynamic) → core::String) → core::Iterable<core::String>}.{core::Iterable::join}(","){([core::String]) → core::String}}]";
|
||||
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.";
|
||||
}
|
||||
}
|
||||
|
||||
constants {
|
||||
#C1 = 2
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
test1(dynamic x) => [for (var [;int ;i, int n] = x; i < n; i++) i];
|
||||
main() {}
|
||||
expectEquals(x, y) {}
|
||||
listToString(List list) => "[${list.map((e) => '${e}').join(',')}]";
|
||||
expectThrows(void Function() f) {}
|
|
@ -0,0 +1,48 @@
|
|||
library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "dart:_internal" as _in;
|
||||
|
||||
static method test1(dynamic x) → dynamic
|
||||
return block {
|
||||
final core::List<core::int> #t1 = <core::int>[];
|
||||
core::int i;
|
||||
core::int n;
|
||||
{
|
||||
final dynamic #0#0 = x;
|
||||
late final dynamic #0#6 = #0#0{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
|
||||
late final dynamic #0#7 = #0#0{core::List<dynamic>}.{core::List::[]}(1){(core::int) → dynamic};
|
||||
if(!(#0#0 is{ForNonNullableByDefault} core::List<dynamic> && #0#0{core::List<dynamic>}.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (#0#6 is{ForNonNullableByDefault} core::int && (let final dynamic #t2 = i = #0#6{core::int} in true)) && (#0#7 is{ForNonNullableByDefault} core::int && (let final dynamic #t3 = n = #0#7{core::int} in true))))
|
||||
throw new _in::ReachabilityError::•();
|
||||
}
|
||||
for (core::int i = i, core::int n = n; i.{core::num::<}(n){(core::num) → core::bool}; i = i.{core::num::+}(1){(core::num) → core::int})
|
||||
#t1.{core::List::add}{Invariant}(i){(core::int) → void};
|
||||
} =>#t1;
|
||||
static method main() → dynamic {
|
||||
self::expectEquals(self::listToString(self::test1(<core::int>[0, 3]) as{TypeError,ForDynamic,ForNonNullableByDefault} core::List<dynamic>), self::listToString(<dynamic>[0, 1, 2]));
|
||||
self::expectEquals(self::listToString(self::test1(<core::int>[0, 0]) as{TypeError,ForDynamic,ForNonNullableByDefault} core::List<dynamic>), self::listToString(<dynamic>[]));
|
||||
self::expectThrows(() → void => self::test1(<dynamic, dynamic>{}));
|
||||
}
|
||||
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 listToString(core::List<dynamic> list) → dynamic
|
||||
return "[${list.{core::Iterable::map}<core::String>((dynamic e) → core::String => "${e}"){((dynamic) → core::String) → core::Iterable<core::String>}.{core::Iterable::join}(","){([core::String]) → core::String}}]";
|
||||
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.";
|
||||
}
|
||||
}
|
||||
|
||||
constants {
|
||||
#C1 = 2
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "dart:_internal" as _in;
|
||||
|
||||
static method test1(dynamic x) → dynamic
|
||||
return block {
|
||||
final core::List<core::int> #t1 = <core::int>[];
|
||||
core::int i;
|
||||
core::int n;
|
||||
{
|
||||
final dynamic #0#0 = x;
|
||||
late final dynamic #0#6 = #0#0{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
|
||||
late final dynamic #0#7 = #0#0{core::List<dynamic>}.{core::List::[]}(1){(core::int) → dynamic};
|
||||
if(!(#0#0 is{ForNonNullableByDefault} core::List<dynamic> && #0#0{core::List<dynamic>}.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (#0#6 is{ForNonNullableByDefault} core::int && (let final dynamic #t2 = i = #0#6{core::int} in true)) && (#0#7 is{ForNonNullableByDefault} core::int && (let final dynamic #t3 = n = #0#7{core::int} in true))))
|
||||
throw new _in::ReachabilityError::•();
|
||||
}
|
||||
for (core::int i = i, core::int n = n; i.{core::num::<}(n){(core::num) → core::bool}; i = i.{core::num::+}(1){(core::num) → core::int})
|
||||
#t1.{core::List::add}{Invariant}(i){(core::int) → void};
|
||||
} =>#t1;
|
||||
static method main() → dynamic {
|
||||
self::expectEquals(self::listToString(self::test1(<core::int>[0, 3]) as{TypeError,ForDynamic,ForNonNullableByDefault} core::List<dynamic>), self::listToString(<dynamic>[0, 1, 2]));
|
||||
self::expectEquals(self::listToString(self::test1(<core::int>[0, 0]) as{TypeError,ForDynamic,ForNonNullableByDefault} core::List<dynamic>), self::listToString(<dynamic>[]));
|
||||
self::expectThrows(() → void => self::test1(<dynamic, dynamic>{}));
|
||||
}
|
||||
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 listToString(core::List<dynamic> list) → dynamic
|
||||
return "[${list.{core::Iterable::map}<core::String>((dynamic e) → core::String => "${e}"){((dynamic) → core::String) → core::Iterable<core::String>}.{core::Iterable::join}(","){([core::String]) → core::String}}]";
|
||||
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.";
|
||||
}
|
||||
}
|
||||
|
||||
constants {
|
||||
#C1 = 2
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
static method test1(dynamic x) → dynamic
|
||||
;
|
||||
static method main() → dynamic
|
||||
;
|
||||
static method expectEquals(dynamic x, dynamic y) → dynamic
|
||||
;
|
||||
static method listToString(core::List<dynamic> list) → dynamic
|
||||
;
|
||||
static method expectThrows(() → void f) → dynamic
|
||||
;
|
|
@ -0,0 +1,52 @@
|
|||
library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "dart:_internal" as _in;
|
||||
|
||||
static method test1(dynamic x) → dynamic
|
||||
return block {
|
||||
final core::List<core::int> #t1 = core::_GrowableList::•<core::int>(0);
|
||||
core::int i;
|
||||
core::int n;
|
||||
{
|
||||
final dynamic #0#0 = x;
|
||||
function ##0#6#initializer() → dynamic
|
||||
return #0#0{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
|
||||
late final dynamic #0#6 = ##0#6#initializer(){() → dynamic};
|
||||
function ##0#7#initializer() → dynamic
|
||||
return #0#0{core::List<dynamic>}.{core::List::[]}(1){(core::int) → dynamic};
|
||||
late final dynamic #0#7 = ##0#7#initializer(){() → dynamic};
|
||||
if(!(#0#0 is{ForNonNullableByDefault} core::List<dynamic> && #0#0{core::List<dynamic>}.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (#0#6 is{ForNonNullableByDefault} core::int && (let final core::int #t2 = i = #0#6{core::int} in true)) && (#0#7 is{ForNonNullableByDefault} core::int && (let final core::int #t3 = n = #0#7{core::int} in true))))
|
||||
throw new _in::ReachabilityError::•();
|
||||
}
|
||||
for (core::int i = i, core::int n = n; i.{core::num::<}(n){(core::num) → core::bool}; i = i.{core::num::+}(1){(core::num) → core::int})
|
||||
#t1.{core::List::add}{Invariant}(i){(core::int) → void};
|
||||
} =>#t1;
|
||||
static method main() → dynamic {
|
||||
self::expectEquals(self::listToString(self::test1(core::_GrowableList::_literal2<core::int>(0, 3)) as{TypeError,ForDynamic,ForNonNullableByDefault} core::List<dynamic>), self::listToString(core::_GrowableList::_literal3<dynamic>(0, 1, 2)));
|
||||
self::expectEquals(self::listToString(self::test1(core::_GrowableList::_literal2<core::int>(0, 0)) as{TypeError,ForDynamic,ForNonNullableByDefault} core::List<dynamic>), self::listToString(core::_GrowableList::•<dynamic>(0)));
|
||||
self::expectThrows(() → void => self::test1(<dynamic, dynamic>{}));
|
||||
}
|
||||
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 listToString(core::List<dynamic> list) → dynamic
|
||||
return "[${list.{core::Iterable::map}<core::String>((dynamic e) → core::String => "${e}"){((dynamic) → core::String) → core::Iterable<core::String>}.{core::Iterable::join}(","){([core::String]) → core::String}}]";
|
||||
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.";
|
||||
}
|
||||
}
|
||||
|
||||
constants {
|
||||
#C1 = 2
|
||||
}
|
|
@ -167,6 +167,7 @@ patterns/pattern_matching: FormatterCrash
|
|||
patterns/pattern_types: FormatterCrash
|
||||
patterns/records/destructuring: FormatterCrash
|
||||
patterns/records/record_pattern_inside_if_case: FormatterCrash
|
||||
patterns/simple_c_style_pattern_for_in_collections: FormatterCrash
|
||||
patterns/simple_if_case_in_lists: FormatterCrash
|
||||
patterns/simple_if_case_map_entries: FormatterCrash
|
||||
patterns/switchExpression_empty: FormatterCrash
|
||||
|
|
Loading…
Reference in a new issue