blob: c525fd011178846773465adfe50750a6bbc3adfa [file]
// 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.
/// Helper library for creating external AST nodes during inference.
import 'package:kernel/ast.dart';
import 'package:kernel/core_types.dart';
import 'package:kernel/names.dart';
import '../source/check_helper.dart';
import 'internal_ast.dart';
/// Returns a clone of [node].
///
/// This assumes that `isPureExpression(node)` is `true`.
Expression clonePureExpression(Expression node) {
if (node is ThisExpression) {
return createThisExpression(fileOffset: node.fileOffset);
} else if (node is VariableGet) {
assert(
node.variable.isFinal && !node.variable.isLate,
"Trying to clone VariableGet of non-final variable"
" ${node.variable}.",
);
return createVariableGet(
node.variable,
promotedType: node.promotedType,
fileOffset: node.fileOffset,
);
}
// Coverage-ignore-block(suite): Not run.
throw new UnsupportedError("Clone not supported for ${node.runtimeType}.");
}
/// Returns a block like this:
///
/// {
/// statement;
/// body;
/// }
///
/// If [body] is a [Block], it's returned with [statement] prepended to it.
Block combineStatements(Statement statement, Statement body) {
if (body is Block) {
if (statement is Block) {
body.statements.insertAll(0, statement.statements);
setParents(statement.statements, body);
} else {
body.statements.insert(0, statement);
statement.parent = body;
}
return body;
} else {
return createBlock(
[if (statement is Block) ...statement.statements else statement, body],
fileOffset: statement.fileOffset,
fileEndOffset: body.fileOffset,
);
}
}
/// Creates a logical and expression of [left] and [right].
LogicalExpression createAndExpression(
Expression left,
Expression right, {
required int fileOffset,
}) {
return new LogicalExpression(left, LogicalExpressionOperator.AND, right)
..fileOffset = fileOffset;
}
AndPattern createAndPattern({
required Pattern left,
required Pattern right,
required int fileOffset,
}) {
return new AndPattern(left, right)..fileOffset = fileOffset;
}
/// Creates an [Arguments] object for the [positional] and [named] arguments,
/// and [types] as the type arguments.
Arguments createArguments(
List<Expression> positional, {
List<DartType>? types,
List<NamedExpression>? named,
required int fileOffset,
}) {
return new Arguments(positional, types: types, named: named)
..fileOffset = fileOffset;
}
Arguments createArgumentsForwarded(
FunctionNode function, {
required int fileOffset,
}) {
return new Arguments.forwarded(function)..fileOffset = fileOffset;
}
/// Creates an as-cast on [operand] against [type].
AsExpression createAsExpression(
Expression operand,
DartType type, {
bool isUnchecked = false,
bool isCovarianceCheck = false,
bool isTypeError = false,
bool isForDynamic = false,
required int fileOffset,
}) {
return new AsExpression(operand, type)
..fileOffset = fileOffset
..isUnchecked = isUnchecked
..isCovarianceCheck = isCovarianceCheck
..isTypeError = isTypeError
..isForDynamic = isForDynamic;
}
AssertInitializer createAssertInitializer(
AssertStatement statement, {
required int fileOffset,
}) {
return new AssertInitializer(statement)..fileOffset = fileOffset;
}
AssertStatement createAssertStatement(
Expression condition, {
Expression? message,
required int conditionStartOffset,
required int conditionEndOffset,
required int fileOffset,
}) {
return new AssertStatement(
condition,
message: message,
conditionStartOffset: conditionStartOffset,
conditionEndOffset: conditionEndOffset,
)..fileOffset = fileOffset;
}
AssignedVariablePattern createAssignedVariablePattern({
required Variable variable,
required Variable? setter,
required DartType matchedValueType,
required bool needsCast,
required bool hasObservableEffect,
required int fileOffset,
}) {
return new AssignedVariablePattern(variable)
..setter = setter
..matchedValueType = matchedValueType
..needsCast = needsCast
..hasObservableEffect = hasObservableEffect
..fileOffset = fileOffset;
}
Expression createAwaitExpression(
Expression operand, {
required DartType? runtimeCheckType,
required int fileOffset,
}) {
return new AwaitExpression(operand)
..runtimeCheckType = runtimeCheckType
..fileOffset = fileOffset;
}
/// Creates a block containing the [statements].
Block createBlock(
List<Statement> statements, {
required int fileOffset,
int? fileEndOffset,
}) {
return new Block(statements)
..fileOffset = fileOffset
..fileEndOffset = fileEndOffset ?? fileOffset;
}
/// Creates a block expression using [body] as the body and [value] as the
/// resulting value.
BlockExpression createBlockExpression(
Block body,
Expression value, {
// TODO(johnniwinther,cstefantsova): This should be required.
Scope? scope,
required int fileOffset,
}) {
return new BlockExpression(body, value)
..scope = scope
..fileOffset = fileOffset;
}
/// Creates a boolean literal of [value].
BoolLiteral createBoolLiteral(bool value, {required int fileOffset}) {
return new BoolLiteral(value)..fileOffset = fileOffset;
}
/// Creates a break statement with the given [target].
BreakStatement createBreakStatement(
LabeledStatement target, {
required int fileOffset,
}) {
return new BreakStatement(target)..fileOffset = fileOffset;
}
CastPattern createCastPattern({
required Pattern pattern,
required DartType type,
required int fileOffset,
}) {
return new CastPattern(pattern, type)..fileOffset = fileOffset;
}
Catch createCatch({
required DartType guard,
required CatchVariable? exception,
required CatchVariable? stackTrace,
required Statement body,
required Scope? scope,
required int fileOffset,
}) {
return new Catch(exception, body, guard: guard, stackTrace: stackTrace)
..scope = scope
..fileOffset = fileOffset;
}
CatchVariable createCatchVariable({
required String name,
required DartType? type,
required bool isFinal,
required bool isWildcard,
required int fileOffset,
}) {
return new CatchVariable(
name: name,
type: type,
isWildcard: isWildcard,
isFinal: isFinal,
)..fileOffset = fileOffset;
}
Expression createCheckLibraryIsLoaded({
required LibraryDependency dependency,
required int fileOffset,
}) {
return new CheckLibraryIsLoaded(dependency)..fileOffset = fileOffset;
}
/// Creates a conditional expression of the [condition] and the [then] and
/// [otherwise] branches with the given [staticType] of the resulting
/// expression.
ConditionalExpression createConditionalExpression(
Expression condition,
Expression then,
Expression otherwise, {
required DartType staticType,
required int fileOffset,
}) {
return new ConditionalExpression(condition, then, otherwise, staticType)
..fileOffset = fileOffset;
}
ConstantExpression createConstantExpression(
Constant constant,
DartType type, {
required int fileOffset,
}) {
return new ConstantExpression(constant, type)..fileOffset = fileOffset;
}
ConstantPattern createConstantPattern({
required Expression expression,
required DartType expressionType,
required Procedure equalsTarget,
required FunctionType equalsType,
required int fileOffset,
}) {
return new ConstantPattern(expression)
..expressionType = expressionType
..equalsTarget = equalsTarget
..equalsType = equalsType
..fileOffset = fileOffset;
}
Constructor createConstructor(
FunctionNode function, {
required Name name,
Reference? reference,
bool isSynthetic = false,
required Uri fileUri,
required int fileOffset,
required int fileStartOffset,
required int fileEndOffset,
}) {
return new Constructor(
function,
name: name,
reference: reference,
fileUri: fileUri,
isSynthetic: isSynthetic,
)
..fileOffset = fileOffset
..startFileOffset = fileStartOffset
..fileEndOffset = fileEndOffset;
}
/// Creates an invocation of the [target] constructor with the given
/// [arguments].
ConstructorInvocation createConstructorInvocation(
Constructor target,
Arguments arguments, {
required int fileOffset,
bool isConst = false,
}) {
return new ConstructorInvocation(target, arguments, isConst: isConst)
..fileOffset = fileOffset;
}
ConstructorTearOff createConstructorTearOff(
Member target, {
required int fileOffset,
}) {
return new ConstructorTearOff(target)..fileOffset = fileOffset;
}
ConstVariable createConstVariable({
required String name,
required DartType? type,
bool isFinal = false,
bool isWildcard = false,
required int fileOffset,
bool hasDeclaredInitializer = false,
int fileEqualsOffset = TreeNode.noOffset,
}) {
return new ConstVariable(
name: name,
type: type,
isFinal: isFinal,
isWildcard: isWildcard,
hasDeclaredInitializer: hasDeclaredInitializer,
)
..fileOffset = fileOffset
..fileEqualsOffset = fileEqualsOffset;
}
ContinueSwitchStatement createContinueSwitchStatement({
required int fileOffset,
}) {
return new ContinueSwitchStatement(dummySwitchCase)..fileOffset = fileOffset;
}
AsExpression createCovarianceCheckedInstanceGet(
InstanceAccessKind kind,
Expression receiver,
Name name, {
required Member interfaceTarget,
required DartType checkedType,
required DartType operandStaticType,
required int fileOffset,
}) {
return new AsExpression(
new InstanceGet(
kind,
receiver,
name,
interfaceTarget: interfaceTarget,
resultType: operandStaticType,
)..fileOffset = fileOffset,
checkedType,
)
..isTypeError = true
..isCovarianceCheck = true
..fileOffset = fileOffset;
}
AsExpression createCovarianceCheckedInstanceInvocation(
InstanceAccessKind kind,
Expression receiver,
Name name,
Arguments arguments, {
required Procedure interfaceTarget,
required FunctionType functionType,
required DartType checkedType,
required DartType operandStaticType,
required int fileOffset,
}) {
return new AsExpression(
new InstanceInvocation(
kind,
receiver,
name,
arguments,
interfaceTarget: interfaceTarget,
functionType: functionType,
resultType: operandStaticType,
)..fileOffset = fileOffset,
checkedType,
)
..isTypeError = true
..isCovarianceCheck = true
..fileOffset = fileOffset;
}
AsExpression createCovarianceCheckedInstanceTearOff(
InstanceAccessKind kind,
Expression receiver,
Name name, {
required Procedure interfaceTarget,
required DartType checkedType,
required DartType operandStaticType,
required int fileOffset,
}) {
return new AsExpression(
new InstanceTearOff(
kind,
receiver,
name,
interfaceTarget: interfaceTarget,
resultType: operandStaticType,
)..fileOffset = fileOffset,
checkedType,
)
..isTypeError = true
..isCovarianceCheck = true
..fileOffset = fileOffset;
}
AsExpression createCovarianceCheckedVariableGet(
Variable variable, {
required DartType operandStaticType,
required DartType checkedType,
required int fileOffset,
}) {
return new AsExpression(
new VariableGet(variable)
..fileOffset = fileOffset
..promotedType = operandStaticType,
checkedType,
)
..isTypeError = true
..isCovarianceCheck = true
..fileOffset = fileOffset;
}
Statement createDoStatement(
Statement body,
Expression condition, {
required int fileOffset,
}) {
return new DoStatement(body, condition)..fileOffset = fileOffset;
}
DoubleLiteral createDoubleLiteral(double value, {required int fileOffset}) {
return new DoubleLiteral(value)..fileOffset = fileOffset;
}
// Coverage-ignore(suite): Not run.
DynamicInvocation createDynamicInvocation(
DynamicAccessKind kind,
Expression receiver,
Name name,
Arguments arguments, {
int flags = 0,
required int fileOffset,
}) {
return new DynamicInvocation(kind, receiver, name, arguments)
..flags = flags
..fileOffset = fileOffset;
}
// TODO(johnniwinther): Should [fileOffset] be required?
Statement createEmptyStatement({int fileOffset = TreeNode.noOffset}) {
return new EmptyStatement()..fileOffset = fileOffset;
}
// Coverage-ignore(suite): Not run.
EqualsCall createEqualsCall(
Expression left,
Expression right, {
required FunctionType functionType,
required Procedure interfaceTarget,
required int fileOffset,
}) {
return new EqualsCall(
left,
right,
functionType: functionType,
interfaceTarget: interfaceTarget,
)..fileOffset = fileOffset;
}
/// Creates a `== null` test on [expression].
EqualsNull createEqualsNull(Expression expression, {required int fileOffset}) {
return new EqualsNull(expression)..fileOffset = fileOffset;
}
/// Creates an [ExpressionStatement] of [expression] using the file offset of
/// [expression] for the file offset of the statement, unless provided directly
/// through [fileOffset].
ExpressionStatement createExpressionStatement(
Expression expression, {
int? fileOffset,
}) {
return new ExpressionStatement(expression)
..fileOffset = fileOffset ?? expression.fileOffset;
}
FieldInitializer createFieldInitializer(
Field field,
Expression value, {
required int fileOffset,
required bool isSynthetic,
}) {
return new FieldInitializer(field, value)
..fileOffset = fileOffset
..isSynthetic = isSynthetic;
}
FileUriConstantExpression createFileUriConstantExpression(
Constant constant, {
DartType type = const DynamicType(),
required Uri fileUri,
required int fileOffset,
}) {
return new FileUriConstantExpression(constant, type: type, fileUri: fileUri)
..fileOffset = fileOffset;
}
FileUriExpression createFileUriExpression({
required Expression expression,
required Uri fileUri,
required int fileOffset,
}) {
return new FileUriExpression(expression, fileUri)..fileOffset = fileOffset;
}
ForStatement createForStatement({
required List<VariableDeclaration> variables,
required Expression? condition,
required List<Expression> updates,
required Statement body,
required Scope? scope,
required int fileOffset,
}) {
return new ForStatement(variables, condition, updates, body)
..scope = scope
..fileOffset = fileOffset;
}
FunctionDeclaration createFunctionDeclaration({
required LocalFunctionVariable variable,
required FunctionNode function,
required int fileOffset,
}) {
return new FunctionDeclaration(variable, function)..fileOffset = fileOffset;
}
FunctionExpression createFunctionExpression(
FunctionNode function, {
required int fileOffset,
}) {
return new FunctionExpression(function)..fileOffset = fileOffset;
}
FunctionNode createFunctionNode(
Statement? body, {
List<TypeParameter>? typeParameters,
List<PositionalParameter>? positionalParameters,
List<NamedParameter>? namedParameters,
int? requiredParameterCount,
DartType returnType = const DynamicType(),
required int fileOffset,
int? fileEndOffset,
AsyncMarker asyncMarker = AsyncMarker.Sync,
AsyncMarker? dartAsyncMarker,
DartType? emittedValueType,
Scope? scope,
List<VariableContext>? capturedContexts,
}) {
return new FunctionNode(
body,
typeParameters: typeParameters,
positionalParameters: positionalParameters,
namedParameters: namedParameters,
returnType: returnType,
requiredParameterCount: requiredParameterCount,
asyncMarker: asyncMarker,
dartAsyncMarker: dartAsyncMarker,
)
..emittedValueType = emittedValueType
..scope = scope
..capturedContexts = capturedContexts
..fileOffset = fileOffset
..fileEndOffset = fileEndOffset ?? fileOffset;
}
IfCaseStatement createIfCaseStatement({
required Expression expression,
required PatternGuard patternGuard,
required Statement then,
required Statement? otherwise,
required DartType matchedValueType,
required int fileOffset,
}) {
return new IfCaseStatement(expression, patternGuard, then, otherwise)
..matchedValueType = matchedValueType
..fileOffset = fileOffset;
}
/// Creates an if statement with the [condition], [then] branch and [otherwise]
/// as the optional else branch.
IfStatement createIfStatement(
Expression condition,
Statement then, {
Statement? otherwise,
required int fileOffset,
}) {
return new IfStatement(condition, then, otherwise)..fileOffset = fileOffset;
}
Field createImmutableField(
Name name, {
required DartType type,
bool isLate = false,
bool isFinal = false,
bool isConst = false,
bool isStatic = false,
required Uri fileUri,
Reference? fieldReference,
Reference? getterReference,
bool isEnumElement = false,
required int fileOffset,
required int fileEndOffset,
}) {
return new Field.immutable(
name,
type: type,
isLate: isLate,
isFinal: isFinal,
isConst: isConst,
isStatic: isStatic,
fileUri: fileUri,
fieldReference: fieldReference,
getterReference: getterReference,
isEnumElement: isEnumElement,
)
..fileOffset = fileOffset
..fileEndOffset = fileEndOffset;
}
/// Creates an initialized (but mutable) [Variable] of the static
/// [type].
VariableDeclaration createInitializedVariableDeclaration({
required Expression expression,
required DartType type,
required int fileOffset,
String? name,
}) {
return createVariableDeclaration(
new SyntheticVariable(
cosmeticName: name,
initializer: expression,
type: type,
hasDeclaredInitializer: true,
)..fileOffset = fileOffset,
);
}
InstanceGet createInstanceGet(
InstanceAccessKind kind,
Expression receiver,
Name name, {
required Member interfaceTarget,
required DartType resultType,
required int fileOffset,
}) {
return new InstanceGet(
kind,
receiver,
name,
interfaceTarget: interfaceTarget,
resultType: resultType,
)..fileOffset = fileOffset;
}
InstanceInvocation createInstanceInvocation(
InstanceAccessKind kind,
Expression receiver,
Name name,
Arguments arguments, {
required Procedure interfaceTarget,
required FunctionType functionType,
required int fileOffset,
}) {
return new InstanceInvocation(
kind,
receiver,
name,
arguments,
interfaceTarget: interfaceTarget,
functionType: functionType,
)..fileOffset = fileOffset;
}
InstanceSet createInstanceSet(
InstanceAccessKind kind,
Expression receiver,
Name name,
Expression value, {
required Member interfaceTarget,
required int fileOffset,
}) {
return new InstanceSet(
kind,
receiver,
name,
value,
interfaceTarget: interfaceTarget,
)..fileOffset = fileOffset;
}
InstanceTearOff createInstanceTearOff(
InstanceAccessKind kind,
Expression receiver,
Name name, {
required Procedure interfaceTarget,
required DartType resultType,
required int fileOffset,
}) {
return new InstanceTearOff(
kind,
receiver,
name,
interfaceTarget: interfaceTarget,
resultType: resultType,
)..fileOffset = fileOffset;
}
Instantiation createInstantiation(
Expression expression,
List<DartType> typeArguments, {
required int fileOffset,
}) {
return new Instantiation(expression, typeArguments)..fileOffset = fileOffset;
}
/// Creates an integer literal of [value].
///
/// If [encodeForWeb] is `true`, negative values are encoded using unary-. This
/// should be done if the [value] isn't known to be a valid negative number in
/// the web encoding.
Expression createIntLiteral(
CoreTypes coreTypes,
int value, {
required int fileOffset,
bool encodeForWeb = true,
}) {
if (encodeForWeb && value < 0) {
/// The web backends need this to be encoded as a unary minus on the
/// positive value.
return new InstanceInvocation(
InstanceAccessKind.Instance,
new IntLiteral(-value)..fileOffset = fileOffset,
unaryMinusName,
new Arguments([])..fileOffset = fileOffset,
interfaceTarget: coreTypes.intUnaryMinus,
functionType: coreTypes.intUnaryMinus.getterType as FunctionType,
)..fileOffset = fileOffset;
} else {
return new IntLiteral(value)..fileOffset = fileOffset;
}
}
InvalidExpression createInvalidExpression(
String message, {
Expression? expression,
required int fileOffset,
}) {
return new InvalidExpression(message, expression)..fileOffset = fileOffset;
}
InvalidExpression createInvalidExpressionFromErrorText(
ErrorText errorText, {
Expression? expression,
}) {
return new InvalidExpression(errorText.message, expression)
..fileOffset = errorText.fileOffset;
}
InvalidInitializer createInvalidInitializer(
InvalidExpression expression, {
bool isSuperInitializer = false,
bool isRedirectingInitializer = false,
}) {
return new InvalidInitializer(expression.message)
..fileOffset = expression.fileOffset
..isSuperInitializer = isSuperInitializer
..isRedirectingInitializer = isRedirectingInitializer;
}
InvalidInitializer createInvalidInitializer2(
ErrorText errorText, {
bool isSuperInitializer = false,
bool isRedirectingInitializer = false,
}) {
return new InvalidInitializer(errorText.message)
..fileOffset = errorText.fileOffset
..isSuperInitializer = isSuperInitializer
..isRedirectingInitializer = isRedirectingInitializer;
}
InvalidInitializer createInvalidInitializerFromMessage(
String message, {
required int fileOffset,
required bool isSuperInitializer,
required bool isRedirectingInitializer,
}) {
return new InvalidInitializer(message)
..fileOffset = fileOffset
..isSuperInitializer = isSuperInitializer
..isRedirectingInitializer = isRedirectingInitializer;
}
InvalidPattern createInvalidPattern({
required Expression error,
required List<InternalDeclaredVariable> declaredVariables,
int? fileOffset,
}) {
return new InvalidPattern(
error,
declaredVariables: declaredVariables
.map((InternalDeclaredVariable variable) => variable.astVariable)
.toList(),
)..fileOffset = fileOffset ?? error.fileOffset;
}
/// Creates an is-test on [operand] against [type].
IsExpression createIsExpression(
Expression operand,
DartType type, {
required int fileOffset,
}) {
return new IsExpression(operand, type)..fileOffset = fileOffset;
}
/// Creates a labeled statement that serves as a label for [statement].
LabeledStatement createLabeledStatement(
Statement statement, {
required int fileOffset,
}) {
return new LabeledStatement(statement)..fileOffset = fileOffset;
}
LateVariable createLateVariable({
required String name,
required DartType? type,
bool isFinal = false,
bool isWildcard = false,
required int fileOffset,
bool hasDeclaredInitializer = false,
int fileEqualsOffset = TreeNode.noOffset,
}) {
return new LateVariable(
name: name,
type: type,
isFinal: isFinal,
isWildcard: isWildcard,
hasDeclaredInitializer: hasDeclaredInitializer,
)
..fileOffset = fileOffset
..fileEqualsOffset = fileEqualsOffset;
}
/// Creates a [Let] of [variable] with the given [body] using
/// `variable.fileOffset` as the file offset for the let.
Let createLet({
required SyntheticVariable variable,
Expression? value,
required Expression body,
int? fileOffset,
}) {
if (value != null) {
variable.initializer = value..parent = variable;
}
return new Let(variable, body)
..fileOffset = fileOffset ?? variable.fileOffset;
}
/// Creates a [Let] with the [effect] as the variable initializer and the
/// [result] as the body of the [Let] expression and using
/// `effect.fileOffset` as the file offset for the let.
Let createLetEffect({required Expression effect, required Expression result}) {
return new Let(createVariableCache(effect, const DynamicType()), result)
..fileOffset = effect.fileOffset;
}
ListPattern createListPattern({
required DartType? typeArgument,
required List<Pattern> patterns,
required DartType requiredType,
required DartType matchedValueType,
required bool needsCheck,
required DartType lookupType,
required bool hasRestPattern,
required Member lengthTarget,
required DartType lengthType,
required Procedure lengthCheckTarget,
required FunctionType lengthCheckType,
required Procedure sublistTarget,
required FunctionType sublistType,
required Procedure minusTarget,
required FunctionType minusType,
required Procedure indexGetTarget,
required FunctionType indexGetType,
required int fileOffset,
}) {
return new ListPattern(typeArgument, patterns)
..requiredType = requiredType
..matchedValueType = matchedValueType
..needsCheck = needsCheck
..lookupType = lookupType
..hasRestPattern = hasRestPattern
..lengthTarget = lengthTarget
..lengthType = lengthType
..lengthCheckTarget = lengthCheckTarget
..lengthCheckType = lengthCheckType
..sublistTarget = sublistTarget
..sublistType = sublistType
..minusTarget = minusTarget
..minusType = minusType
..indexGetTarget = indexGetTarget
..indexGetType = indexGetType
..fileOffset = fileOffset;
}
LoadLibrary createLoadLibrary(
LibraryDependency dependency, {
required int fileOffset,
}) {
return new LoadLibrary(dependency)..fileOffset = fileOffset;
}
/// Creates an invocation of the local function [variable] with the provided
/// [arguments].
LocalFunctionInvocation createLocalFunctionInvocation(
LocalFunctionVariable variable, {
Arguments? arguments,
required int fileOffset,
}) {
return new LocalFunctionInvocation(
variable,
arguments ?? // Coverage-ignore(suite): Not run.
createArguments([], fileOffset: fileOffset)
..fileOffset = fileOffset,
functionType: variable.type as FunctionType,
)..fileOffset = fileOffset;
}
LocalFunctionVariable createLocalFunctionVariable({
required String name,
required DartType? type,
bool isWildcard = false,
required int fileOffset,
required bool isLowered,
int fileEqualsOffset = TreeNode.noOffset,
}) {
return new LocalFunctionVariable(
name: name,
type: type,
isWildcard: isWildcard,
isLowered: isLowered,
)
..fileOffset = fileOffset
..fileEqualsOffset = fileEqualsOffset;
}
LocalVariable createLocalVariable({
required String name,
required DartType? type,
bool isFinal = false,
bool isWildcard = false,
required int fileOffset,
bool hasDeclaredInitializer = false,
int fileEqualsOffset = TreeNode.noOffset,
}) {
return new LocalVariable(
name: name,
type: type,
isFinal: isFinal,
isWildcard: isWildcard,
hasDeclaredInitializer: hasDeclaredInitializer,
)
..fileOffset = fileOffset
..fileEqualsOffset = fileEqualsOffset;
}
Expression createLogicalExpression({
required Expression left,
required LogicalExpressionOperator operator,
required Expression right,
required int fileOffset,
}) {
return new LogicalExpression(left, operator, right)..fileOffset = fileOffset;
}
MapLiteralEntry createMapLiteralEntry(
Expression key,
Expression value, {
required int fileOffset,
}) {
return new MapLiteralEntry(key, value)..fileOffset = fileOffset;
}
MapPattern createMapPattern({
required DartType? keyType,
required DartType? valueType,
required List<MapPatternEntry> entries,
required DartType requiredType,
required DartType matchedValueType,
required bool needsCheck,
required DartType lookupType,
required Procedure containsKeyTarget,
required FunctionType containsKeyType,
required Procedure indexGetTarget,
required FunctionType indexGetType,
required int fileOffset,
}) {
return new MapPattern(keyType, valueType, entries)
..requiredType = requiredType
..matchedValueType = matchedValueType
..needsCheck = needsCheck
..lookupType = lookupType
..containsKeyTarget = containsKeyTarget
..containsKeyType = containsKeyType
..indexGetTarget = indexGetTarget
..indexGetType = indexGetType
..fileOffset = fileOffset;
}
MapPatternEntry createMapPatternEntry({
required Expression key,
required DartType keyType,
required Pattern value,
required int fileOffset,
}) {
return new MapPatternEntry(key, value)
..keyType = keyType
..fileOffset = fileOffset;
}
MapPatternRestEntry createMapPatternRestEntry({required int fileOffset}) {
return new MapPatternRestEntry()..fileOffset = fileOffset;
}
Field createMutableField(
Name name, {
DartType type = const DynamicType(),
bool isLate = false,
bool isFinal = false,
bool isStatic = false,
required Uri fileUri,
Reference? fieldReference,
Reference? getterReference,
Reference? setterReference,
required int fileOffset,
required int fileEndOffset,
bool isInternalImplementation = false,
}) {
return new Field.mutable(
name,
type: type,
isLate: isLate,
isFinal: isFinal,
isStatic: isStatic,
fileUri: fileUri,
fieldReference: fieldReference,
getterReference: getterReference,
setterReference: setterReference,
)
..fileOffset = fileOffset
..fileEndOffset = fileEndOffset
..isInternalImplementation = isInternalImplementation;
}
NamedExpression createNamedExpression(
String name,
Expression expression, {
int? fileOffset,
}) {
return new NamedExpression(name, expression)
..fileOffset = fileOffset ?? expression.fileOffset;
}
NamedParameter createNamedParameter({
required String parameterName,
required DartType type,
Expression? defaultValue,
bool isCovariantByDeclaration = false,
bool isCovariantByClass = false,
bool isRequired = false,
bool isInitializingFormal = false,
bool isSuperInitializingFormal = false,
bool isFinal = false,
bool hasDeclaredDefaultValue = false,
bool isLowered = false,
bool isSynthesized = false,
bool isWildcard = false,
bool isRenamedPrivateNamedParameter = false,
required int fileOffset,
}) {
return new NamedParameter(
parameterName: parameterName,
type: type,
defaultValue: defaultValue,
isCovariantByDeclaration: isCovariantByDeclaration,
isCovariantByClass: isCovariantByClass,
isRequired: isRequired,
isInitializingFormal: isInitializingFormal,
isSuperInitializingFormal: isSuperInitializingFormal,
isFinal: isFinal,
hasDeclaredDefaultValue: hasDeclaredDefaultValue,
isLowered: isLowered,
isSynthesized: isSynthesized,
isWildcard: isWildcard,
isRenamedPrivateNamedParameter: isRenamedPrivateNamedParameter,
)..fileOffset = fileOffset;
}
NamedPattern createNamedPattern({
required String name,
Name? fieldName,
required Pattern pattern,
required int fileOffset,
}) {
NamedPattern result = new NamedPattern(name, pattern)
..fileOffset = fileOffset;
if (fieldName != null) {
result.fieldName = fieldName;
}
return result;
}
/// Creates a [Not] of [operand].
Not createNot(Expression operand, {int? fileOffset}) {
return new Not(operand)..fileOffset = fileOffset ?? operand.fileOffset;
}
NullAssertPattern createNullAssertPattern({
required Pattern pattern,
required int fileOffset,
}) {
return new NullAssertPattern(pattern)..fileOffset = fileOffset;
}
/// Creates a [NullCheck] of [expression].
NullCheck createNullCheck(Expression expression, {required int fileOffset}) {
return new NullCheck(expression)..fileOffset = fileOffset;
}
NullCheckPattern createNullCheckPattern({
required Pattern pattern,
required int fileOffset,
}) {
return new NullCheckPattern(pattern)..fileOffset = fileOffset;
}
/// Creates a null literal.
NullLiteral createNullLiteral({required int fileOffset}) {
return new NullLiteral()..fileOffset = fileOffset;
}
ObjectPattern createObjectPattern({
required DartType requiredType,
required List<NamedPattern> fields,
required DartType matchedValueType,
required bool needsCheck,
required DartType lookupType,
required int fileOffset,
}) {
return new ObjectPattern(requiredType, fields)
..matchedValueType = matchedValueType
..needsCheck = needsCheck
..lookupType = lookupType
..fileOffset = fileOffset;
}
/// Creates a logical or expression of [left] and [right].
LogicalExpression createOrExpression(
Expression left,
Expression right, {
required int fileOffset,
}) {
return new LogicalExpression(left, LogicalExpressionOperator.OR, right)
..fileOffset = fileOffset;
}
OrPattern createOrPattern({
required Pattern left,
required Pattern right,
required List<DeclaredVariable> orPatternJointVariables,
required int fileOffset,
}) {
return new OrPattern(
left,
right,
orPatternJointVariables: orPatternJointVariables,
)..fileOffset = fileOffset;
}
PatternAssignment createPatternAssignment({
required Pattern pattern,
required Expression expression,
required DartType matchedValueType,
required int fileOffset,
}) {
return new PatternAssignment(pattern, expression)
..matchedValueType = matchedValueType
..fileOffset = fileOffset;
}
PatternGuard createPatternGuard({
required Pattern pattern,
required Expression? guard,
required int fileOffset,
}) {
return new PatternGuard(pattern, guard)..fileOffset = fileOffset;
}
PatternSwitchCase createPatternSwitchCase({
required List<int> caseOffsets,
required List<PatternGuard> patternGuards,
required Statement body,
required bool isDefault,
required bool hasLabel,
required List<DeclaredVariable> jointVariables,
required List<int>? jointVariableFirstUseOffsets,
required int fileOffset,
}) {
return new PatternSwitchCase(
caseOffsets,
patternGuards,
body,
isDefault: isDefault,
hasLabel: hasLabel,
jointVariables: jointVariables,
jointVariableFirstUseOffsets: jointVariableFirstUseOffsets,
)..fileOffset = fileOffset;
}
PatternSwitchStatement createPatternSwitchStatement({
required Expression expression,
required List<PatternSwitchCase> cases,
required DartType expressionType,
required bool lastCaseTerminates,
required int fileOffset,
}) {
return new PatternSwitchStatement(expression, cases)
..expressionType = expressionType
..lastCaseTerminates = lastCaseTerminates
..fileOffset = fileOffset;
}
PatternVariableDeclaration createPatternVariableDeclaration({
required Pattern pattern,
required Expression initializer,
required bool isFinal,
required DartType matchedValueType,
required int fileOffset,
}) {
return new PatternVariableDeclaration(pattern, initializer, isFinal: isFinal)
..matchedValueType = matchedValueType
..fileOffset = fileOffset;
}
PositionalParameter createPositionalParameter({
String? cosmeticName,
required DartType type,
Expression? defaultValue,
bool isCovariantByDeclaration = false,
bool isCovariantByClass = false,
bool isRequired = false,
bool isInitializingFormal = false,
bool isSuperInitializingFormal = false,
bool isFinal = false,
bool hasDeclaredDefaultValue = false,
bool isLowered = false,
bool isSynthesized = false,
bool isWildcard = false,
required int fileOffset,
}) {
return new PositionalParameter(
cosmeticName: cosmeticName,
type: type,
defaultValue: defaultValue,
isCovariantByDeclaration: isCovariantByDeclaration,
isCovariantByClass: isCovariantByClass,
isRequired: isRequired,
isInitializingFormal: isInitializingFormal,
isSuperInitializingFormal: isSuperInitializingFormal,
isFinal: isFinal,
hasDeclaredDefaultValue: hasDeclaredDefaultValue,
isLowered: isLowered,
isSynthesized: isSynthesized,
isWildcard: isWildcard,
)..fileOffset = fileOffset;
}
Procedure createProcedure(
Name name,
ProcedureKind kind,
FunctionNode function, {
Reference? reference,
ProcedureStubKind stubKind = ProcedureStubKind.Regular,
Member? stubTarget,
required Uri fileUri,
required int fileOffset,
int fileStartOffset = TreeNode.noOffset,
required int fileEndOffset,
bool isAbstract = false,
bool isExternal = false,
bool isStatic = false,
bool isConst = false,
bool isExtensionMember = false,
bool isExtensionTypeMember = false,
bool isSynthetic = false,
}) {
return new Procedure(
name,
kind,
function,
stubKind: stubKind,
stubTarget: stubTarget,
fileUri: fileUri,
reference: reference,
isAbstract: isAbstract,
isExternal: isExternal,
isConst: isConst,
isStatic: isStatic,
isExtensionMember: isExtensionMember,
isExtensionTypeMember: isExtensionTypeMember,
isSynthetic: isSynthetic,
)
..fileStartOffset = fileStartOffset
..fileOffset = fileOffset
..fileEndOffset = fileEndOffset;
}
RecordPattern createRecordPattern({
required List<Pattern> patterns,
required RecordType requiredType,
required DartType matchedValueType,
required bool needsCheck,
required RecordType lookupType,
required int fileOffset,
}) {
return new RecordPattern(patterns)
..requiredType = requiredType
..matchedValueType = matchedValueType
..needsCheck = needsCheck
..lookupType = lookupType
..fileOffset = fileOffset;
}
RedirectingFactoryTearOff createRedirectingFactoryTearOff(
Procedure procedure, {
required int fileOffset,
}) {
assert(procedure.isRedirectingFactory);
return new RedirectingFactoryTearOff(procedure)..fileOffset = fileOffset;
}
RelationalPattern createRelationalPattern({
required RelationalPatternKind kind,
required Expression expression,
required DartType expressionType,
required DartType matchedValueType,
required RelationalAccessKind accessKind,
required Name? name,
required Procedure? target,
required List<DartType>? typeArguments,
required FunctionType? functionType,
required int fileOffset,
}) {
return new RelationalPattern(kind, expression)
..expressionType = expressionType
..matchedValueType = matchedValueType
..accessKind = accessKind
..name = name
..target = target
..typeArguments = typeArguments
..functionType = functionType
..fileOffset = fileOffset;
}
RestPattern createRestPattern({
required Pattern? subPattern,
required int fileOffset,
}) {
return new RestPattern(subPattern)..fileOffset;
}
Expression createRethrow({required int fileOffset}) {
return new Rethrow()..fileOffset = fileOffset;
}
ReturnStatement createReturnStatement(
Expression? expression, {
int? fileOffset,
}) {
return new ReturnStatement(expression)
..fileOffset = fileOffset ?? expression!.fileOffset;
}
StaticGet createStaticGet(Member member, {required int fileOffset}) {
return new StaticGet(member)..fileOffset = fileOffset;
}
/// Creates a static invocation of [target] with the given arguments.
StaticInvocation createStaticInvocation(
Procedure target,
Arguments arguments, {
required int fileOffset,
bool isConst = false,
}) {
return new StaticInvocation(target, arguments, isConst: isConst)
..fileOffset = fileOffset;
}
StaticSet createStaticSet(
Member member,
Expression value, {
required int fileOffset,
}) {
return new StaticSet(member, value)..fileOffset = fileOffset;
}
StaticTearOff createStaticTearOff(Procedure target, {required int fileOffset}) {
return new StaticTearOff(target)..fileOffset = fileOffset;
}
Expression createStringConcatenation(
List<Expression> expressions, {
required int fileOffset,
}) {
return new StringConcatenation(expressions)..fileOffset = fileOffset;
}
/// Creates a string literal of [value].
StringLiteral createStringLiteral(String value, {required int fileOffset}) {
return new StringLiteral(value)..fileOffset = fileOffset;
}
/// Creates a super method invocation of [target] with the given arguments.
SuperMethodInvocation createSuperMethodInvocation(
Expression receiver,
Name name,
Procedure target,
Arguments arguments, {
required int fileOffset,
}) {
return new SuperMethodInvocation(receiver, name, arguments, target)
..fileOffset = fileOffset;
}
SuperPropertyGet createSuperPropertyGet(
Expression receiver,
Name name,
Member target, {
required int fileOffset,
}) {
return new SuperPropertyGet(receiver, name, target)..fileOffset = fileOffset;
}
SuperPropertySet createSuperPropertySet(
Expression receiver,
Name name,
Member target,
Expression value, {
required int fileOffset,
}) {
return new SuperPropertySet(receiver, name, value, target)
..fileOffset = fileOffset;
}
/// Creates a switch case for the case [expressions] and their corresponding
/// file offsets in [expressionOffsets] with the given [body].
SwitchCase createSwitchCase({
required List<Expression> expressions,
required List<int> expressionOffsets,
required Statement body,
required bool isDefault,
required int fileOffset,
}) {
return new SwitchCase(
expressions,
expressionOffsets,
body,
isDefault: isDefault,
)..fileOffset = fileOffset;
}
SwitchExpression createSwitchExpression({
required Expression expression,
required List<SwitchExpressionCase> cases,
required DartType expressionType,
required DartType staticType,
required int fileOffset,
}) {
return new SwitchExpression(expression, cases)
..expressionType = expressionType
..staticType = staticType
..fileOffset = fileOffset;
}
SwitchExpressionCase createSwitchExpressionCase({
required PatternGuard patternGuard,
required Expression expression,
required int fileOffset,
}) {
return new SwitchExpressionCase(patternGuard, expression)
..fileOffset = fileOffset;
}
/// Create a switch statement on the [expression] with the given [cases]. If
/// the switch is known to be exhaustive and without a default case,
/// [isExplicitlyExhaustive] should be set to `true`.
///
/// The [expressionType] is the static type of the switch expression.
SwitchStatement createSwitchStatement({
required Expression expression,
required List<SwitchCase> cases,
required bool isExplicitlyExhaustive,
required DartType expressionType,
required int fileOffset,
}) {
return new SwitchStatement(
expression,
cases,
isExplicitlyExhaustive: isExplicitlyExhaustive,
)
..expressionType = expressionType
..fileOffset = fileOffset;
}
SymbolLiteral createSymbolLiteral({
required String value,
required int fileOffset,
}) {
return new SymbolLiteral(value)..fileOffset = fileOffset;
}
ThisExpression createThisExpression({required int fileOffset}) {
return new ThisExpression()..fileOffset = fileOffset;
}
/// Creates a throw of [expression] using the file offset of [expression] for
/// the throw expression.
Throw createThrow(
Expression expression, {
bool forErrorHandling = false,
int? fileOffset,
}) {
return new Throw(expression)
..fileOffset = fileOffset ?? expression.fileOffset
..forErrorHandling = forErrorHandling;
}
TypedefTearOff createTypedefTearOff({
required List<StructuralParameter> structuralParameters,
required Expression expression,
required List<DartType> typeArguments,
required int fileOffset,
}) {
return new TypedefTearOff(structuralParameters, expression, typeArguments)
..fileOffset = fileOffset;
}
TypeLiteral createTypeLiteral(DartType type, {required int fileOffset}) {
return new TypeLiteral(type)..fileOffset = fileOffset;
}
TypeParameter createTypeParameter(String? name, {required int fileOffset}) {
return new TypeParameter(name)..fileOffset = fileOffset;
}
/// Creates an uninitialized [Variable] of the static [type].
SyntheticVariable createUninitializedVariable({
required DartType type,
String? name,
required int fileOffset,
bool isFinal = false,
bool isLowered = false,
bool isSynthesized = true,
bool hasDeclaredInitializer = false,
}) {
return new SyntheticVariable(
cosmeticName: name,
type: type,
isFinal: isFinal,
isLowered: isLowered,
hasDeclaredInitializer: hasDeclaredInitializer,
isSynthesized: isSynthesized,
)..fileOffset = fileOffset;
}
/// Creates a declaration of an uninitialized [Variable] of the static [type].
VariableDeclaration createUninitializedVariableDeclaration({
required DartType type,
String? name,
required int fileOffset,
bool isFinal = false,
}) {
return createVariableDeclaration(
createUninitializedVariable(
type: type,
name: name,
fileOffset: fileOffset,
isFinal: isFinal,
),
);
}
/// Creates a [Variable] for [expression] with the static [type]
/// using `expression.fileOffset` as the file offset for the declaration.
// TODO(johnniwinther): Merge the use of this with [createVariableCache].
SyntheticVariable createVariable(
Expression expression,
DartType type, {
String? cosmeticName,
int? fileOffset,
bool isLowered = false,
bool isSynthesized = true,
bool isFinal = true,
}) {
assert(expression is! ThisExpression);
return new SyntheticVariable(
cosmeticName: cosmeticName,
initializer: expression,
type: type,
isLowered: isLowered,
isFinal: isFinal,
isSynthesized: isSynthesized,
hasDeclaredInitializer: true,
)..fileOffset = fileOffset ?? expression.fileOffset;
}
/// Creates a [Variable] for caching [expression] of the static
/// [type] using `expression.fileOffset` as the file offset for the declaration.
SyntheticVariable createVariableCache(
Expression expression,
DartType type, {
int? fileOffset,
}) {
return new SyntheticVariable(
initializer: expression,
type: type,
isFinal: true,
hasDeclaredInitializer: true,
)..fileOffset = fileOffset ?? expression.fileOffset;
}
VariableDeclaration createVariableDeclaration(
DeclaredVariable variable, {
// TODO(johnniwinther): Make this required.
Expression? initializer,
List<VariableContext>? capturedContexts,
int? fileOffset,
}) {
if (initializer != null) {
variable.initializer = initializer..parent = variable;
}
return new VariableDeclaration(variable)
..capturedContexts = capturedContexts
..fileOffset = fileOffset ?? variable.fileOffset;
}
/// Creates a [VariableGet] of [variable] using `variable.fileOffset` as the
/// file offset for the expression.
VariableGet createVariableGet(
Variable variable, {
DartType? promotedType,
int? fileOffset,
}) {
return new VariableGet(variable)
..fileOffset = fileOffset ?? variable.fileOffset
..promotedType = promotedType != variable.type ? promotedType : null;
}
VariablePattern createVariablePattern({
required DartType? type,
required DeclaredVariable variable,
required DartType matchedValueType,
required int fileOffset,
}) {
return new VariablePattern(type, variable)
..matchedValueType = matchedValueType
..fileOffset = fileOffset;
}
/// Creates a [VariableSet] of [variable] with the [value].
Expression createVariableSet(
Variable variable,
Expression value, {
bool allowFinalAssignment = false,
required int fileOffset,
}) {
if (variable is LocalFunctionVariable) {
return createLocalFunctionInvocation(
variable,
arguments: createArguments([value], fileOffset: fileOffset),
fileOffset: fileOffset,
);
} else {
assert(
allowFinalAssignment || variable.isAssignable,
"Cannot assign to variable $variable",
);
return new VariableSet(variable, value)..fileOffset = fileOffset;
}
}
VariableStatement createVariableStatement(
VariableDeclaration declaration, {
int? fileOffset,
}) {
return new VariableStatement(declaration)
..fileOffset = fileOffset ?? declaration.fileOffset;
}
Statement createWhileStatement(
Expression condition,
Statement body, {
required Scope? scope,
required int fileOffset,
}) {
return new WhileStatement(condition, body)
..scope = scope
..fileOffset = fileOffset;
}
WildcardPattern createWildcardPattern({
required DartType? type,
required int fileOffset,
}) {
return new WildcardPattern(type)..fileOffset = fileOffset;
}
YieldStatement createYieldStatement(
Expression expression, {
required bool isYieldStar,
required int fileOffset,
}) {
return new YieldStatement(expression, isYieldStar: isYieldStar)
..fileOffset = fileOffset;
}
/// Returns `true` if [node] is a pure expression.
///
/// A pure expression is an expression that is deterministic and side effect
/// free, such as `this` or a variable get of a final variable.
bool isPureExpression(Expression node) {
if (node is ThisExpression) {
return true;
} else if (node is VariableGet) {
return node.variable.isFinal && !node.variable.isLate;
}
return false;
}