[cfe][InternalNodes] Add InternalCatch
This is a step towards separating Variable from InternalVariable. Change-Id: I5941148e55ae7105a5798df557db512fce3d8255 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/509941 Reviewed-by: Chloe Stefantsova <cstefantsova@google.com> Commit-Queue: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
committed by
dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent
8492bfd7ac
commit
19db32f041
@@ -5935,18 +5935,18 @@ class BodyBuilderImpl extends StackListenerImpl
|
||||
assignedVariables.deferNode(),
|
||||
);
|
||||
}
|
||||
List<Catch>? catchBlocks;
|
||||
List<InternalCatch>? catchBlocks;
|
||||
List<Statement>? compileTimeErrors;
|
||||
if (catchCount != 0) {
|
||||
List<Object?> catchBlocksAndErrors = const FixedNullableList<Object?>()
|
||||
.pop(stack, catchCount * 2)!;
|
||||
catchBlocks = new List<Catch>.filled(
|
||||
catchBlocks = new List<InternalCatch>.filled(
|
||||
catchCount,
|
||||
dummyCatch,
|
||||
dummyInternalCatch,
|
||||
growable: true,
|
||||
);
|
||||
for (int i = 0; i < catchCount; i++) {
|
||||
catchBlocks[i] = catchBlocksAndErrors[i * 2] as Catch;
|
||||
catchBlocks[i] = catchBlocksAndErrors[i * 2] as InternalCatch;
|
||||
Statement? error = catchBlocksAndErrors[i * 2 + 1] as Statement?;
|
||||
if (error != null) {
|
||||
compileTimeErrors ??= <Statement>[];
|
||||
|
||||
@@ -1341,3 +1341,16 @@ WildcardPattern createWildcardPattern({
|
||||
}) {
|
||||
return new WildcardPattern(type)..fileOffset = fileOffset;
|
||||
}
|
||||
|
||||
Catch createCatch({
|
||||
required DartType guard,
|
||||
required Variable? exception,
|
||||
required Variable? stackTrace,
|
||||
required Statement body,
|
||||
required Scope? scope,
|
||||
required int fileOffset,
|
||||
}) {
|
||||
return new Catch(exception, body, guard: guard, stackTrace: stackTrace)
|
||||
..scope = scope
|
||||
..fileOffset = fileOffset;
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ abstract class InternalStatement extends AuxiliaryStatement {
|
||||
|
||||
class TryStatement extends InternalStatement {
|
||||
Statement tryBlock;
|
||||
List<Catch> catchBlocks;
|
||||
List<InternalCatch> catchBlocks;
|
||||
Statement? finallyBlock;
|
||||
|
||||
new(this.tryBlock, this.catchBlocks, this.finallyBlock) {
|
||||
@@ -132,9 +132,9 @@ class TryStatement extends InternalStatement {
|
||||
void toTextInternal(AstPrinter printer) {
|
||||
printer.write('try ');
|
||||
printer.writeStatement(tryBlock);
|
||||
for (Catch catchBlock in catchBlocks) {
|
||||
for (InternalCatch catchBlock in catchBlocks) {
|
||||
printer.write(' ');
|
||||
printer.writeCatch(catchBlock);
|
||||
catchBlock.toTextInternal(printer);
|
||||
}
|
||||
if (finallyBlock != null) {
|
||||
printer.write(' finally ');
|
||||
@@ -6981,7 +6981,6 @@ class InternalFunctionDeclaration extends InternalStatement {
|
||||
}
|
||||
}
|
||||
|
||||
// Coverage-ignore(suite): Not run.
|
||||
sealed class InternalPattern extends TreeNode with InternalTreeNode {
|
||||
/// Returns the variable name that this pattern defines, if any.
|
||||
///
|
||||
@@ -7000,27 +6999,33 @@ sealed class InternalPattern extends TreeNode with InternalTreeNode {
|
||||
List<InternalVariable> get declaredVariables;
|
||||
|
||||
@override
|
||||
// Coverage-ignore(suite): Not run.
|
||||
R accept<R>(TreeVisitor<R> v) =>
|
||||
unsupported("${runtimeType}.accept", -1, null);
|
||||
|
||||
@override
|
||||
// Coverage-ignore(suite): Not run.
|
||||
R accept1<R, A>(TreeVisitor1<R, A> v, A arg) =>
|
||||
unsupported("${runtimeType}.accept", -1, null);
|
||||
|
||||
@override
|
||||
// Coverage-ignore(suite): Not run.
|
||||
void replaceChild(TreeNode child, TreeNode replacement) {
|
||||
// Do nothing. The node should not be part of the resulting AST, anyway.
|
||||
}
|
||||
|
||||
@override
|
||||
// Coverage-ignore(suite): Not run.
|
||||
void visitChildren(Visitor<dynamic> v) =>
|
||||
unsupported("${runtimeType}.visitChildren", -1, null);
|
||||
|
||||
@override
|
||||
// Coverage-ignore(suite): Not run.
|
||||
void transformChildren(Transformer v) =>
|
||||
unsupported("${runtimeType}.transformChildren", -1, null);
|
||||
|
||||
@override
|
||||
// Coverage-ignore(suite): Not run.
|
||||
void transformOrRemoveChildren(RemovingTransformer v) {
|
||||
unsupported("${runtimeType}.transformOrRemoveChildren", -1, null);
|
||||
}
|
||||
@@ -8233,6 +8238,89 @@ class InternalContinueSwitchStatement extends InternalStatement {
|
||||
}
|
||||
}
|
||||
|
||||
class InternalCatch extends TreeNode with InternalTreeNode {
|
||||
final DartType guard; // Not null, defaults to dynamic.
|
||||
final InternalVariable? exception;
|
||||
final InternalVariable? stackTrace;
|
||||
final Statement body;
|
||||
|
||||
new({
|
||||
required this.exception,
|
||||
required this.body,
|
||||
this.guard = const DynamicType(),
|
||||
this.stackTrace,
|
||||
required int fileOffset,
|
||||
}) {
|
||||
exception?.parent = this;
|
||||
stackTrace?.parent = this;
|
||||
body.parent = this;
|
||||
this.fileOffset = fileOffset;
|
||||
}
|
||||
|
||||
@override
|
||||
// Coverage-ignore(suite): Not run.
|
||||
R accept<R>(TreeVisitor<R> v) {
|
||||
unsupported("${runtimeType}.accept on ${v.runtimeType}", -1, null);
|
||||
}
|
||||
|
||||
@override
|
||||
// Coverage-ignore(suite): Not run.
|
||||
R accept1<R, A>(TreeVisitor1<R, A> v, A arg) {
|
||||
unsupported("${runtimeType}.accept1 on ${v.runtimeType}", -1, null);
|
||||
}
|
||||
|
||||
@override
|
||||
// Coverage-ignore(suite): Not run.
|
||||
void toTextInternal(AstPrinter printer) {
|
||||
bool isImplicitType(DartType type) {
|
||||
if (type is DynamicType) {
|
||||
return true;
|
||||
}
|
||||
if (type is InterfaceType &&
|
||||
type.classReference.node != null &&
|
||||
type.classNode.name == 'Object') {
|
||||
Uri uri = type.classNode.enclosingLibrary.importUri;
|
||||
return uri.isScheme('dart') &&
|
||||
uri.path == 'core' &&
|
||||
type.nullability == Nullability.nonNullable;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (exception != null) {
|
||||
if (!isImplicitType(guard)) {
|
||||
printer.write('on ');
|
||||
printer.writeType(guard);
|
||||
printer.write(' ');
|
||||
}
|
||||
printer.write('catch (');
|
||||
printer.writeVariableInitialization(
|
||||
exception!.astVariable,
|
||||
includeModifiersAndType: false,
|
||||
includeInitializer: false,
|
||||
);
|
||||
if (stackTrace != null) {
|
||||
printer.write(', ');
|
||||
printer.writeVariableInitialization(
|
||||
stackTrace!.astVariable,
|
||||
includeModifiersAndType: false,
|
||||
);
|
||||
}
|
||||
printer.write(') ');
|
||||
} else {
|
||||
printer.write('on ');
|
||||
printer.writeType(guard);
|
||||
printer.write(' ');
|
||||
}
|
||||
printer.writeStatement(body);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return "$runtimeType(${toStringInternal()})";
|
||||
}
|
||||
}
|
||||
|
||||
final InternalPattern dummyInternalPattern = new InternalConstantPattern(
|
||||
expression: dummyExpression,
|
||||
fileOffset: TreeNode.noOffset,
|
||||
@@ -8261,3 +8349,16 @@ final InternalSwitchCase dummyInternalSwitchCase =
|
||||
labels: null,
|
||||
fileOffset: TreeNode.noOffset,
|
||||
);
|
||||
|
||||
final InternalCatch dummyInternalCatch = new InternalCatch(
|
||||
exception: dummyInternalVariable,
|
||||
body: dummyStatement,
|
||||
stackTrace: dummyInternalVariable,
|
||||
fileOffset: TreeNode.noOffset,
|
||||
);
|
||||
|
||||
final InternalVariable dummyInternalVariable = new VariableDeclarationImpl(
|
||||
null,
|
||||
fileOffset: TreeNode.noOffset,
|
||||
isSynthesized: true,
|
||||
);
|
||||
|
||||
@@ -172,7 +172,7 @@ InternalPattern createCastPattern(
|
||||
}
|
||||
|
||||
/// Return a representation of a catch clause.
|
||||
Catch createCatch(
|
||||
InternalCatch createCatch(
|
||||
int fileOffset,
|
||||
DartType exceptionType,
|
||||
InternalVariable? exceptionParameter,
|
||||
@@ -180,12 +180,13 @@ Catch createCatch(
|
||||
DartType stackTraceType,
|
||||
Statement body,
|
||||
) {
|
||||
return new Catch(
|
||||
exceptionParameter?.asVariableDeclaration,
|
||||
body,
|
||||
return new InternalCatch(
|
||||
exception: exceptionParameter,
|
||||
body: body,
|
||||
guard: exceptionType,
|
||||
stackTrace: stackTraceParameter?.asVariableDeclaration,
|
||||
)..fileOffset = fileOffset;
|
||||
stackTrace: stackTraceParameter,
|
||||
fileOffset: fileOffset,
|
||||
);
|
||||
}
|
||||
|
||||
InternalVariable createCatchVariable({
|
||||
@@ -1583,10 +1584,10 @@ Expression createThrow(int fileOffset, Expression expression) {
|
||||
Statement createTryStatement(
|
||||
int fileOffset,
|
||||
Statement tryBlock,
|
||||
List<Catch>? catchBlocks,
|
||||
List<InternalCatch>? catchBlocks,
|
||||
Statement? finallyBlock,
|
||||
) {
|
||||
return new TryStatement(tryBlock, catchBlocks ?? <Catch>[], finallyBlock)
|
||||
return new TryStatement(tryBlock, catchBlocks ?? [], finallyBlock)
|
||||
..fileOffset = fileOffset;
|
||||
}
|
||||
|
||||
|
||||
@@ -13521,46 +13521,50 @@ class InferenceVisitorImpl extends InferenceVisitorBase
|
||||
return new ExpressionInferenceResult(const NeverType.nonNullable(), node);
|
||||
}
|
||||
|
||||
void visitCatch(Catch node) {
|
||||
Catch visitCatch(InternalCatch node) {
|
||||
ScopeProviderInfo? scopeProviderInfo;
|
||||
Variable? exception = node.exception?.astVariable;
|
||||
Variable? stackTrace = node.stackTrace?.astVariable;
|
||||
if (isClosureContextLoweringEnabled) {
|
||||
scopeProviderInfo = _contextAllocationStrategy.enterScopeProvider(
|
||||
scopeProviderInfoKind: ScopeProviderInfoKind.Catch,
|
||||
);
|
||||
if (node.exception case CatchVariable exceptionCatchVariable?) {
|
||||
if (exception != null) {
|
||||
// TODO(62401): Remove the casts when the flow analysis uses
|
||||
// [InternalExpressionVariable]s.
|
||||
exceptionCatchVariable =
|
||||
(exceptionCatchVariable as InternalVariable).astVariable
|
||||
as CatchVariable;
|
||||
_contextAllocationStrategy.handleDeclarationOfVariable(
|
||||
exceptionCatchVariable,
|
||||
captureKind: _captureKindForVariable(exceptionCatchVariable),
|
||||
exception,
|
||||
captureKind: _captureKindForVariable(exception),
|
||||
);
|
||||
node.exception = exceptionCatchVariable;
|
||||
}
|
||||
if (node.stackTrace case CatchVariable stackTraceCatchVariable?) {
|
||||
if (stackTrace != null) {
|
||||
// TODO(62401): Remove the casts when the flow analysis uses
|
||||
// [InternalExpressionVariable]s.
|
||||
stackTraceCatchVariable =
|
||||
(stackTraceCatchVariable as InternalVariable).astVariable
|
||||
as CatchVariable;
|
||||
_contextAllocationStrategy.handleDeclarationOfVariable(
|
||||
stackTraceCatchVariable,
|
||||
captureKind: _captureKindForVariable(stackTraceCatchVariable),
|
||||
stackTrace,
|
||||
captureKind: _captureKindForVariable(stackTrace),
|
||||
);
|
||||
node.stackTrace = stackTraceCatchVariable;
|
||||
}
|
||||
}
|
||||
StatementInferenceResult bodyResult = inferStatement(node.body);
|
||||
if (bodyResult.hasChanged) {
|
||||
// Coverage-ignore-block(suite): Not run.
|
||||
node.body = bodyResult.statement..parent = node;
|
||||
}
|
||||
Statement body = bodyResult.hasChanged
|
||||
?
|
||||
// Coverage-ignore(suite): Not run.
|
||||
bodyResult.statement
|
||||
: node.body;
|
||||
Scope? scope;
|
||||
if (scopeProviderInfo != null) {
|
||||
_contextAllocationStrategy.exitScopeProvider(scopeProviderInfo);
|
||||
node.scope = scopeProviderInfo.scope;
|
||||
scope = scopeProviderInfo.scope;
|
||||
}
|
||||
return extern.createCatch(
|
||||
guard: node.guard,
|
||||
exception: exception,
|
||||
stackTrace: stackTrace,
|
||||
body: body,
|
||||
scope: scope,
|
||||
fileOffset: node.fileOffset,
|
||||
);
|
||||
}
|
||||
|
||||
StatementInferenceResult visitTryStatement(TryStatement node) {
|
||||
@@ -13576,16 +13580,18 @@ class InferenceVisitorImpl extends InferenceVisitorBase
|
||||
|
||||
StatementInferenceResult tryBlockResult = inferStatement(node.tryBlock);
|
||||
|
||||
List<Catch>? catchBlocks;
|
||||
if (node.catchBlocks.isNotEmpty) {
|
||||
catchBlocks = [];
|
||||
flowAnalysis.tryCatchStatement_bodyEnd(tryBodyWithAssignedInfo);
|
||||
for (Catch catchBlock in node.catchBlocks) {
|
||||
for (InternalCatch catchBlock in node.catchBlocks) {
|
||||
// TODO(62401): Remove the casts when the flow analysis uses
|
||||
// [InternalExpressionVariable]s.
|
||||
flowAnalysis.tryCatchStatement_catchBegin(
|
||||
(catchBlock.exception as InternalVariable?)?.astVariable,
|
||||
(catchBlock.stackTrace as InternalVariable?)?.astVariable,
|
||||
catchBlock.exception?.astVariable,
|
||||
catchBlock.stackTrace?.astVariable,
|
||||
);
|
||||
visitCatch(catchBlock);
|
||||
catchBlocks.add(visitCatch(catchBlock));
|
||||
flowAnalysis.tryCatchStatement_catchEnd();
|
||||
}
|
||||
flowAnalysis.tryCatchStatement_end();
|
||||
@@ -13605,9 +13611,8 @@ class InferenceVisitorImpl extends InferenceVisitorBase
|
||||
Statement result = tryBlockResult.hasChanged
|
||||
? tryBlockResult.statement
|
||||
: node.tryBlock;
|
||||
if (node.catchBlocks.isNotEmpty) {
|
||||
result = new TryCatch(result, node.catchBlocks)
|
||||
..fileOffset = node.fileOffset;
|
||||
if (catchBlocks != null) {
|
||||
result = new TryCatch(result, catchBlocks)..fileOffset = node.fileOffset;
|
||||
}
|
||||
if (node.finallyBlock != null) {
|
||||
result = new TryFinally(
|
||||
|
||||
@@ -248,20 +248,27 @@ void _testTryStatement() {
|
||||
Block emptyBlock2 = new Block([]);
|
||||
Block returnBlock1 = new Block([new ReturnStatement()]);
|
||||
Block returnBlock2 = new Block([new ReturnStatement()]);
|
||||
Catch emptyCatchBlock = new Catch(new Variable('e'), new Block([]));
|
||||
Catch emptyCatchBlockOnVoid = new Catch(
|
||||
new Variable('e'),
|
||||
new Block([]),
|
||||
guard: const VoidType(),
|
||||
InternalCatch emptyCatchBlock = new InternalCatch(
|
||||
exception: new VariableDeclarationImpl('e', fileOffset: TreeNode.noOffset),
|
||||
body: new Block([]),
|
||||
fileOffset: TreeNode.noOffset,
|
||||
);
|
||||
Catch returnCatchBlock = new Catch(
|
||||
new Variable('e'),
|
||||
new Block([new ReturnStatement()]),
|
||||
);
|
||||
Catch returnCatchBlockOnVoid = new Catch(
|
||||
new Variable('e'),
|
||||
new Block([new ReturnStatement()]),
|
||||
InternalCatch emptyCatchBlockOnVoid = new InternalCatch(
|
||||
exception: new VariableDeclarationImpl('e', fileOffset: TreeNode.noOffset),
|
||||
body: new Block([]),
|
||||
guard: const VoidType(),
|
||||
fileOffset: TreeNode.noOffset,
|
||||
);
|
||||
InternalCatch returnCatchBlock = new InternalCatch(
|
||||
exception: new VariableDeclarationImpl('e', fileOffset: TreeNode.noOffset),
|
||||
body: new Block([new ReturnStatement()]),
|
||||
fileOffset: TreeNode.noOffset,
|
||||
);
|
||||
InternalCatch returnCatchBlockOnVoid = new InternalCatch(
|
||||
exception: new VariableDeclarationImpl('e', fileOffset: TreeNode.noOffset),
|
||||
body: new Block([new ReturnStatement()]),
|
||||
guard: const VoidType(),
|
||||
fileOffset: TreeNode.noOffset,
|
||||
);
|
||||
|
||||
testStatement(new TryStatement(emptyBlock1, [], emptyBlock2), '''
|
||||
|
||||
Reference in New Issue
Block a user