blob: 19206627a1a8afe69b899743e03fc97fa487fbb9 [file] [log] [blame] [edit]
// Copyright (c) 2019, 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.
// ignore: implementation_imports
import 'package:front_end/src/api_prototype/static_weak_references.dart'
as ir
show StaticWeakReferences;
// ignore: implementation_imports
import 'package:front_end/src/api_unstable/dart2js.dart' show Operator;
import 'package:kernel/ast.dart' as ir;
import 'package:kernel/class_hierarchy.dart' as ir;
import 'package:kernel/type_environment.dart' as ir;
import 'package:kernel/type_algebra.dart' as ir;
import '../common.dart';
import '../common/elements.dart';
import '../common/names.dart' show Identifiers, Uris;
import '../elements/entities.dart';
import '../elements/types.dart';
import '../kernel/element_map.dart';
import '../options.dart';
import '../util/enumset.dart';
import 'constants.dart';
import 'impact.dart';
import 'protobuf_impacts.dart';
import 'runtime_type_analysis.dart';
import 'util.dart';
/// Checks [node] against available [ConditionalImpactHandler] to see if any
/// are applicable to it. Returns null if there is no matching handler.
ConditionalImpactHandler? _getConditionalImpactHandler(
KernelToElementMap elementMap,
ir.Member node,
) {
return ProtobufImpactHandler.createIfApplicable(elementMap, node);
}
abstract class ConditionalImpactHandler {
/// Invoked before children of [node] are analyzed. Returns a temporary
/// [ImpactData] if one should be used for the scope of [node] or null
/// otherwise.
ImpactData? beforeInstanceInvocation(ir.InstanceInvocation node);
/// Invoked after children of [node] are analyzed. Returns a
/// [ConditionalImpactData] containing the conditional data to register for
/// [node]. Returns null if [node] is not relevant to this handler.
ConditionalImpactData? afterInstanceInvocation(ir.InstanceInvocation node);
}
class _ConditionalImpactBuilder extends ImpactBuilder {
final ConditionalImpactHandler _conditionalHandler;
_ConditionalImpactBuilder._(
super.elementMap,
super.node,
this._conditionalHandler,
) : super._();
@override
void visitInstanceInvocation(ir.InstanceInvocation node) {
final oldData = _data;
_data = _conditionalHandler.beforeInstanceInvocation(node) ?? _data;
super.visitInstanceInvocation(node);
final conditionalData = _conditionalHandler.afterInstanceInvocation(node);
if (conditionalData != null) {
final replacement = conditionalData.replacement;
if (replacement != null) {
final replacementImpact = _data = ImpactData();
replacement.accept(this);
conditionalData.replacementImpactData = replacementImpact;
}
_data = oldData;
registerConditionalImpact(conditionalData);
} else {
_data = oldData;
}
}
}
/// Visitor that builds an [ImpactData] object for the world impact.
class ImpactBuilder extends ir.RecursiveVisitor implements ImpactRegistry {
ImpactData _data = ImpactData();
final ir.Member node;
final KernelToElementMap _elementMap;
final ir.StaticTypeContext staticTypeContext;
factory ImpactBuilder(KernelToElementMap elementMap, ir.Member node) {
final conditionalHandler = _getConditionalImpactHandler(elementMap, node);
return conditionalHandler != null
? _ConditionalImpactBuilder._(elementMap, node, conditionalHandler)
: ImpactBuilder._(elementMap, node);
}
ImpactBuilder._(this._elementMap, this.node)
: staticTypeContext = ir.StaticTypeContext(
node,
_elementMap.typeEnvironment,
);
CommonElements get _commonElements => _elementMap.commonElements;
DiagnosticReporter get _reporter => _elementMap.reporter;
ir.ClassHierarchy get classHierarchy => _elementMap.classHierarchy;
ir.TypeEnvironment get typeEnvironment => _elementMap.typeEnvironment;
CompilerOptions get _options => _elementMap.options;
String _typeToString(DartType type) =>
type.toStructuredText(_elementMap.types);
/// Return the named arguments names as a list of strings.
List<String> _getNamedArguments(ir.Arguments arguments) =>
arguments.named.map((n) => n.name).toList();
ImpactBuilderData computeImpact() {
node.accept(this);
return ImpactBuilderData(node, _data);
}
@override
void visitBlock(ir.Block node) {
assert(
_pendingRuntimeTypeUseData.isEmpty,
"Incomplete RuntimeTypeUseData: $_pendingRuntimeTypeUseData",
);
for (var e in node.statements) {
e.accept(this);
}
assert(
_pendingRuntimeTypeUseData.isEmpty,
"Incomplete RuntimeTypeUseData: $_pendingRuntimeTypeUseData",
);
}
@override
void visitIntLiteral(ir.IntLiteral node) {
registerIntLiteral();
}
@override
void visitDoubleLiteral(ir.DoubleLiteral node) {
registerDoubleLiteral();
}
@override
void visitBoolLiteral(ir.BoolLiteral node) {
registerBoolLiteral();
}
@override
void visitStringLiteral(ir.StringLiteral node) {
registerStringLiteral();
}
@override
void visitSymbolLiteral(ir.SymbolLiteral node) {
registerSymbolLiteral();
}
@override
void visitNullLiteral(ir.NullLiteral node) {
registerNullLiteral();
}
@override
void visitListLiteral(ir.ListLiteral node) {
registerListLiteral(
node.typeArgument,
isConst: node.isConst,
isEmpty: node.expressions.isEmpty,
);
for (var e in node.expressions) {
e.accept(this);
}
}
@override
void visitSetLiteral(ir.SetLiteral node) {
registerSetLiteral(
node.typeArgument,
isConst: node.isConst,
isEmpty: node.expressions.isEmpty,
);
for (var e in node.expressions) {
e.accept(this);
}
}
@override
void visitMapLiteral(ir.MapLiteral node) {
registerMapLiteral(
node.keyType,
node.valueType,
isConst: node.isConst,
isEmpty: node.entries.isEmpty,
);
for (var e in node.entries) {
e.accept(this);
}
}
@override
void visitRecordLiteral(ir.RecordLiteral node) {
registerRecordLiteral(node.recordType, isConst: node.isConst);
for (var e in node.positional) {
e.accept(this);
}
for (var e in node.named) {
e.value.accept(this);
}
}
@override
void visitStaticGet(ir.StaticGet node) {
registerStaticGet(node.target, getDeferredImport(node));
}
@override
void visitStaticTearOff(ir.StaticTearOff node) {
registerStaticTearOff(node.target, getDeferredImport(node));
}
@override
void visitStaticSet(ir.StaticSet node) {
registerStaticSet(node.target, getDeferredImport(node));
node.value.accept(this);
}
@override
void visitAssertStatement(ir.AssertStatement node) {
registerAssert(withMessage: node.message != null);
node.condition.accept(this);
node.message?.accept(this);
}
@override
void visitInstantiation(ir.Instantiation node) {
registerGenericInstantiation(
node.expression.getStaticType(staticTypeContext) as ir.FunctionType,
node.typeArguments,
);
node.expression.accept(this);
}
void handleAsyncMarker(ir.FunctionNode function) {
switch (function.asyncMarker) {
case ir.AsyncMarker.Sync:
break;
case ir.AsyncMarker.SyncStar:
registerSyncStar(function.emittedValueType!);
break;
case ir.AsyncMarker.Async:
registerAsync(function.emittedValueType!);
break;
case ir.AsyncMarker.AsyncStar:
registerAsyncStar(function.emittedValueType!);
break;
}
}
@override
void visitStringConcatenation(ir.StringConcatenation node) {
registerStringConcatenation();
for (var e in node.expressions) {
e.accept(this);
}
}
@override
void visitFunctionDeclaration(ir.FunctionDeclaration node) {
registerLocalFunction(node);
node.function.accept(this);
}
@override
void visitFunctionExpression(ir.FunctionExpression node) {
registerLocalFunction(node);
node.function.accept(this);
}
@override
void visitVariableDeclaration(ir.VariableDeclaration node) {
if (node.initializer == null) {
registerLocalWithoutInitializer();
}
// Don't visit the annotations as any impacts generated by that code are not
// real and should not be included in compiled code.
node.initializer?.accept(this);
}
@override
void visitIsExpression(ir.IsExpression node) {
registerIsCheck(node.type);
node.operand.accept(this);
}
@override
void visitAsExpression(ir.AsExpression node) {
final operandType = node.operand.getStaticType(staticTypeContext);
final isCalculatedTypeSubtype = typeEnvironment.isSubtypeOf(
operandType,
node.type,
);
if (!isCalculatedTypeSubtype) {
// Only register needed cast.
if (node.isTypeError) {
registerImplicitCast(node.type);
} else {
registerAsCast(node.type);
}
}
node.operand.accept(this);
}
@override
void visitThrow(ir.Throw node) {
registerThrow();
node.expression.accept(this);
}
ir.InterfaceType? getInterfaceTypeOf(ir.DartType type) {
while (type is ir.TypeParameterType) {
type = type.parameter.bound;
}
if (type is ir.InterfaceType) {
return type;
} else if (type is ir.NullType) {
return typeEnvironment.coreTypes.deprecatedNullType;
}
return null;
}
@override
void visitForInStatement(ir.ForInStatement node) {
// TODO(fishythefish): Clean up this logic.
ir.DartType iterableType = node.iterable.getStaticType(staticTypeContext);
ir.DartType iteratorType = const ir.DynamicType();
ir.InterfaceType? iterableInterfaceType = getInterfaceTypeOf(iterableType);
if (iterableInterfaceType != null) {
if (node.isAsync) {
List<ir.DartType>? typeArguments = typeEnvironment
.getTypeArgumentsAsInstanceOf(
iterableInterfaceType,
typeEnvironment.coreTypes.streamClass,
);
if (typeArguments != null) {
iteratorType = ir.InterfaceType(
typeEnvironment.coreTypes.streamIteratorClass,
ir.Nullability.nonNullable,
typeArguments,
);
}
} else {
ir.Member? member = classHierarchy.getInterfaceMember(
iterableInterfaceType.classNode,
ir.Name(Identifiers.iterator),
);
if (member != null) {
iteratorType = ir.Substitution.fromTypeDeclarationType(
typeEnvironment.getTypeAsInstanceOf(
iterableInterfaceType,
member.enclosingClass!,
typeEnvironment.coreTypes,
)!,
).substituteType(member.getterType);
}
}
}
if (node.isAsync) {
registerAsyncForIn(iterableType, iteratorType);
} else {
registerSyncForIn(iterableType, iteratorType);
}
node.iterable.accept(this);
node.variable.accept(this);
node.body.accept(this);
}
@override
void visitCatch(ir.Catch node) {
registerCatch();
if (node.stackTrace != null) {
registerStackTrace();
}
if (node.guard is! ir.DynamicType) {
registerCatchType(node.guard);
}
node.body.accept(this);
}
@override
void visitTypeLiteral(ir.TypeLiteral node) {
registerTypeLiteral(node.type, getDeferredImport(node));
}
@override
void visitFieldInitializer(ir.FieldInitializer node) {
registerFieldInitialization(node.field);
node.value.accept(this);
}
@override
void visitLoadLibrary(ir.LoadLibrary node) {
registerLoadLibrary();
}
@override
void visitRedirectingInitializer(ir.RedirectingInitializer node) {
registerRedirectingInitializer(
node.target,
node.arguments.positional.length,
_getNamedArguments(node.arguments),
node.arguments.types,
);
node.arguments.accept(this);
}
@override
void visitFunctionNode(ir.FunctionNode node) {
handleAsyncMarker(node);
for (ir.TypeParameter parameter in node.typeParameters) {
registerParameterCheck(parameter.bound);
}
for (ir.VariableDeclaration parameter in node.positionalParameters) {
registerParameterCheck(parameter.type);
parameter.initializer?.accept(this);
}
for (ir.VariableDeclaration parameter in node.namedParameters) {
registerParameterCheck(parameter.type);
parameter.initializer?.accept(this);
}
node.body?.accept(this);
}
@override
void visitConstructor(ir.Constructor node) {
if (node.isExternal) registerExternalConstructorNode(node);
// Don't visit the annotations as any impacts generated by that code are not
// real and should not be included in compiled code.
for (var e in node.initializers) {
e.accept(this);
}
node.function.accept(this);
}
@override
void visitField(ir.Field node) {
registerParameterCheck(node.type);
if (node.initializer != null) {
if (!node.isInstanceMember &&
!node.isConst &&
node.initializer is! ir.NullLiteral) {
registerLazyField();
}
} else {
registerNullLiteral();
}
// TODO(sigmund): only save relevant fields (e.g. those for jsinterop
// or native types).
registerFieldNode(node);
// Don't visit the annotations as any impacts generated by that code are not
// real and should not be included in compiled code.
node.initializer?.accept(this);
}
@override
void visitProcedure(ir.Procedure node) {
if (node.isExternal) registerExternalProcedureNode(node);
// Don't visit the annotations as any impacts generated by that code are not
// real and should not be included in compiled code.
node.function.accept(this);
}
void _handleConstConstructorInvocation(ir.ConstructorInvocation node) {
assert(node.isConst);
ConstructorEntity constructor = _elementMap.getConstructor(node.target);
if (_commonElements.isSymbolConstructor(constructor)) {
DartType argumentType = _elementMap.getDartType(
node.arguments.positional.first.getStaticType(staticTypeContext),
);
// TODO(joshualitt): Does the CFE check this for us?
if (argumentType != _commonElements.stringType) {
// TODO(het): Get the actual span for the Symbol constructor argument
_reporter.reportErrorMessage(
currentElementSpannable,
MessageKind.stringExpected,
{'type': _typeToString(argumentType)},
);
return;
}
registerConstSymbolConstructorInvocationNode();
}
}
@override
void visitConstructorInvocation(ir.ConstructorInvocation node) {
registerNew(
node.target,
node.constructedType,
node.arguments.positional.length,
_getNamedArguments(node.arguments),
node.arguments.types,
getDeferredImport(node),
isConst: node.isConst,
);
if (node.isConst) {
_handleConstConstructorInvocation(node);
}
node.arguments.accept(this);
}
@override
void visitStaticInvocation(ir.StaticInvocation node) {
if (ir.StaticWeakReferences.isWeakReference(node)) {
registerWeakStaticTearOff(
ir.StaticWeakReferences.getWeakReferenceTarget(node),
getDeferredImport(
ir.StaticWeakReferences.getWeakReferenceArgument(node),
),
);
// We don't explicitly visit the argument for weak references.
} else {
int positionArguments = node.arguments.positional.length;
List<String> namedArguments = _getNamedArguments(node.arguments);
List<ir.DartType> typeArguments = node.arguments.types;
if (node.target.kind == ir.ProcedureKind.Factory) {
// TODO(johnniwinther): We should not mark the type as instantiated but
// rather follow the type arguments directly.
//
// Consider this:
//
// abstract class A<T> {
// factory A.regular() => B<T>();
// factory A.redirect() = B<T>;
// }
//
// class B<T> implements A<T> {}
//
// main() {
// print(new A<int>.regular() is B<int>);
// print(new A<String>.redirect() is B<String>);
// }
//
// To track that B is actually instantiated as B<int> and B<String> we
// need to follow the type arguments passed to A.regular and A.redirect
// to B. Currently, we only do this soundly if we register A<int> and
// A<String> as instantiated. We should instead register that A.T is
// instantiated as int and String.
registerNew(
node.target,
ir.InterfaceType(
node.target.enclosingClass!,
node.target.enclosingLibrary.nonNullable,
typeArguments,
),
positionArguments,
namedArguments,
node.arguments.types,
getDeferredImport(node),
isConst: node.isConst,
);
} else {
registerStaticInvocation(
node.target,
positionArguments,
namedArguments,
typeArguments,
getDeferredImport(node),
);
}
// TODO(sigmund): consider using `_elementMap.getForeignKind` here. We
// currently don't use it because when this step is run modularly we try
// to keep most operations at the kernel level, otherwise it may triggers
// additional unnecessary work.
final name = node.target.name.text;
if (node.target.enclosingClass == null &&
node.target.enclosingLibrary.importUri == Uris.dartForeignHelper &&
getForeignKindFromName(name) != ForeignKind.none) {
registerForeignStaticInvocationNode(node);
}
node.arguments.accept(this);
}
}
@override
void visitDynamicInvocation(ir.DynamicInvocation node) {
int positionArguments = node.arguments.positional.length;
List<String> namedArguments = _getNamedArguments(node.arguments);
List<ir.DartType> typeArguments = node.arguments.types;
final receiverType = node.receiver.getStaticType(staticTypeContext);
registerDynamicInvocation(
receiverType,
node.name,
positionArguments,
namedArguments,
typeArguments,
);
if (Operator.fromText(node.name.text) == null &&
receiverType is ir.DynamicType) {
// We might implicitly call a getter that returns a function.
registerFunctionInvocation(
const ir.DynamicType(),
positionArguments,
namedArguments,
typeArguments,
);
}
node.arguments.accept(this);
node.receiver.accept(this);
}
@override
void visitFunctionInvocation(ir.FunctionInvocation node) {
int positionArguments = node.arguments.positional.length;
List<String> namedArguments = _getNamedArguments(node.arguments);
List<ir.DartType> typeArguments = node.arguments.types;
final receiverType = node.receiver.getStaticType(staticTypeContext);
registerFunctionInvocation(
receiverType,
positionArguments,
namedArguments,
typeArguments,
);
node.arguments.accept(this);
node.receiver.accept(this);
}
@override
void visitInstanceInvocation(ir.InstanceInvocation node) {
int positionArguments = node.arguments.positional.length;
List<String> namedArguments = _getNamedArguments(node.arguments);
List<ir.DartType> typeArguments = node.arguments.types;
final receiverType = node.receiver.getStaticType(staticTypeContext);
final interfaceTarget = node.interfaceTarget;
if (interfaceTarget.kind == ir.ProcedureKind.Getter) {
registerInstanceInvocation(
receiverType,
interfaceTarget,
positionArguments,
namedArguments,
typeArguments,
);
registerFunctionInvocation(
interfaceTarget.getterType,
positionArguments,
namedArguments,
typeArguments,
);
} else {
registerInstanceInvocation(
receiverType,
interfaceTarget,
positionArguments,
namedArguments,
typeArguments,
);
}
node.arguments.accept(this);
node.receiver.accept(this);
}
@override
void visitLocalFunctionInvocation(ir.LocalFunctionInvocation node) {
int positionArguments = node.arguments.positional.length;
List<String> namedArguments = _getNamedArguments(node.arguments);
List<ir.DartType> typeArguments = node.arguments.types;
registerLocalFunctionInvocation(
node.localFunction,
positionArguments,
namedArguments,
typeArguments,
);
node.arguments.accept(this);
}
@override
void visitEqualsCall(ir.EqualsCall node) {
final leftType = node.left.getStaticType(staticTypeContext);
registerInstanceInvocation(
leftType,
node.interfaceTarget,
1,
const <String>[],
const <ir.DartType>[],
);
node.left.accept(this);
node.right.accept(this);
}
@override
void visitEqualsNull(ir.EqualsNull node) {
registerNullLiteral();
node.expression.accept(this);
}
@override
void visitDynamicGet(ir.DynamicGet node) {
final receiverType = node.receiver.getStaticType(staticTypeContext);
registerDynamicGet(receiverType, node.name);
node.receiver.accept(this);
}
@override
void visitInstanceGet(ir.InstanceGet node) {
final receiverType = node.receiver.getStaticType(staticTypeContext);
registerInstanceGet(receiverType, node.interfaceTarget);
if (node.name.text == Identifiers.runtimeType_) {
// This handles `runtimeType` access on non-Never types, like in
// `'foo'.runtimeType`.
handleRuntimeTypeGet(receiverType, node);
}
node.receiver.accept(this);
}
@override
void visitInstanceTearOff(ir.InstanceTearOff node) {
final receiverType = node.receiver.getStaticType(staticTypeContext);
registerInstanceGet(receiverType, node.interfaceTarget);
assert(
node.name.text != Identifiers.runtimeType_,
"Unexpected .runtimeType instance tear-off.",
);
node.receiver.accept(this);
}
@override
void visitFunctionTearOff(ir.FunctionTearOff node) {
final receiverType = node.receiver.getStaticType(staticTypeContext);
registerDynamicGet(receiverType, ir.Name.callName);
node.receiver.accept(this);
}
@override
void visitInstanceGetterInvocation(ir.InstanceGetterInvocation node) {
int positionArguments = node.arguments.positional.length;
List<String> namedArguments = _getNamedArguments(node.arguments);
List<ir.DartType> typeArguments = node.arguments.types;
final receiverType = node.receiver.getStaticType(staticTypeContext);
final interfaceTarget = node.interfaceTarget;
if (interfaceTarget is ir.Field ||
(interfaceTarget is ir.Procedure &&
interfaceTarget.kind == ir.ProcedureKind.Getter)) {
registerInstanceInvocation(
receiverType,
interfaceTarget,
positionArguments,
namedArguments,
typeArguments,
);
registerFunctionInvocation(
interfaceTarget.getterType,
positionArguments,
namedArguments,
typeArguments,
);
} else {
registerInstanceInvocation(
receiverType,
interfaceTarget,
positionArguments,
namedArguments,
typeArguments,
);
}
node.receiver.accept(this);
node.arguments.accept(this);
}
@override
void visitDynamicSet(ir.DynamicSet node) {
final receiverType = node.receiver.getStaticType(staticTypeContext);
registerDynamicSet(receiverType, node.name);
node.receiver.accept(this);
node.value.accept(this);
}
@override
void visitInstanceSet(ir.InstanceSet node) {
final receiverType = node.receiver.getStaticType(staticTypeContext);
registerInstanceSet(receiverType, node.interfaceTarget);
node.receiver.accept(this);
node.value.accept(this);
}
@override
void visitSuperMethodInvocation(ir.SuperMethodInvocation node) {
registerSuperInvocation(
getEffectiveSuperTarget(node.interfaceTarget),
node.arguments.positional.length,
_getNamedArguments(node.arguments),
node.arguments.types,
);
node.arguments.accept(this);
}
@override
void visitSuperPropertyGet(ir.SuperPropertyGet node) {
registerSuperGet(getEffectiveSuperTarget(node.interfaceTarget));
}
@override
void visitSuperPropertySet(ir.SuperPropertySet node) {
registerSuperSet(getEffectiveSuperTarget(node.interfaceTarget));
node.value.accept(this);
}
@override
void visitSuperInitializer(ir.SuperInitializer node) {
registerSuperInitializer(
node.parent as ir.Constructor,
node.target,
node.arguments.positional.length,
_getNamedArguments(node.arguments),
node.arguments.types,
);
node.arguments.accept(this);
}
final Map<ir.InstanceGet, RuntimeTypeUseData> _pendingRuntimeTypeUseData = {};
void handleRuntimeTypeGet(ir.DartType receiverType, ir.InstanceGet node) {
RuntimeTypeUseData data = computeRuntimeTypeUse(
_pendingRuntimeTypeUseData,
node,
);
if (data.leftRuntimeTypeExpression == node) {
// [node] is the left (or single) occurrence of `.runtimeType` so we
// can set the static type of the receiver expression.
data.receiverType = receiverType;
} else {
// [node] is the right occurrence of `.runtimeType` so we
// can set the static type of the argument expression.
assert(
data.rightRuntimeTypeExpression == node,
"Unexpected RuntimeTypeUseData for $node: $data",
);
data.argumentType = receiverType;
}
if (data.isComplete) {
/// We now have all need static types so we can remove the data from
/// the cache and handle the runtime type use.
_pendingRuntimeTypeUseData.remove(data.leftRuntimeTypeExpression);
if (data.rightRuntimeTypeExpression != null) {
_pendingRuntimeTypeUseData.remove(data.rightRuntimeTypeExpression);
}
handleRuntimeTypeUse(
node,
data.kind,
data.receiverType!,
data.argumentType,
);
}
}
void handleRuntimeTypeUse(
ir.Expression node,
RuntimeTypeUseKind kind,
ir.DartType receiverType,
ir.DartType? argumentType,
) {
if (_options.omitImplicitChecks) {
switch (kind) {
case RuntimeTypeUseKind.string:
if (!_options.laxRuntimeTypeToString &&
// Silent on Golem to avoid excessive compiler diagnostics.
!_options.benchmarkingProduction) {
_reporter.reportHintMessage(
computeSourceSpanFromTreeNode(node),
MessageKind.runtimeTypeToString,
);
}
break;
case RuntimeTypeUseKind.equals:
case RuntimeTypeUseKind.unknown:
break;
}
}
registerRuntimeTypeUse(kind, receiverType, argumentType);
}
@override
void visitConstantExpression(ir.ConstantExpression node) {
assert(node.constant is! ir.UnevaluatedConstant);
ir.LibraryDependency? import = getDeferredImport(node);
ConstantImpactVisitor(
this,
import,
node,
staticTypeContext,
).visitConstant(node.constant);
}
void _registerFeature(_Feature feature) {
_data._features = _data._features.add(feature);
}
void _registerTypeUse(ir.DartType type, _TypeUseKind kind) {
(_data._typeUses ??= []).add(_TypeUse(type, kind));
}
@override
void registerSuperInitializer(
ir.Constructor source,
ir.Constructor target,
int positionalArguments,
List<String> namedArguments,
List<ir.DartType> typeArguments,
) {
(_data._superInitializers ??= []).add(
_SuperInitializer(
source,
target,
_CallStructure(positionalArguments, namedArguments, typeArguments),
),
);
}
@override
void registerSuperSet(ir.Member target) {
(_data._superSets ??= []).add(target);
}
@override
void registerSuperGet(ir.Member target) {
(_data._superGets ??= []).add(target);
}
@override
void registerSuperInvocation(
ir.Member target,
int positionalArguments,
List<String> namedArguments,
List<ir.DartType> typeArguments,
) {
(_data._superInvocations ??= []).add(
_SuperInvocation(
target,
_CallStructure(positionalArguments, namedArguments, typeArguments),
),
);
}
@override
void registerInstanceSet(ir.DartType receiverType, ir.Member target) {
(_data._instanceSets ??= []).add(_InstanceAccess(receiverType, target));
}
@override
void registerDynamicSet(ir.DartType receiverType, ir.Name name) {
(_data._dynamicSets ??= []).add(_DynamicAccess(receiverType, name));
}
@override
void registerInstanceGet(ir.DartType receiverType, ir.Member target) {
(_data._instanceGets ??= []).add(_InstanceAccess(receiverType, target));
}
@override
void registerDynamicGet(ir.DartType receiverType, ir.Name name) {
(_data._dynamicGets ??= []).add(_DynamicAccess(receiverType, name));
}
@override
void registerFunctionInvocation(
ir.DartType receiverType,
int positionalArguments,
List<String> namedArguments,
List<ir.DartType> typeArguments,
) {
(_data._functionInvocations ??= []).add(
_FunctionInvocation(
receiverType,
_CallStructure(positionalArguments, namedArguments, typeArguments),
),
);
}
@override
void registerInstanceInvocation(
ir.DartType receiverType,
ir.Member target,
int positionalArguments,
List<String> namedArguments,
List<ir.DartType> typeArguments,
) {
(_data._instanceInvocations ??= []).add(
_InstanceInvocation(
receiverType,
target,
_CallStructure(positionalArguments, namedArguments, typeArguments),
),
);
}
@override
void registerDynamicInvocation(
ir.DartType receiverType,
ir.Name name,
int positionalArguments,
List<String> namedArguments,
List<ir.DartType> typeArguments,
) {
(_data._dynamicInvocations ??= []).add(
_DynamicInvocation(
receiverType,
name,
_CallStructure(positionalArguments, namedArguments, typeArguments),
),
);
}
@override
void registerLocalFunctionInvocation(
ir.FunctionDeclaration localFunction,
int positionalArguments,
List<String> namedArguments,
List<ir.DartType> typeArguments,
) {
(_data._localFunctionInvocations ??= []).add(
_LocalFunctionInvocation(
localFunction,
_CallStructure(positionalArguments, namedArguments, typeArguments),
),
);
}
@override
void registerStaticInvocation(
ir.Procedure target,
int positionalArguments,
List<String> namedArguments,
List<ir.DartType> typeArguments,
ir.LibraryDependency? import,
) {
(_data._staticInvocations ??= []).add(
_StaticInvocation(
target,
_CallStructure(positionalArguments, namedArguments, typeArguments),
import,
),
);
}
@override
void registerNew(
ir.Member constructor,
ir.InterfaceType type,
int positionalArguments,
List<String> namedArguments,
List<ir.DartType> typeArguments,
ir.LibraryDependency? import, {
required bool isConst,
}) {
(_data._constructorInvocations ??= []).add(
_ConstructorInvocation(
constructor,
type,
_CallStructure(positionalArguments, namedArguments, typeArguments),
import,
isConst: isConst,
),
);
}
@override
void registerConstInstantiation(
ir.Class cls,
List<ir.DartType> typeArguments,
ir.LibraryDependency? import,
) {
(_data._constInstantiations ??= []).add(
_ConstInstantiation(cls, typeArguments, import),
);
}
@override
void registerLazyField() {
_registerFeature(_Feature.lazyField);
}
@override
void registerParameterCheck(ir.DartType type) {
_registerTypeUse(type, _TypeUseKind.parameterCheck);
}
@override
void registerRedirectingInitializer(
ir.Constructor constructor,
int positionalArguments,
List<String> namedArguments,
List<ir.DartType> typeArguments,
) {
(_data._redirectingInitializers ??= []).add(
_RedirectingInitializer(
constructor,
_CallStructure(positionalArguments, namedArguments, typeArguments),
),
);
}
@override
void registerLoadLibrary() {
_registerFeature(_Feature.loadLibrary);
}
@override
void registerFieldInitialization(ir.Field node) {
(_data._fieldInitializers ??= []).add(node);
}
@override
void registerFieldConstantInitialization(
ir.Field node,
ConstantReference constant,
) {
(_data._fieldConstantInitializers ??= {})
.putIfAbsent(node, () => [])
.add(constant);
}
@override
void registerTypeLiteral(ir.DartType type, ir.LibraryDependency? import) {
(_data._typeLiterals ??= []).add(_TypeLiteral(type, import));
}
@override
void registerCatchType(ir.DartType type) {
_registerTypeUse(type, _TypeUseKind.catchType);
}
@override
void registerStackTrace() {
_registerFeature(_Feature.stackTrace);
}
@override
void registerCatch() {
_registerFeature(_Feature.catchClause);
}
@override
void registerAsyncForIn(ir.DartType iterableType, ir.DartType iteratorType) {
(_data._forInData ??= []).add(
_ForInData(iterableType, iteratorType, isAsync: true),
);
}
@override
void registerSyncForIn(ir.DartType iterableType, ir.DartType iteratorType) {
(_data._forInData ??= []).add(
_ForInData(iterableType, iteratorType, isAsync: false),
);
}
@override
void registerThrow() {
_registerFeature(_Feature.throwExpression);
}
@override
void registerAsCast(ir.DartType type) {
_registerTypeUse(type, _TypeUseKind.asCast);
}
@override
void registerImplicitCast(ir.DartType type) {
_registerTypeUse(type, _TypeUseKind.implicitCast);
}
@override
void registerIsCheck(ir.DartType type) {
_registerTypeUse(type, _TypeUseKind.isCheck);
}
@override
void registerLocalWithoutInitializer() {
_registerFeature(_Feature.localWithoutInitializer);
}
@override
void registerLocalFunction(ir.TreeNode node) {
(_data._localFunctions ??= []).add(node);
}
@override
void registerStringConcatenation() {
_registerFeature(_Feature.stringConcatenation);
}
@override
void registerAsyncStar(ir.DartType elementType) {
_registerTypeUse(elementType, _TypeUseKind.asyncStarMarker);
}
@override
void registerAsync(ir.DartType elementType) {
_registerTypeUse(elementType, _TypeUseKind.asyncMarker);
}
@override
void registerSyncStar(ir.DartType elementType) {
_registerTypeUse(elementType, _TypeUseKind.syncStarMarker);
}
@override
void registerGenericInstantiation(
ir.FunctionType expressionType,
List<ir.DartType> typeArguments,
) {
(_data._genericInstantiations ??= []).add(
_GenericInstantiation(expressionType, typeArguments),
);
}
@override
void registerAssert({required bool withMessage}) {
_registerFeature(
withMessage ? _Feature.assertWithMessage : _Feature.assertWithoutMessage,
);
}
@override
void registerStaticSet(ir.Member member, ir.LibraryDependency? import) {
(_data._staticSets ??= []).add(_StaticAccess(member, import));
}
@override
void registerStaticGet(ir.Member member, ir.LibraryDependency? import) {
(_data._staticGets ??= []).add(_StaticAccess(member, import));
}
@override
void registerStaticTearOff(
ir.Procedure procedure,
ir.LibraryDependency? import,
) {
(_data._staticTearOffs ??= []).add(_StaticAccess(procedure, import));
}
@override
void registerWeakStaticTearOff(
ir.Procedure procedure,
ir.LibraryDependency? import,
) {
(_data._weakStaticTearOffs ??= []).add(_StaticAccess(procedure, import));
}
@override
void registerMapLiteral(
ir.DartType keyType,
ir.DartType valueType, {
required bool isConst,
required bool isEmpty,
}) {
(_data._mapLiterals ??= []).add(
_MapLiteral(keyType, valueType, isConst: isConst, isEmpty: isEmpty),
);
}
@override
void registerListLiteral(
ir.DartType elementType, {
required bool isConst,
required bool isEmpty,
}) {
(_data._listLiterals ??= []).add(
_ContainerLiteral(elementType, isConst: isConst, isEmpty: isEmpty),
);
}
@override
void registerSetLiteral(
ir.DartType elementType, {
required bool isConst,
required bool isEmpty,
}) {
(_data._setLiterals ??= []).add(
_ContainerLiteral(elementType, isConst: isConst, isEmpty: isEmpty),
);
}
@override
void registerRecordLiteral(
ir.RecordType recordType, {
required bool isConst,
}) {
(_data._recordLiterals ??= []).add(
_RecordLiteral(recordType, isConst: isConst),
);
}
@override
void registerNullLiteral() {
_registerFeature(_Feature.nullLiteral);
}
@override
void registerSymbolLiteral() {
_registerFeature(_Feature.symbolLiteral);
}
@override
void registerStringLiteral() {
_registerFeature(_Feature.stringLiteral);
}
@override
void registerBoolLiteral() {
_registerFeature(_Feature.boolLiteral);
}
@override
void registerDoubleLiteral() {
_registerFeature(_Feature.doubleLiteral);
}
@override
void registerIntLiteral() {
_registerFeature(_Feature.intLiteral);
}
@override
void registerRuntimeTypeUse(
RuntimeTypeUseKind kind,
ir.DartType receiverType,
ir.DartType? argumentType,
) {
(_data._runtimeTypeUses ??= []).add(
_RuntimeTypeUse(kind, receiverType, argumentType),
);
}
@override
void registerExternalConstructorNode(ir.Constructor node) {
(_data._externalConstructorNodes ??= []).add(node);
}
@override
void registerFieldNode(ir.Field node) {
(_data._fieldNodes ??= []).add(node);
}
@override
void registerExternalProcedureNode(ir.Procedure node) {
(_data._externalProcedureNodes ??= []).add(node);
}
@override
void registerForeignStaticInvocationNode(ir.StaticInvocation node) {
(_data._foreignStaticInvocationNodes ??= []).add(node);
}
@override
void registerConstSymbolConstructorInvocationNode() {
_data._hasConstSymbolConstructorInvocation = true;
}
@override
void registerConditionalImpact(ConditionalImpactData impact) {
// Ensure conditional impact is registered on parent impact, `_data`.
(_data._conditionalImpacts ??= []).add(impact);
}
}
class ConditionalImpactData {
final ir.TreeNode? original;
final ir.TreeNode? replacement;
final List<ir.Member> originalConditions;
final ImpactData impactData;
late ImpactData replacementImpactData;
ConditionalImpactData(
this.originalConditions,
this.impactData, {
this.original,
this.replacement,
});
}
/// Data object that contains the world impact data derived purely from kernel.
/// It is critical that all of the data in this class be invariant to changes in
/// the AST that occur after modular compilation and before deserializing the
/// impact data.
class ImpactData {
static const String tag = 'ImpactData';
List<_SuperInitializer>? _superInitializers;
List<ir.Member>? _superSets;
List<ir.Member>? _superGets;
List<_SuperInvocation>? _superInvocations;
List<_InstanceAccess>? _instanceSets;
List<_DynamicAccess>? _dynamicSets;
List<_InstanceAccess>? _instanceGets;
List<_DynamicAccess>? _dynamicGets;
List<_FunctionInvocation>? _functionInvocations;
List<_InstanceInvocation>? _instanceInvocations;
List<_DynamicInvocation>? _dynamicInvocations;
List<_LocalFunctionInvocation>? _localFunctionInvocations;
List<_StaticInvocation>? _staticInvocations;
List<_ConstructorInvocation>? _constructorInvocations;
List<_ConstInstantiation>? _constInstantiations;
EnumSet<_Feature> _features = EnumSet.empty();
List<_TypeUse>? _typeUses;
List<_RedirectingInitializer>? _redirectingInitializers;
List<ir.Field>? _fieldInitializers;
Map<ir.Field, List<ConstantReference>>? _fieldConstantInitializers;
List<_TypeLiteral>? _typeLiterals;
List<ir.TreeNode>? _localFunctions;
List<_GenericInstantiation>? _genericInstantiations;
List<_StaticAccess>? _staticSets;
List<_StaticAccess>? _staticGets;
List<_StaticAccess>? _staticTearOffs;
List<_StaticAccess>? _weakStaticTearOffs;
List<_MapLiteral>? _mapLiterals;
List<_ContainerLiteral>? _listLiterals;
List<_ContainerLiteral>? _setLiterals;
List<_RecordLiteral>? _recordLiterals;
List<_RuntimeTypeUse>? _runtimeTypeUses;
List<_ForInData>? _forInData;
List<ConditionalImpactData>? _conditionalImpacts;
// TODO(johnniwinther): Remove these when CFE provides constants.
List<ir.Constructor>? _externalConstructorNodes;
List<ir.Field>? _fieldNodes;
List<ir.Procedure>? _externalProcedureNodes;
List<ir.StaticInvocation>? _foreignStaticInvocationNodes;
bool _hasConstSymbolConstructorInvocation = false;
ImpactData();
/// Registers the impact data with [registry].
void apply(ImpactRegistry registry) {
if (_superInitializers != null) {
for (_SuperInitializer data in _superInitializers!) {
registry.registerSuperInitializer(
data.source,
data.target,
data.callStructure.positionalArguments,
data.callStructure.namedArguments,
data.callStructure.typeArguments,
);
}
}
if (_superSets != null) {
for (ir.Member data in _superSets!) {
registry.registerSuperSet(data);
}
}
if (_superGets != null) {
for (ir.Member data in _superGets!) {
registry.registerSuperGet(data);
}
}
if (_superInvocations != null) {
for (_SuperInvocation data in _superInvocations!) {
registry.registerSuperInvocation(
data.target,
data.callStructure.positionalArguments,
data.callStructure.namedArguments,
data.callStructure.typeArguments,
);
}
}
if (_instanceSets != null) {
for (_InstanceAccess data in _instanceSets!) {
registry.registerInstanceSet(data.receiverType, data.target);
}
}
if (_dynamicSets != null) {
for (_DynamicAccess data in _dynamicSets!) {
registry.registerDynamicSet(data.receiverType, data.name);
}
}
if (_instanceGets != null) {
for (_InstanceAccess data in _instanceGets!) {
registry.registerInstanceGet(data.receiverType, data.target);
}
}
if (_dynamicGets != null) {
for (_DynamicAccess data in _dynamicGets!) {
registry.registerDynamicGet(data.receiverType, data.name);
}
}
if (_functionInvocations != null) {
for (_FunctionInvocation data in _functionInvocations!) {
registry.registerFunctionInvocation(
data.receiverType,
data.callStructure.positionalArguments,
data.callStructure.namedArguments,
data.callStructure.typeArguments,
);
}
}
if (_instanceInvocations != null) {
for (_InstanceInvocation data in _instanceInvocations!) {
registry.registerInstanceInvocation(
data.receiverType,
data.target,
data.callStructure.positionalArguments,
data.callStructure.namedArguments,
data.callStructure.typeArguments,
);
}
}
if (_dynamicInvocations != null) {
for (_DynamicInvocation data in _dynamicInvocations!) {
registry.registerDynamicInvocation(
data.receiverType,
data.name,
data.callStructure.positionalArguments,
data.callStructure.namedArguments,
data.callStructure.typeArguments,
);
}
}
if (_localFunctionInvocations != null) {
for (_LocalFunctionInvocation data in _localFunctionInvocations!) {
registry.registerLocalFunctionInvocation(
data.localFunction,
data.callStructure.positionalArguments,
data.callStructure.namedArguments,
data.callStructure.typeArguments,
);
}
}
if (_staticInvocations != null) {
for (_StaticInvocation data in _staticInvocations!) {
registry.registerStaticInvocation(
data.target,
data.callStructure.positionalArguments,
data.callStructure.namedArguments,
data.callStructure.typeArguments,
data.import,
);
}
}
if (_constructorInvocations != null) {
for (_ConstructorInvocation data in _constructorInvocations!) {
registry.registerNew(
data.constructor,
data.type,
data.callStructure.positionalArguments,
data.callStructure.namedArguments,
data.callStructure.typeArguments,
data.import,
isConst: data.isConst,
);
}
}
if (_constInstantiations != null) {
for (_ConstInstantiation data in _constInstantiations!) {
registry.registerConstInstantiation(
data.cls,
data.typeArguments,
data.import,
);
}
}
if (_features.isNotEmpty) {
for (_Feature data in _features.iterable(_Feature.values)) {
switch (data) {
case _Feature.lazyField:
registry.registerLazyField();
break;
case _Feature.loadLibrary:
registry.registerLoadLibrary();
break;
case _Feature.stackTrace:
registry.registerStackTrace();
break;
case _Feature.catchClause:
registry.registerCatch();
break;
case _Feature.throwExpression:
registry.registerThrow();
break;
case _Feature.localWithoutInitializer:
registry.registerLocalWithoutInitializer();
break;
case _Feature.stringConcatenation:
registry.registerStringConcatenation();
break;
case _Feature.assertWithMessage:
registry.registerAssert(withMessage: true);
break;
case _Feature.assertWithoutMessage:
registry.registerAssert(withMessage: false);
break;
case _Feature.nullLiteral:
registry.registerNullLiteral();
break;
case _Feature.symbolLiteral:
registry.registerSymbolLiteral();
break;
case _Feature.stringLiteral:
registry.registerStringLiteral();
break;
case _Feature.boolLiteral:
registry.registerBoolLiteral();
break;
case _Feature.doubleLiteral:
registry.registerDoubleLiteral();
break;
case _Feature.intLiteral:
registry.registerIntLiteral();
break;
}
}
}
if (_typeUses != null) {
for (_TypeUse data in _typeUses!) {
switch (data.kind) {
case _TypeUseKind.parameterCheck:
registry.registerParameterCheck(data.type);
break;
case _TypeUseKind.catchType:
registry.registerCatchType(data.type);
break;
case _TypeUseKind.asCast:
registry.registerAsCast(data.type);
break;
case _TypeUseKind.implicitCast:
registry.registerImplicitCast(data.type);
break;
case _TypeUseKind.isCheck:
registry.registerIsCheck(data.type);
break;
case _TypeUseKind.asyncStarMarker:
registry.registerAsyncStar(data.type);
break;
case _TypeUseKind.asyncMarker:
registry.registerAsync(data.type);
break;
case _TypeUseKind.syncStarMarker:
registry.registerSyncStar(data.type);
break;
}
}
}
if (_redirectingInitializers != null) {
for (_RedirectingInitializer data in _redirectingInitializers!) {
registry.registerRedirectingInitializer(
data.constructor,
data.callStructure.positionalArguments,
data.callStructure.namedArguments,
data.callStructure.typeArguments,
);
}
}
if (_fieldInitializers != null) {
for (ir.Field data in _fieldInitializers!) {
registry.registerFieldInitialization(data);
}
}
if (_fieldConstantInitializers != null) {
_fieldConstantInitializers!.forEach((
ir.Field field,
List<ConstantReference> constants,
) {
for (ConstantReference constant in constants) {
registry.registerFieldConstantInitialization(field, constant);
}
});
}
if (_typeLiterals != null) {
for (_TypeLiteral data in _typeLiterals!) {
registry.registerTypeLiteral(data.type, data.import);
}
}
if (_localFunctions != null) {
for (ir.TreeNode data in _localFunctions!) {
registry.registerLocalFunction(data);
}
}
if (_genericInstantiations != null) {
for (_GenericInstantiation data in _genericInstantiations!) {
registry.registerGenericInstantiation(
data.expressionType,
data.typeArguments,
);
}
}
if (_staticSets != null) {
for (_StaticAccess data in _staticSets!) {
registry.registerStaticSet(data.target, data.import);
}
}
if (_staticGets != null) {
for (_StaticAccess data in _staticGets!) {
registry.registerStaticGet(data.target, data.import);
}
}
if (_staticTearOffs != null) {
for (_StaticAccess data in _staticTearOffs!) {
registry.registerStaticTearOff(
data.target as ir.Procedure,
data.import,
);
}
}
if (_weakStaticTearOffs != null) {
for (_StaticAccess data in _weakStaticTearOffs!) {
registry.registerWeakStaticTearOff(
data.target as ir.Procedure,
data.import,
);
}
}
if (_mapLiterals != null) {
for (_MapLiteral data in _mapLiterals!) {
registry.registerMapLiteral(
data.keyType,
data.valueType,
isConst: data.isConst,
isEmpty: data.isEmpty,
);
}
}
if (_listLiterals != null) {
for (_ContainerLiteral data in _listLiterals!) {
registry.registerListLiteral(
data.elementType,
isConst: data.isConst,
isEmpty: data.isEmpty,
);
}
}
if (_setLiterals != null) {
for (_ContainerLiteral data in _setLiterals!) {
registry.registerSetLiteral(
data.elementType,
isConst: data.isConst,
isEmpty: data.isEmpty,
);
}
}
if (_recordLiterals != null) {
for (_RecordLiteral data in _recordLiterals!) {
registry.registerRecordLiteral(data.recordType, isConst: data.isConst);
}
}
if (_runtimeTypeUses != null) {
for (_RuntimeTypeUse data in _runtimeTypeUses!) {
registry.registerRuntimeTypeUse(
data.kind,
data.receiverType,
data.argumentType,
);
}
}
if (_forInData != null) {
for (_ForInData data in _forInData!) {
if (data.isAsync) {
registry.registerAsyncForIn(data.iterableType, data.iteratorType);
} else {
registry.registerSyncForIn(data.iterableType, data.iteratorType);
}
}
}
_conditionalImpacts?.forEach(registry.registerConditionalImpact);
// TODO(johnniwinther): Remove these when CFE provides constants.
if (_externalConstructorNodes != null) {
for (ir.Constructor data in _externalConstructorNodes!) {
registry.registerExternalConstructorNode(data);
}
}
if (_fieldNodes != null) {
for (ir.Field data in _fieldNodes!) {
registry.registerFieldNode(data);
}
}
if (_externalProcedureNodes != null) {
for (ir.Procedure data in _externalProcedureNodes!) {
registry.registerExternalProcedureNode(data);
}
}
if (_foreignStaticInvocationNodes != null) {
for (ir.StaticInvocation data in _foreignStaticInvocationNodes!) {
registry.registerForeignStaticInvocationNode(data);
}
}
if (_hasConstSymbolConstructorInvocation) {
registry.registerConstSymbolConstructorInvocationNode();
}
}
}
class _CallStructure {
final List<ir.DartType> typeArguments;
final int positionalArguments;
final List<String> namedArguments;
_CallStructure.internal(
this.typeArguments,
this.positionalArguments,
this.namedArguments,
);
factory _CallStructure(
int positionalArguments,
List<String> namedArguments,
List<ir.DartType> typeArguments,
) {
return _CallStructure.internal(
typeArguments,
positionalArguments,
namedArguments,
);
}
}
class _SuperInitializer {
final ir.Constructor source;
final ir.Constructor target;
final _CallStructure callStructure;
_SuperInitializer(this.source, this.target, this.callStructure);
}
class _SuperInvocation {
final ir.Member target;
final _CallStructure callStructure;
_SuperInvocation(this.target, this.callStructure);
}
class _InstanceAccess {
final ir.DartType receiverType;
final ir.Member target;
_InstanceAccess(this.receiverType, this.target);
}
class _DynamicAccess {
final ir.DartType receiverType;
final ir.Name name;
_DynamicAccess(this.receiverType, this.name);
}
class _FunctionInvocation {
final ir.DartType receiverType;
final _CallStructure callStructure;
_FunctionInvocation(this.receiverType, this.callStructure);
}
class _InstanceInvocation {
final ir.DartType receiverType;
final ir.Member target;
final _CallStructure callStructure;
_InstanceInvocation(this.receiverType, this.target, this.callStructure);
}
class _DynamicInvocation {
final ir.DartType receiverType;
final ir.Name name;
final _CallStructure callStructure;
_DynamicInvocation(this.receiverType, this.name, this.callStructure);
}
class _LocalFunctionInvocation {
final ir.FunctionDeclaration localFunction;
final _CallStructure callStructure;
_LocalFunctionInvocation(this.localFunction, this.callStructure);
}
class _StaticInvocation {
final ir.Procedure target;
final _CallStructure callStructure;
final ir.LibraryDependency? import;
_StaticInvocation(this.target, this.callStructure, this.import);
}
class _ConstructorInvocation {
final ir.Member constructor;
final ir.InterfaceType type;
final _CallStructure callStructure;
final ir.LibraryDependency? import;
final bool isConst;
_ConstructorInvocation(
this.constructor,
this.type,
this.callStructure,
this.import, {
required this.isConst,
});
}
class _ConstInstantiation {
final ir.Class cls;
final List<ir.DartType> typeArguments;
final ir.LibraryDependency? import;
_ConstInstantiation(this.cls, this.typeArguments, this.import);
}
enum _Feature {
lazyField,
loadLibrary,
stackTrace,
catchClause,
throwExpression,
localWithoutInitializer,
stringConcatenation,
assertWithMessage,
assertWithoutMessage,
nullLiteral,
stringLiteral,
boolLiteral,
intLiteral,
symbolLiteral,
doubleLiteral,
}
class _TypeUse {
final ir.DartType type;
final _TypeUseKind kind;
_TypeUse(this.type, this.kind);
}
enum _TypeUseKind {
parameterCheck,
catchType,
asCast,
implicitCast,
isCheck,
asyncStarMarker,
asyncMarker,
syncStarMarker,
}
class _RedirectingInitializer {
final ir.Constructor constructor;
final _CallStructure callStructure;
_RedirectingInitializer(this.constructor, this.callStructure);
}
class _TypeLiteral {
final ir.DartType type;
final ir.LibraryDependency? import;
_TypeLiteral(this.type, this.import);
}
class _GenericInstantiation {
final ir.FunctionType expressionType;
final List<ir.DartType> typeArguments;
_GenericInstantiation(this.expressionType, this.typeArguments);
}
class _StaticAccess {
final ir.Member target;
final ir.LibraryDependency? import;
_StaticAccess(this.target, this.import);
}
class _MapLiteral {
final ir.DartType keyType;
final ir.DartType valueType;
final bool isConst;
final bool isEmpty;
_MapLiteral(
this.keyType,
this.valueType, {
required this.isConst,
required this.isEmpty,
});
}
class _ContainerLiteral {
final ir.DartType elementType;
final bool isConst;
final bool isEmpty;
_ContainerLiteral(
this.elementType, {
required this.isConst,
required this.isEmpty,
});
}
class _RecordLiteral {
final ir.RecordType recordType;
final bool isConst;
_RecordLiteral(this.recordType, {required this.isConst});
}
class _RuntimeTypeUse {
final RuntimeTypeUseKind kind;
final ir.DartType receiverType;
final ir.DartType? argumentType;
_RuntimeTypeUse(this.kind, this.receiverType, this.argumentType);
}
class _ForInData {
final ir.DartType iterableType;
final ir.DartType iteratorType;
final bool isAsync;
_ForInData(this.iterableType, this.iteratorType, {required this.isAsync});
}