Migrate pkg/vm to null safety, part 3

TEST=ci

Issue: https://github.com/dart-lang/sdk/issues/46620
Change-Id: I1ab793eec6ffd7e01cee1e6641138e96a4f4d9fc
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/207864
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
Alexander Markov
2021-07-27 17:50:47 +00:00
committed by commit-bot@chromium.org
parent f4d3f801b3
commit ccd063bda5
14 changed files with 795 additions and 837 deletions
+141 -133
View File
@@ -2,10 +2,7 @@
// 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.
// @dart=2.9
/// Global type flow analysis.
library kernel.transformations.analysis;
import 'dart:collection';
import 'dart:core' hide Type;
@@ -51,24 +48,28 @@ import '../pragma.dart';
/// Maintains set of dependent invocations.
class _DependencyTracker {
Set<_Invocation> _dependentInvocations;
Set<_Invocation>? _dependentInvocations;
void addDependentInvocation(_Invocation invocation) {
if (!identical(invocation, this)) {
_dependentInvocations ??= new Set<_Invocation>();
_dependentInvocations.add(invocation);
var dependentInvocations = _dependentInvocations;
if (dependentInvocations == null) {
_dependentInvocations = dependentInvocations = Set<_Invocation>();
}
dependentInvocations.add(invocation);
}
}
void invalidateDependentInvocations(_WorkList workList) {
if (_dependentInvocations != null) {
final dependentInvocations = _dependentInvocations;
if (dependentInvocations != null) {
if (kPrintTrace) {
tracePrint(' - CHANGED: $this');
for (var di in _dependentInvocations) {
for (var di in dependentInvocations) {
tracePrint(' - invalidating $di');
}
}
_dependentInvocations.forEach(workList.invalidateInvocation);
dependentInvocations.forEach(workList.invalidateInvocation);
}
}
}
@@ -83,12 +84,12 @@ abstract class _Invocation extends _DependencyTracker
final Selector selector;
final Args<Type> args;
Type result;
Type? result;
/// Result of the invocation calculated before invocation was invalidated.
/// Used to check if the re-analysis of the invocation yields the same
/// result or not (to avoid invalidation of callers if result hasn't changed).
Type invalidatedResult;
Type? invalidatedResult;
/// Number of times result of this invocation was invalidated.
int invalidationCounter = 0;
@@ -108,7 +109,7 @@ abstract class _Invocation extends _DependencyTracker
/// Returns result of this invocation if its available without
/// further analysis, or `null` if it's not available.
/// Used for recursive calls while this invocation is being processed.
Type get resultForRecursiveInvocation => result;
Type? get resultForRecursiveInvocation => result;
/// Use [type] as a current computed result of this invocation.
/// If this invocation was invalidated, and the invalidated result is
@@ -116,7 +117,6 @@ abstract class _Invocation extends _DependencyTracker
/// Result type may be saturated if this invocation was invalidated
/// too many times.
void setResult(TypeFlowAnalysis typeFlowAnalysis, Type type) {
assert(type != null);
result = type;
if (invalidatedResult != null) {
@@ -132,8 +132,8 @@ abstract class _Invocation extends _DependencyTracker
// the analysis, result is saturated after invocation is invalidated
// at least [_Invocation.invalidationLimit] times.
if (invalidationCounter > _Invocation.invalidationLimit) {
result =
result.union(invalidatedResult, typeFlowAnalysis.hierarchyCache);
result = result!
.union(invalidatedResult!, typeFlowAnalysis.hierarchyCache);
}
}
invalidatedResult = null;
@@ -192,11 +192,12 @@ class _DirectInvocation extends _Invocation {
// they could fail bounds checks.
//
// TODO(sjindel): Use [TypeCheck] to avoid bounds checks.
if (selector.member.function != null) {
typeChecksNeeded = selector.member.function.typeParameters
.any((t) => t.isGenericCovariantImpl);
final function = selector.member.function;
if (function != null) {
typeChecksNeeded =
function.typeParameters.any((t) => t.isGenericCovariantImpl);
} else {
Field field = selector.member;
Field field = selector.member as Field;
if (selector.callKind == CallKind.PropertySet) {
// TODO(dartbug.com/40615): Use TFA results to improve this criterion.
typeChecksNeeded = field.isGenericCovariantImpl;
@@ -277,13 +278,10 @@ class _DirectInvocation extends _Invocation {
fieldValue.isInitialized = true;
return const EmptyType();
}
// Make dartanalyzer happy.
throw 'Unexpected call kind ${selector.callKind}';
}
Type _processFunction(TypeFlowAnalysis typeFlowAnalysis) {
final Member member = selector.member;
final Member member = selector.member!;
if (selector.memberAgreesToCallKind(member)) {
if (_argumentsValid()) {
final summary = typeFlowAnalysis.getSummary(member);
@@ -326,13 +324,12 @@ class _DirectInvocation extends _Invocation {
}
bool _argumentsValid() {
final function = selector.member.function;
assert(function != null);
final member = selector.member!;
final function = member.function!;
final int positionalArguments = args.positionalCount;
final int firstParamIndex = numTypeParams(selector.member) +
(hasReceiverArg(selector.member) ? 1 : 0);
final int firstParamIndex =
numTypeParams(member) + (hasReceiverArg(member) ? 1 : 0);
final int requiredParameters =
firstParamIndex + function.requiredParameterCount;
if (positionalArguments < requiredParameters) {
@@ -361,9 +358,9 @@ class _DirectInvocation extends _Invocation {
class _DispatchableInvocation extends _Invocation {
bool _isPolymorphic = false;
Set<Call> _callSites; // Populated only if not polymorphic.
Member _monomorphicTarget;
_DirectInvocation _monomorphicDirectInvocation;
Set<Call>? _callSites; // Populated only if not polymorphic.
Member? _monomorphicTarget;
_DirectInvocation? _monomorphicDirectInvocation;
@override
set typeChecksNeeded(bool value) {
@@ -434,7 +431,8 @@ class _DispatchableInvocation extends _Invocation {
if (!_isPolymorphic) {
assert(target == _monomorphicTarget);
_monomorphicDirectInvocation = directInvocation;
_monomorphicDirectInvocation =
directInvocation as _DirectInvocation;
}
type = typeFlowAnalysis.workList.processInvocation(directInvocation);
@@ -486,13 +484,13 @@ class _DispatchableInvocation extends _Invocation {
final bool isNullableReceiver = receiver is NullableType;
if (isNullableReceiver) {
receiver = (receiver as NullableType).baseType;
receiver = receiver.baseType;
assert(receiver is! NullableType);
}
if (selector is InterfaceSelector) {
final staticReceiverType = new ConeType(typeFlowAnalysis.hierarchyCache
.getTFClass(selector.member.enclosingClass));
.getTFClass(selector.member!.enclosingClass!));
receiver = receiver.intersection(
staticReceiverType, typeFlowAnalysis.hierarchyCache);
assert(receiver is! NullableType);
@@ -507,7 +505,7 @@ class _DispatchableInvocation extends _Invocation {
// invocation to the receiver class. A new allocated class discovered
// in the receiver cone will invalidate this invocation.
receiver = typeFlowAnalysis.hierarchyCache
.specializeTypeCone((receiver as ConeType).cls, allowWideCone: false);
.specializeTypeCone(receiver.cls, allowWideCone: false);
}
assert(targets.isEmpty);
@@ -535,7 +533,7 @@ class _DispatchableInvocation extends _Invocation {
Class nullClass =
typeFlowAnalysis.environment.coreTypes.deprecatedNullClass;
Member target = typeFlowAnalysis.hierarchyCache.hierarchy
Member? target = typeFlowAnalysis.hierarchyCache.hierarchy
.getDispatchTarget(nullClass, selector.name, setter: selector.isSetter);
if (target != null) {
@@ -552,7 +550,7 @@ class _DispatchableInvocation extends _Invocation {
TypeFlowAnalysis typeFlowAnalysis) {
final TFClass cls = receiver.cls;
Member target =
Member? target =
(cls as _TFClassImpl).getDispatchTarget(selector, typeFlowAnalysis);
if (target != null) {
@@ -647,8 +645,9 @@ class _DispatchableInvocation extends _Invocation {
if (_isPolymorphic) {
callSite.setPolymorphic();
} else {
if (_monomorphicTarget != null) {
callSite.addTarget(_monomorphicTarget);
final monomorphicTarget = _monomorphicTarget;
if (monomorphicTarget != null) {
callSite.addTarget(monomorphicTarget);
}
}
@@ -660,18 +659,20 @@ class _DispatchableInvocation extends _Invocation {
/// Notify call sites monitoring this invocation about changes in
/// polymorphism of this invocation.
void _notifyCallSites() {
if (_callSites != null) {
_callSites.forEach(_notifyCallSite);
final callSites = _callSites;
if (callSites != null) {
callSites.forEach(_notifyCallSite);
}
}
@override
Type get resultForRecursiveInvocation {
Type? get resultForRecursiveInvocation {
if (result != null) {
return result;
}
if (_monomorphicDirectInvocation != null) {
return _monomorphicDirectInvocation.resultForRecursiveInvocation;
final monomorphicDirectInvocation = _monomorphicDirectInvocation;
if (monomorphicDirectInvocation != null) {
return monomorphicDirectInvocation.resultForRecursiveInvocation;
}
return null;
}
@@ -683,30 +684,30 @@ class _DispatchableInvocation extends _Invocation {
/// 1) Add 1..N concrete types ordered by classId OR add 1 arbitrary type.
/// 2) Make type nullable.
class _ReceiverTypeBuilder {
Type _type;
List<ConcreteType> _list;
Type? _type;
List<ConcreteType>? _list;
bool _nullable = false;
/// Appends a ConcreteType. May be called multiple times.
/// Should not be used in conjunction with [addType].
void addConcreteType(ConcreteType type) {
if (_list == null) {
if (_type == null) {
final list = _list;
if (list == null) {
final Type? t = _type;
if (t == null) {
_type = type;
return;
}
final ct = t as ConcreteType;
assert(_type is ConcreteType);
assert(_type != type);
_list = <ConcreteType>[];
_list.add(_type);
assert(ct != type);
assert(ct.cls.id < type.cls.id);
_list = <ConcreteType>[ct, type];
_type = null;
} else {
assert(list.last.cls.id < type.cls.id);
list.add(type);
}
assert(_list.last.cls.id < type.cls.id);
_list.add(type);
}
/// Appends an arbitrary Type. May be called only once.
@@ -723,12 +724,13 @@ class _ReceiverTypeBuilder {
/// Returns union of added types.
Type toType() {
Type t = _type;
Type? t = _type;
if (t == null) {
if (_list == null) {
final list = _list;
if (list == null) {
t = const EmptyType();
} else {
t = new SetType(_list);
t = SetType(list);
}
} else {
assert(_list == null);
@@ -753,7 +755,7 @@ class _SelectorApproximation {
static const int maxInvocationsPerSelector = 5000;
int count = 0;
_Invocation approximation;
_Invocation? approximation;
}
/// Maintains ([Selector], [Args]) => [_Invocation] cache.
@@ -771,7 +773,7 @@ class _InvocationsCache {
_Invocation invocation = (selector is DirectSelector)
? new _DirectInvocation(selector, args)
: new _DispatchableInvocation(selector, args);
_Invocation result = _invocations.lookup(invocation);
_Invocation? result = _invocations.lookup(invocation);
if (result != null) {
return result;
}
@@ -784,14 +786,16 @@ class _InvocationsCache {
final sa = (_approximations[selector] ??= new _SelectorApproximation());
if (sa.count >= _SelectorApproximation.maxInvocationsPerSelector) {
if (sa.approximation == null) {
_Invocation? approximation = sa.approximation;
if (approximation == null) {
final rawArgs =
_typeFlowAnalysis.summaryCollector.rawArguments(selector);
sa.approximation = new _DispatchableInvocation(selector, rawArgs);
sa.approximation =
approximation = _DispatchableInvocation(selector, rawArgs);
Statistics.approximateInvocationsCreated++;
}
Statistics.approximateInvocationsUsed++;
return sa.approximation;
return approximation;
}
++sa.count;
@@ -809,8 +813,8 @@ class _InvocationsCache {
class _FieldValue extends _DependencyTracker {
final Field field;
final Type staticType;
final Summary typeGuardSummary;
Type value;
final Summary? typeGuardSummary;
Type value = const EmptyType();
/// Flag indicating if field initializer was executed.
bool isInitialized = false;
@@ -825,8 +829,6 @@ class _FieldValue extends _DependencyTracker {
: staticType = typesBuilder.fromStaticType(field.type, true) {
if (field.initializer == null && _isDefaultValueOfFieldObservable()) {
value = new Type.nullable(const EmptyType());
} else {
value = const EmptyType();
}
}
@@ -839,8 +841,7 @@ class _FieldValue extends _DependencyTracker {
return true;
}
final enclosingClass = field.enclosingClass;
assert(enclosingClass != null);
final enclosingClass = field.enclosingClass!;
// Default value is not observable if every generative constructor
// is redirecting or initializes the field.
@@ -856,10 +857,11 @@ class _FieldValue extends _DependencyTracker {
});
}
void ensureInitialized(TypeFlowAnalysis typeFlowAnalysis, Type receiverType) {
void ensureInitialized(
TypeFlowAnalysis typeFlowAnalysis, Type? receiverType) {
if (field.initializer != null) {
assert(field.isStatic == (receiverType == null));
final args = !field.isStatic ? <Type>[receiverType] : const <Type>[];
final args = !field.isStatic ? <Type>[receiverType!] : const <Type>[];
final initializerInvocation = typeFlowAnalysis._invocationsCache
.getInvocation(
new DirectSelector(field, callKind: CallKind.FieldInitializer),
@@ -870,17 +872,18 @@ class _FieldValue extends _DependencyTracker {
}
}
Type getValue(TypeFlowAnalysis typeFlowAnalysis, Type receiverType) {
Type getValue(TypeFlowAnalysis typeFlowAnalysis, Type? receiverType) {
ensureInitialized(typeFlowAnalysis, receiverType);
addDependentInvocation(typeFlowAnalysis.currentInvocation);
final typeGuardSummary = this.typeGuardSummary;
return (typeGuardSummary != null)
? typeGuardSummary.apply(Args([receiverType, value]),
? typeGuardSummary.apply(Args([receiverType!, value]),
typeFlowAnalysis.hierarchyCache, typeFlowAnalysis)
: value;
}
void setValue(
Type newValue, TypeFlowAnalysis typeFlowAnalysis, Type receiverType) {
Type newValue, TypeFlowAnalysis typeFlowAnalysis, Type? receiverType) {
// Make sure type cones are specialized before putting them into field
// value, in order to ensure that dependency is established between
// cone's base type and corresponding field setter.
@@ -907,10 +910,11 @@ class _FieldValue extends _DependencyTracker {
//
final hierarchy = typeFlowAnalysis.hierarchyCache;
// TODO(sjindel/tfa): Perform narrowing inside 'TypeCheck'.
final typeGuardSummary = this.typeGuardSummary;
final narrowedNewValue = typeGuardSummary != null
? typeGuardSummary
.apply(
new Args([receiverType, newValue]), hierarchy, typeFlowAnalysis)
.apply(new Args([receiverType!, newValue]), hierarchy,
typeFlowAnalysis)
.intersection(staticType, hierarchy)
: newValue.specialize(hierarchy).intersection(staticType, hierarchy);
Type newType =
@@ -952,28 +956,26 @@ class _TFClassImpl extends TFClass {
/// Flag indicating if this class has a noSuchMethod() method not inherited
/// from Object.
/// Lazy initialized by ClassHierarchyCache.hasNonTrivialNoSuchMethod().
bool hasNonTrivialNoSuchMethod;
bool? hasNonTrivialNoSuchMethod;
_TFClassImpl(int id, Class classNode, this.supertypes)
: super(id, classNode) {
supertypes.add(this);
}
ConcreteType _concreteType;
ConcreteType get concreteType =>
_concreteType ??= new ConcreteType(this, null);
late final ConcreteType concreteType = ConcreteType(this, null);
Type _specializedConeType;
Type? _specializedConeType;
Type get specializedConeType =>
_specializedConeType ??= _calculateConeTypeSpecialization();
bool get hasWideCone =>
_allocatedSubtypes.length > maxAllocatedTypesInSetSpecializations;
WideConeType _wideConeType;
late final WideConeType _wideConeType = WideConeType(this);
WideConeType get wideConeType {
assert(hasWideCone);
return _wideConeType ??= new WideConeType(this);
return _wideConeType;
}
Type _calculateConeTypeSpecialization() {
@@ -999,14 +1001,16 @@ class _TFClassImpl extends TFClass {
_specializedConeType = null; // Reset cached specialization.
}
Member getDispatchTarget(
Member? getDispatchTarget(
Selector selector, TypeFlowAnalysis typeFlowAnalysis) {
Member target = _dispatchTargets[selector];
Member? target = _dispatchTargets[selector];
if (target == null) {
target = typeFlowAnalysis.hierarchyCache.hierarchy.getDispatchTarget(
classNode, selector.name,
setter: selector.isSetter);
_dispatchTargets[selector] = target;
if (target != null) {
_dispatchTargets[selector] = target;
}
}
return target;
}
@@ -1021,10 +1025,11 @@ class GenericInterfacesInfoImpl implements GenericInterfacesInfo {
final cachedFlattenedTypeArgs = <Class, List<DartType>>{};
final cachedFlattenedTypeArgsForNonGeneric = <Class, List<Type>>{};
RuntimeTypeTranslatorImpl closedTypeTranslator;
late final RuntimeTypeTranslatorImpl closedTypeTranslator;
GenericInterfacesInfoImpl(this.hierarchy) {
closedTypeTranslator = RuntimeTypeTranslatorImpl.forClosedTypes(this);
GenericInterfacesInfoImpl(CoreTypes coreTypes, this.hierarchy) {
closedTypeTranslator =
RuntimeTypeTranslatorImpl.forClosedTypes(coreTypes, this);
}
List<DartType> flattenedTypeArgumentsFor(Class klass, {bool useCache: true}) {
@@ -1049,7 +1054,7 @@ class GenericInterfacesInfoImpl implements GenericInterfacesInfo {
if (klass == iface) return 0;
final pair = new SubtypePair(klass, iface);
int offset = supertypeOffsetsCache[pair];
int? offset = supertypeOffsetsCache[pair];
if (offset != null) return offset;
@@ -1064,16 +1069,16 @@ class GenericInterfacesInfoImpl implements GenericInterfacesInfo {
}
List<Type> flattenedTypeArgumentsForNonGeneric(Class klass) {
List<Type> result = cachedFlattenedTypeArgsForNonGeneric[klass];
List<Type>? result = cachedFlattenedTypeArgsForNonGeneric[klass];
if (result != null) return result;
List<DartType> flattenedTypeArgs =
flattenedTypeArgumentsFor(klass, useCache: false);
result = new List<Type>.filled(flattenedTypeArgs.length, null);
for (int i = 0; i < flattenedTypeArgs.length; ++i) {
final translated = closedTypeTranslator.translate(flattenedTypeArgs[i]);
result = <Type>[];
for (DartType arg in flattenedTypeArgs) {
final translated = closedTypeTranslator.translate(arg);
assert(translated is RuntimeType || translated is UnknownType);
result[i] = translated;
result.add(translated as Type);
}
cachedFlattenedTypeArgsForNonGeneric[klass] = result;
return result;
@@ -1108,10 +1113,8 @@ class _ClassHierarchyCache extends TypeHierarchy {
_ClassHierarchyCache(this._typeFlowAnalysis, this.hierarchy,
this.genericInterfacesInfo, this.environment, bool nullSafety)
: objectNoSuchMethod = hierarchy.getDispatchTarget(
environment.coreTypes.objectClass, noSuchMethodName),
super(environment.coreTypes, nullSafety) {
assert(objectNoSuchMethod != null);
}
environment.coreTypes.objectClass, noSuchMethodName)!,
super(environment.coreTypes, nullSafety);
@override
_TFClassImpl getTFClass(Class c) {
@@ -1198,10 +1201,13 @@ class _ClassHierarchyCache extends TypeHierarchy {
bool hasNonTrivialNoSuchMethod(TFClass c) {
final classImpl = c as _TFClassImpl;
classImpl.hasNonTrivialNoSuchMethod ??=
(hierarchy.getDispatchTarget(c.classNode, noSuchMethodName) !=
objectNoSuchMethod);
return classImpl.hasNonTrivialNoSuchMethod;
bool? value = classImpl.hasNonTrivialNoSuchMethod;
if (value == null) {
classImpl.hasNonTrivialNoSuchMethod = value =
(hierarchy.getDispatchTarget(c.classNode, noSuchMethodName) !=
objectNoSuchMethod);
}
return value;
}
_DynamicTargetSet getDynamicTargetSet(DynamicSelector selector) {
@@ -1294,10 +1300,11 @@ class _WorkList {
}
bool invalidateProtobufFields() {
if (_typeFlowAnalysis.protobufHandler == null) {
final protobufHandler = _typeFlowAnalysis.protobufHandler;
if (protobufHandler == null) {
return false;
}
final fields = _typeFlowAnalysis.protobufHandler.getInvalidatedFields();
final fields = protobufHandler.getInvalidatedFields();
if (fields.isEmpty) {
return false;
}
@@ -1305,7 +1312,7 @@ class _WorkList {
for (var field in fields) {
assert(field.isStatic);
// Reset summary in order to rebuild it.
_typeFlowAnalysis._summaries[field] = null;
_typeFlowAnalysis._summaries.remove(field);
// Invalidate (and enqueue) field initializer invocation.
final initializerInvocation = _typeFlowAnalysis._invocationsCache
.getInvocation(
@@ -1328,10 +1335,11 @@ class _WorkList {
}
Type processInvocation(_Invocation invocation) {
if (invocation.result != null) {
Type? result = invocation.result;
if (result != null) {
// Already processed.
Statistics.usedCachedResultsOfInvocations++;
return invocation.result;
return result;
}
// Test if tracing is enabled to avoid expensive message formatting.
@@ -1374,18 +1382,18 @@ class _WorkList {
-1);
}
processing.remove(invocation);
return invocation.invalidatedResult;
return invocation.invalidatedResult!;
}
callStack.add(invocation);
pending.remove(invocation);
Type result = invocation.process(_typeFlowAnalysis);
result = invocation.process(_typeFlowAnalysis);
invocation.setResult(_typeFlowAnalysis, result);
// setResult may saturate result to ensure convergence.
result = invocation.result;
result = invocation.result!;
// Invocation is still pending - it was invalidated while being processed.
// Move result to invalidatedResult.
@@ -1434,12 +1442,12 @@ class TypeFlowAnalysis implements EntryPointsListener, CallHandler {
final TypeEnvironment environment;
final LibraryIndex libraryIndex;
final PragmaAnnotationParser annotationMatcher;
final ProtobufHandler protobufHandler;
NativeCodeOracle nativeCodeOracle;
_ClassHierarchyCache hierarchyCache;
SummaryCollector summaryCollector;
_InvocationsCache _invocationsCache;
_WorkList workList;
final ProtobufHandler? protobufHandler;
late NativeCodeOracle nativeCodeOracle;
late _ClassHierarchyCache hierarchyCache;
late SummaryCollector summaryCollector;
late _InvocationsCache _invocationsCache;
late _WorkList workList;
GenericInterfacesInfo _genericInterfacesInfo;
final Map<Member, Summary> _summaries = <Member, Summary>{};
@@ -1459,7 +1467,7 @@ class TypeFlowAnalysis implements EntryPointsListener, CallHandler {
this.environment,
this.libraryIndex,
this.protobufHandler,
PragmaAnnotationParser matcher)
PragmaAnnotationParser? matcher)
: annotationMatcher =
matcher ?? new ConstantPragmaAnnotationParser(coreTypes) {
nativeCodeOracle = new NativeCodeOracle(libraryIndex, annotationMatcher);
@@ -1488,9 +1496,9 @@ class TypeFlowAnalysis implements EntryPointsListener, CallHandler {
}
_FieldValue getFieldValue(Field field) {
_FieldValue fieldValue = _fieldValues[field];
_FieldValue? fieldValue = _fieldValues[field];
if (fieldValue == null) {
Summary typeGuardSummary = null;
Summary? typeGuardSummary = null;
if (field.isGenericCovariantImpl) {
typeGuardSummary = summaryCollector.createSummary(field,
fieldSummaryType: FieldSummaryType.kFieldGuard);
@@ -1548,24 +1556,24 @@ class TypeFlowAnalysis implements EntryPointsListener, CallHandler {
bool isClassAllocated(Class c) => hierarchyCache.allocatedClasses.contains(c);
Call callSite(TreeNode node) => summaryCollector.callSites[node];
Call? callSite(TreeNode node) => summaryCollector.callSites[node];
TypeCheck explicitCast(AsExpression cast) =>
TypeCheck? explicitCast(AsExpression cast) =>
summaryCollector.explicitCasts[cast];
TypeCheck isTest(IsExpression node) => summaryCollector.isTests[node];
TypeCheck? isTest(IsExpression node) => summaryCollector.isTests[node];
NarrowNotNull nullTest(TreeNode node) => summaryCollector.nullTests[node];
NarrowNotNull? nullTest(TreeNode node) => summaryCollector.nullTests[node];
Type fieldType(Field field) => _fieldValues[field]?.value;
Type? fieldType(Field field) => _fieldValues[field]?.value;
Args<Type> argumentTypes(Member member) => _summaries[member]?.argumentTypes;
Args<Type>? argumentTypes(Member member) => _summaries[member]?.argumentTypes;
Type argumentType(Member member, VariableDeclaration memberParam) {
Type? argumentType(Member member, VariableDeclaration memberParam) {
return _summaries[member]?.argumentType(member, memberParam);
}
List<VariableDeclaration> uncheckedParameters(Member member) =>
List<VariableDeclaration>? uncheckedParameters(Member member) =>
_summaries[member]?.uncheckedParameters;
bool isTearOffTaken(Member member) => _tearOffTaken.contains(member);
@@ -1599,7 +1607,7 @@ class TypeFlowAnalysis implements EntryPointsListener, CallHandler {
/// ---- Implementation of [CallHandler] interface. ----
@override
Type applyCall(Call callSite, Selector selector, Args<Type> args,
Type applyCall(Call? callSite, Selector selector, Args<Type> args,
{bool isResultUsed: true, bool processImmediately: true}) {
_Invocation invocation = _invocationsCache.getInvocation(selector, args);
@@ -1629,7 +1637,7 @@ class TypeFlowAnalysis implements EntryPointsListener, CallHandler {
workList.enqueueInvocation(invocation);
}
return null;
return const EmptyType();
}
}
@@ -1680,7 +1688,7 @@ class TypeFlowAnalysis implements EntryPointsListener, CallHandler {
}
@override
void recordTearOff(Procedure target) {
void recordTearOff(Member target) {
_tearOffTaken.add(target);
}
}
@@ -2,10 +2,7 @@
// 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.
// @dart=2.9
/// Declares classes which describe a call: selectors and arguments.
library vm.transformations.type_flow.calls;
import 'dart:core' hide Type;
@@ -30,10 +27,10 @@ abstract class Selector {
Selector(this.callKind);
/// Interface or concrete target, may be null.
Member get member;
Member? get member;
/// Selector name.
Name get name => member.name;
Name get name => member!.name;
bool get isSetter => (callKind == CallKind.PropertySet);
@@ -46,6 +43,7 @@ abstract class Selector {
/// Static approximation of Dart return type.
DartType get staticReturnType {
final member = this.member;
if (member == null) {
return const DynamicType();
}
@@ -61,7 +59,6 @@ abstract class Selector {
case CallKind.SetFieldInConstructor:
return const NeverType.nonNullable();
}
return null;
}
bool memberAgreesToCallKind(Member member) {
@@ -79,7 +76,6 @@ abstract class Selector {
case CallKind.SetFieldInConstructor:
return member is Field;
}
return false;
}
String get _callKindPrefix {
@@ -94,7 +90,6 @@ abstract class Selector {
case CallKind.FieldInitializer:
return 'init ';
}
return '';
}
}
@@ -169,7 +164,7 @@ class DynamicSelector extends Selector {
DynamicSelector(CallKind callKind, this.name) : super(callKind);
@override
Member get member => null;
Member? get member => null;
@override
int get hashCode => (super.hashCode ^ name.hashCode + 37) & kHashMask;
@@ -189,7 +184,8 @@ class Args<T extends TypeExpr> {
final List<T> values;
final List<String> names;
int _hashCode;
@override
late final int hashCode = _computeHashCode();
Args(this.values, {this.names = const <String>[]}) {
assert(isSorted(names));
@@ -206,9 +202,6 @@ class Args<T extends TypeExpr> {
T get receiver => values[0];
@override
int get hashCode => _hashCode ??= _computeHashCode();
int _computeHashCode() {
int hash = 1231;
for (var v in values) {
@@ -2,10 +2,7 @@
// 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.
// @dart=2.9
/// Handling of native code and entry points.
library vm.transformations.type_flow.native_code;
import 'dart:core' hide Type;
@@ -35,24 +32,21 @@ abstract class EntryPointsListener {
/// Record the fact that given member is called from this.
void recordMemberCalledViaThis(Member target);
/// Record the fact that given method is torn off.
void recordTearOff(Procedure target) {}
/// Record the fact that given member is torn off.
void recordTearOff(Member target) {}
}
class PragmaEntryPointsVisitor extends RecursiveVisitor {
final EntryPointsListener entryPoints;
final NativeCodeOracle nativeCodeOracle;
final PragmaAnnotationParser matcher;
Class currentClass = null;
PragmaEntryPointsVisitor(
this.entryPoints, this.nativeCodeOracle, this.matcher) {
assert(matcher != null);
}
this.entryPoints, this.nativeCodeOracle, this.matcher);
PragmaEntryPointType _annotationsDefineRoot(List<Expression> annotations) {
PragmaEntryPointType? _annotationsDefineRoot(List<Expression> annotations) {
for (var annotation in annotations) {
ParsedPragma pragma = matcher.parsePragma(annotation);
ParsedPragma? pragma = matcher.parsePragma(annotation);
if (pragma == null) continue;
if (pragma is ParsedEntryPointPragma) return pragma.type;
}
@@ -72,7 +66,6 @@ class PragmaEntryPointsVisitor extends RecursiveVisitor {
}
nativeCodeOracle.addClassReferencedFromNativeCode(klass);
}
currentClass = klass;
klass.visitChildren(this);
}
@@ -88,8 +81,7 @@ class PragmaEntryPointsVisitor extends RecursiveVisitor {
}
Member target = proc;
while (target is Procedure && target.isRedirectingFactory) {
target = getRedirectingFactoryBody(target).target;
assert(target != null);
target = getRedirectingFactoryBody(target)!.target!;
assert(
(target is Procedure && target.isFactory) || target is Constructor);
}
@@ -152,7 +144,7 @@ class PragmaEntryPointsVisitor extends RecursiveVisitor {
}
entryPoints
.addRawCall(new DirectSelector(ctor, callKind: CallKind.Method));
entryPoints.addAllocatedClass(currentClass);
entryPoints.addAllocatedClass(ctor.enclosingClass);
nativeCodeOracle.setMemberReferencedFromNativeCode(ctor);
}
}
@@ -201,9 +193,7 @@ class NativeCodeOracle {
final Set<Class> _classesReferencedFromNativeCode = new Set<Class>();
final PragmaAnnotationParser _matcher;
NativeCodeOracle(this._libraryIndex, this._matcher) {
assert(_matcher != null);
}
NativeCodeOracle(this._libraryIndex, this._matcher);
void addClassReferencedFromNativeCode(Class klass) {
_classesReferencedFromNativeCode.add(klass);
@@ -219,9 +209,9 @@ class NativeCodeOracle {
bool isMemberReferencedFromNativeCode(Member member) =>
_membersReferencedFromNativeCode.contains(member);
PragmaRecognizedType recognizedType(Member member) {
PragmaRecognizedType? recognizedType(Member member) {
for (var annotation in member.annotations) {
ParsedPragma pragma = _matcher.parsePragma(annotation);
ParsedPragma? pragma = _matcher.parsePragma(annotation);
if (pragma is ParsedRecognized) {
return pragma.type;
}
@@ -229,15 +219,16 @@ class NativeCodeOracle {
return null;
}
bool isRecognized(Member member, [List<PragmaRecognizedType> expectedTypes]) {
PragmaRecognizedType type = recognizedType(member);
bool isRecognized(Member member,
[List<PragmaRecognizedType>? expectedTypes]) {
PragmaRecognizedType? type = recognizedType(member);
return type != null &&
(expectedTypes == null || expectedTypes.contains(type));
}
bool hasDisableUnboxedParameters(Member member) {
for (var annotation in member.annotations) {
ParsedPragma pragma = _matcher.parsePragma(annotation);
ParsedPragma? pragma = _matcher.parsePragma(annotation);
if (pragma is ParsedDisableUnboxedParameters) {
if (member.enclosingLibrary.importUri.scheme != "dart") {
throw "ERROR: Cannot use @pragma(vm:disable-unboxed-parameters) outside core libraries.";
@@ -255,11 +246,11 @@ class NativeCodeOracle {
EntryPointsListener entryPointsListener,
TypesBuilder typesBuilder,
RuntimeTypeTranslator translator) {
TypeExpr returnType = null;
bool nullable = null;
TypeExpr? returnType = null;
bool? nullable = null;
for (var annotation in member.annotations) {
ParsedPragma pragma = _matcher.parsePragma(annotation);
ParsedPragma? pragma = _matcher.parsePragma(annotation);
if (pragma == null) continue;
if (pragma is ParsedResultTypeByTypePragma ||
pragma is ParsedResultTypeByPathPragma ||
@@ -278,8 +269,8 @@ class NativeCodeOracle {
returnType = entryPointsListener.addAllocatedClass(type.classNode);
if (pragma.resultTypeUsesPassedTypeArguments) {
returnType = translator.instantiateConcreteType(
returnType,
member.function.typeParameters
returnType as ConcreteType,
member.function!.typeParameters
.map((t) => TypeParameterType(
t, TypeParameterType.computeNullabilityFromBound(t)))
.toList());
@@ -314,7 +305,7 @@ class NativeCodeOracle {
return returnType;
} else {
return typesBuilder.fromStaticType(
member.function.returnType, nullable ?? true);
member.function!.returnType, nullable ?? true);
}
}
}
@@ -2,8 +2,6 @@
// 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.
// @dart=2.9
import 'package:kernel/ast.dart';
import 'package:kernel/clone.dart' show CloneVisitorNotMembers;
import 'package:kernel/core_types.dart' show CoreTypes;
@@ -47,14 +45,14 @@ class ProtobufHandler {
final Procedure _builderInfoAddMethod;
// Type of BuilderInfo.add<Null>().
FunctionType _typeOfBuilderInfoAddOfNull;
late FunctionType _typeOfBuilderInfoAddOfNull;
final _messageClasses = <Class, _MessageClass>{};
final _invalidatedClasses = <_MessageClass>{};
/// Creates [ProtobufHandler] instance for [component].
/// Returns null if protobuf library is not used.
static ProtobufHandler forComponent(
static ProtobufHandler? forComponent(
Component component, CoreTypes coreTypes) {
final libraryIndex = LibraryIndex(component, [protobufLibraryUri]);
if (!libraryIndex.containsLibrary(protobufLibraryUri)) {
@@ -68,12 +66,12 @@ class ProtobufHandler {
libraryIndex.getClass(protobufLibraryUri, 'GeneratedMessage'),
_tagNumberClass =
libraryIndex.getClass(protobufLibraryUri, 'TagNumber'),
_tagNumberField = libraryIndex.getMember(
protobufLibraryUri, 'TagNumber', 'tagNumber'),
_tagNumberField =
libraryIndex.getField(protobufLibraryUri, 'TagNumber', 'tagNumber'),
_builderInfoClass =
libraryIndex.getClass(protobufLibraryUri, 'BuilderInfo'),
_builderInfoAddMethod =
libraryIndex.getMember(protobufLibraryUri, 'BuilderInfo', 'add') {
_builderInfoAddMethod = libraryIndex.getProcedure(
protobufLibraryUri, 'BuilderInfo', 'add') {
final functionType = _builderInfoAddMethod.getterType as FunctionType;
_typeOfBuilderInfoAddOfNull = Substitution.fromPairs(
functionType.typeParameters, const <DartType>[NullType()])
@@ -130,8 +128,9 @@ class ProtobufHandler {
List<Field> getInvalidatedFields() {
final fields = <Field>[];
for (var cls in _invalidatedClasses) {
if (cls._metadataField != null) {
fields.add(cls._metadataField);
final field = cls._metadataField;
if (field != null) {
fields.add(field);
}
}
_invalidatedClasses.clear();
@@ -143,14 +142,15 @@ class ProtobufHandler {
++Statistics.protobufMetadataInitializersUpdated;
Statistics.protobufMetadataFieldsPruned -= cls.numberOfFieldsPruned;
final field = cls._metadataField;
if (cls._originalInitializer == null) {
cls._originalInitializer = field.initializer;
final field = cls._metadataField!;
Expression? originalInitializer = cls._originalInitializer;
if (originalInitializer == null) {
cls._originalInitializer = originalInitializer = field.initializer!;
}
final cloner = CloneVisitorNotMembers();
field.initializer = cloner.clone(cls._originalInitializer)..parent = field;
field.initializer = cloner.clone(originalInitializer)..parent = field;
final transformer = _MetadataTransformer(this, cls);
field.initializer.accept(transformer);
field.initializer!.accept(transformer);
_invalidatedClasses.remove(cls);
cls.numberOfFieldsPruned = transformer.numberOfFieldsPruned;
@@ -168,8 +168,8 @@ class ProtobufHandler {
}
class _MessageClass {
Field _metadataField;
Expression _originalInitializer;
Field? _metadataField;
Expression? _originalInitializer;
final _usedTags = <int>{};
int numberOfFieldsPruned = 0;
}
@@ -2,8 +2,6 @@
// 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.
// @dart=2.9
import 'package:kernel/ast.dart';
import 'package:kernel/external_name.dart';
import 'package:kernel/type_environment.dart';
@@ -57,7 +55,7 @@ class SignatureShaker {
SignatureShaker(this.typeFlowAnalysis, this.tableSelectorAssigner);
_ProcedureInfo _infoForMember(Member member) {
_ProcedureInfo? _infoForMember(Member member) {
if (!(member is Procedure &&
(member.kind == ProcedureKind.Method ||
member.kind == ProcedureKind.Factory) ||
@@ -89,7 +87,7 @@ class SignatureShaker {
}
while (worklist.isNotEmpty) {
_ParameterInfo param = worklist.removeLast();
for (_ParameterInfo dependencyParam in param.useDependencies) {
for (_ParameterInfo dependencyParam in param.useDependencies!) {
if (!dependencyParam.isRead) {
dependencyParam.isRead = true;
if (dependencyParam.useDependencies != null) {
@@ -141,7 +139,7 @@ class _ProcedureInfo {
return positional.any((param) =>
param.canBeEliminated ||
(param.isAlwaysPassed &&
param.index >= function.requiredParameterCount)) ||
param.index! >= function.requiredParameterCount)) ||
named.values
.any((param) => param.canBeEliminated || param.isAlwaysPassed);
}
@@ -149,7 +147,7 @@ class _ProcedureInfo {
class _ParameterInfo {
final _ProcedureInfo info;
final int index;
final int? index;
int passCount = 0;
bool isRead = false;
@@ -160,7 +158,7 @@ class _ParameterInfo {
/// List of parameter variables which were passed as arguments via this
/// parameter. When this parameter is considered used, all [useDependencies]
/// parameters should be transitively marked as read.
List<_ParameterInfo> useDependencies = null;
List<_ParameterInfo>? useDependencies = null;
_ParameterInfo(this.info, this.index);
@@ -177,7 +175,7 @@ class _ParameterInfo {
void observeParameter(
Member member, VariableDeclaration param, SignatureShaker shaker) {
final Type type = shaker.typeFlowAnalysis.argumentType(member, param);
final Type? type = shaker.typeFlowAnalysis.argumentType(member, param);
// A parameter is considered constant if the TFA has inferred it to have a
// constant value in every implementation. The constant value inferred does
@@ -214,19 +212,19 @@ class _Collect extends RecursiveVisitor {
_Collect(this.shaker);
void enterFunction(Member member) {
final _ProcedureInfo info = shaker._infoForMember(member);
final _ProcedureInfo? info = shaker._infoForMember(member);
if (info == null) return;
localParameters.clear();
useDependencies.clear();
final FunctionNode fun = member.function;
final FunctionNode fun = member.function!;
for (int i = 0; i < fun.positionalParameters.length; i++) {
final VariableDeclaration param = fun.positionalParameters[i];
localParameters[param] = info.ensurePositional(i)
..observeParameter(member, param, shaker);
}
for (VariableDeclaration param in fun.namedParameters) {
localParameters[param] = info.ensureNamed(param.name)
localParameters[param] = info.ensureNamed(param.name!)
..observeParameter(member, param, shaker);
}
@@ -270,19 +268,22 @@ class _Collect extends RecursiveVisitor {
void addUseDependency(Expression arg, _ParameterInfo param) {
if (arg is VariableGet) {
_ParameterInfo localParam = localParameters[arg.variable];
_ParameterInfo? localParam = localParameters[arg.variable];
if (localParam != null && !localParam.isUsed) {
// This is a parameter passed as an argument. Mark it as a use
// dependency.
param.useDependencies ??= [];
param.useDependencies.add(localParam);
var paramUseDependencies = param.useDependencies;
if (paramUseDependencies == null) {
param.useDependencies = paramUseDependencies = [];
}
paramUseDependencies.add(localParam);
useDependencies.add(arg);
}
}
}
void collectCall(Member member, Arguments args) {
final _ProcedureInfo info = shaker._infoForMember(member);
final _ProcedureInfo? info = shaker._infoForMember(member);
if (info == null) return;
for (int i = 0; i < args.positional.length; i++) {
@@ -306,7 +307,10 @@ class _Collect extends RecursiveVisitor {
@override
void visitSuperMethodInvocation(SuperMethodInvocation node) {
collectCall(node.interfaceTarget, node.arguments);
final interfaceTarget = node.interfaceTarget;
if (interfaceTarget != null) {
collectCall(interfaceTarget, node.arguments);
}
super.visitSuperMethodInvocation(node);
}
@@ -338,7 +342,7 @@ class _Collect extends RecursiveVisitor {
class _Transform extends RecursiveVisitor {
final SignatureShaker shaker;
StaticTypeContext typeContext;
late StaticTypeContext typeContext;
final Map<VariableDeclaration, Constant> eliminatedParams = {};
final Set<VariableDeclaration> unusedParams = {};
final List<LocalInitializer> addedInitializers = [];
@@ -349,16 +353,15 @@ class _Transform extends RecursiveVisitor {
Member member, _ParameterInfo param, VariableDeclaration variable) {
Constant value;
if (param.isConstant) {
Type type = shaker.typeFlowAnalysis.argumentType(member, variable);
Type type = shaker.typeFlowAnalysis.argumentType(member, variable)!;
if (type is ConcreteType) {
assert(type.constant != null);
value = type.constant;
value = type.constant!;
} else {
assert(type is NullableType && type.baseType is EmptyType);
value = NullConstant();
}
} else {
value = (variable.initializer as ConstantExpression)?.constant ??
value = (variable.initializer as ConstantExpression?)?.constant ??
NullConstant();
}
eliminatedParams[variable] = value;
@@ -370,10 +373,10 @@ class _Transform extends RecursiveVisitor {
eliminatedParams.clear();
unusedParams.clear();
final _ProcedureInfo info = shaker._infoForMember(member);
final _ProcedureInfo? info = shaker._infoForMember(member);
if (info == null || !info.eligible || info.callCount == 0) return;
final FunctionNode function = member.function;
final FunctionNode function = member.function!;
if (!info.transformNeeded(function)) return;
@@ -404,9 +407,9 @@ class _Transform extends RecursiveVisitor {
// as required positional parameters, alphabetically by name.
final List<VariableDeclaration> sortedNamed = function.namedParameters
.toList()
..sort((var1, var2) => var1.name.compareTo(var2.name));
..sort((var1, var2) => var1.name!.compareTo(var2.name!));
for (VariableDeclaration variable in sortedNamed) {
final _ParameterInfo param = info.named[variable.name];
final _ParameterInfo param = info.named[variable.name!]!;
if (param.isAlwaysPassed) {
if (param.isUsed) {
if (param.canBeEliminated) {
@@ -451,7 +454,7 @@ class _Transform extends RecursiveVisitor {
// 4. All named parameters that are not always passed and can't be
// eliminated, as named parameters in alphabetical order.
for (VariableDeclaration variable in sortedNamed) {
final _ParameterInfo param = info.named[variable.name];
final _ParameterInfo param = info.named[variable.name!]!;
if (!param.isAlwaysPassed) {
if (param.isUsed) {
if (param.canBeEliminated) {
@@ -475,7 +478,7 @@ class _Transform extends RecursiveVisitor {
@override
void visitVariableGet(VariableGet node) {
Constant constantValue = eliminatedParams[node.variable];
Constant? constantValue = eliminatedParams[node.variable];
if (constantValue != null) {
node.replaceWith(ConstantExpression(constantValue));
}
@@ -511,7 +514,7 @@ class _Transform extends RecursiveVisitor {
void Function(Expression, _ParameterInfo) fun) {
for (int i = args.named.length - 1; i >= 0; i--) {
final NamedExpression namedExp = args.named[i];
fun(namedExp.value, info.named[namedExp.name]);
fun(namedExp.value, info.named[namedExp.name]!);
}
for (int i = args.positional.length - 1; i >= 0; i--) {
fun(args.positional[i], info.positional[i]);
@@ -519,8 +522,8 @@ class _Transform extends RecursiveVisitor {
}
void transformCall(
Member target, TreeNode call, Expression receiver, Arguments args) {
final _ProcedureInfo info = shaker._infoForMember(target);
Member target, TreeNode call, Expression? receiver, Arguments args) {
final _ProcedureInfo? info = shaker._infoForMember(target);
if (info == null || !info.eligible) return;
bool transformNeeded = false;
@@ -544,7 +547,7 @@ class _Transform extends RecursiveVisitor {
Map<Expression, VariableDeclaration> hoisted = {};
if (hoistingNeeded) {
if (call is Initializer) {
final Constructor constructor = call.parent;
final Constructor constructor = call.parent as Constructor;
forEachArgumentRev(args, info, (Expression arg, _ParameterInfo param) {
if (mayHaveOrSeeSideEffects(arg) && !isUnusedParam(arg)) {
VariableDeclaration argVar = VariableDeclaration(null,
@@ -557,8 +560,8 @@ class _Transform extends RecursiveVisitor {
}
});
} else {
final TreeNode parent = call.parent;
Expression current = call;
final TreeNode parent = call.parent!;
Expression current = call as Expression;
forEachArgumentRev(args, info, (Expression arg, _ParameterInfo param) {
if (mayHaveOrSeeSideEffects(arg) && !isUnusedParam(arg)) {
VariableDeclaration argVar = VariableDeclaration(null,
@@ -606,7 +609,7 @@ class _Transform extends RecursiveVisitor {
final List<NamedExpression> sortedNamed = args.named.toList()
..sort((var1, var2) => var1.name.compareTo(var2.name));
for (NamedExpression arg in sortedNamed) {
final _ParameterInfo param = info.named[arg.name];
final _ParameterInfo param = info.named[arg.name]!;
if (param.isAlwaysPassed && !param.canBeEliminated) {
positional.add(getMaybeHoistedArg(arg.value));
}
@@ -625,7 +628,7 @@ class _Transform extends RecursiveVisitor {
// eliminated, as named parameters in alphabetical order.
// (Arguments are kept in original order.)
for (NamedExpression arg in args.named) {
final _ParameterInfo param = info.named[arg.name];
final _ParameterInfo param = info.named[arg.name]!;
if (!param.isAlwaysPassed && !param.canBeEliminated) {
arg.value = getMaybeHoistedArg(arg.value)..parent = arg;
named.add(arg);
@@ -644,7 +647,10 @@ class _Transform extends RecursiveVisitor {
@override
void visitSuperMethodInvocation(SuperMethodInvocation node) {
super.visitSuperMethodInvocation(node);
transformCall(node.interfaceTarget, node, null, node.arguments);
final interfaceTarget = node.interfaceTarget;
if (interfaceTarget != null) {
transformCall(interfaceTarget, node, null, node.arguments);
}
}
@override
@@ -2,10 +2,7 @@
// 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.
// @dart=2.9
/// Type flow summary of a member, function or initializer.
library vm.transformations.type_flow.summary;
import 'dart:core' hide Type;
@@ -18,7 +15,7 @@ import 'utils.dart';
abstract class CallHandler {
Type applyCall(Call callSite, Selector selector, Args<Type> args,
{bool isResultUsed});
{required bool isResultUsed});
void typeCheckTriggered();
void addAllocatedClass(Class c);
}
@@ -27,14 +24,10 @@ abstract class CallHandler {
abstract class Statement extends TypeExpr {
/// Index of this statement in the [Summary].
int index = -1;
Summary summary;
late Summary summary;
@override
Type getComputedType(List<Type> types) {
final type = types[index];
assert(type != null);
return type;
}
Type getComputedType(List<Type?> types) => types[index]!;
String get label => "t$index";
@@ -48,7 +41,7 @@ abstract class Statement extends TypeExpr {
void accept(StatementVisitor visitor);
/// Execute this statement and compute its resulting type.
Type apply(List<Type> computedTypes, TypeHierarchy typeHierarchy,
Type apply(List<Type?> computedTypes, TypeHierarchy typeHierarchy,
CallHandler callHandler);
}
@@ -74,9 +67,9 @@ class Parameter extends Statement {
// [staticType] is null if no narrowing should be performed. This happens for
// type parameters and for parameters whose type is narrowed by a [TypeCheck]
// statement.
final Type staticTypeForNarrowing;
final Type? staticTypeForNarrowing;
Type defaultValue;
Type? defaultValue;
Type _argumentType = const EmptyType();
Parameter(this.name, this.staticTypeForNarrowing);
@@ -97,7 +90,7 @@ class Parameter extends Statement {
}
@override
Type apply(List<Type> computedTypes, TypeHierarchy typeHierarchy,
Type apply(List<Type?> computedTypes, TypeHierarchy typeHierarchy,
CallHandler callHandler) =>
throw 'Unable to apply _Parameter';
@@ -110,7 +103,7 @@ class Parameter extends Statement {
}
Type _observeNotPassed(TypeHierarchy typeHierarchy) {
final Type argType = defaultValue.specialize(typeHierarchy);
final Type argType = defaultValue!.specialize(typeHierarchy);
_observeArgumentType(argType, typeHierarchy);
return argType;
}
@@ -130,7 +123,7 @@ class Narrow extends Statement {
String dump() => "$label = _Narrow ($arg to $type)";
@override
Type apply(List<Type> computedTypes, TypeHierarchy typeHierarchy,
Type apply(List<Type?> computedTypes, TypeHierarchy typeHierarchy,
CallHandler callHandler) =>
arg.getComputedType(computedTypes).intersection(type, typeHierarchy);
}
@@ -147,11 +140,11 @@ class NarrowNotNull extends Narrow {
// Shared NarrowNotNull instances which are used when the outcome is
// known at summary creation time.
static final NarrowNotNull alwaysNotNull = NarrowNotNull(null)
static final NarrowNotNull alwaysNotNull = NarrowNotNull(const EmptyType())
.._flags = canBeNotNullFlag;
static final NarrowNotNull alwaysNull = NarrowNotNull(null)
static final NarrowNotNull alwaysNull = NarrowNotNull(const EmptyType())
.._flags = canBeNullFlag;
static final NarrowNotNull unknown = NarrowNotNull(null)
static final NarrowNotNull unknown = NarrowNotNull(const EmptyType())
.._flags = canBeNullFlag | canBeNotNullFlag;
bool get isAlwaysNull => (_flags & canBeNotNullFlag) == 0;
@@ -173,14 +166,14 @@ class NarrowNotNull extends Narrow {
}
@override
Type apply(List<Type> computedTypes, TypeHierarchy typeHierarchy,
Type apply(List<Type?> computedTypes, TypeHierarchy typeHierarchy,
CallHandler callHandler) =>
handleArgument(arg.getComputedType(computedTypes));
}
/// Joins values from multiple sources. Its type is a union of [values].
class Join extends Statement {
final String _name;
final String? _name;
final DartType staticType;
final List<TypeExpr> values = <TypeExpr>[]; // TODO(alexmarkov): Set
@@ -197,15 +190,14 @@ class Join extends Statement {
" (${values.join(", ")})";
@override
Type apply(List<Type> computedTypes, TypeHierarchy typeHierarchy,
Type apply(List<Type?> computedTypes, TypeHierarchy typeHierarchy,
CallHandler callHandler) {
Type type = null;
assert(values.isNotEmpty);
Type? type = null;
for (var value in values) {
final valueType = value.getComputedType(computedTypes);
type = type != null ? type.union(valueType, typeHierarchy) : valueType;
}
return type;
return type!;
}
}
@@ -222,7 +214,7 @@ class Use extends Statement {
String dump() => "$label = _Use ($arg)";
@override
Type apply(List<Type> computedTypes, TypeHierarchy typeHierarchy,
Type apply(List<Type?> computedTypes, TypeHierarchy typeHierarchy,
CallHandler callHandler) =>
throw 'Use statements should be removed during summary normalization';
}
@@ -231,7 +223,7 @@ class Use extends Statement {
class Call extends Statement {
final Selector selector;
final Args<TypeExpr> args;
final Type staticResultType;
final Type? staticResultType;
Call(this.selector, this.args, this.staticResultType,
bool isInstanceCreation) {
@@ -252,9 +244,10 @@ class Call extends Statement {
String dump() => "$label${isResultUsed ? '*' : ''} = _Call $selector $args";
@override
Type apply(List<Type> computedTypes, TypeHierarchy typeHierarchy,
Type apply(List<Type?> computedTypes, TypeHierarchy typeHierarchy,
CallHandler callHandler) {
final List<Type> argTypes = new List<Type>.filled(args.values.length, null);
final List<Type> argTypes =
new List<Type>.filled(args.values.length, const EmptyType());
for (int i = 0; i < args.values.length; i++) {
final Type type = args.values[i].getComputedType(computedTypes);
if (type == const EmptyType()) {
@@ -271,14 +264,15 @@ class Call extends Statement {
callHandler
.addAllocatedClass((argTypes[0] as ConcreteType).cls.classNode);
}
final Stopwatch timer = kPrintTimings ? (new Stopwatch()..start()) : null;
final Stopwatch? timer = kPrintTimings ? (new Stopwatch()..start()) : null;
Type result = callHandler.applyCall(
this, selector, new Args<Type>(argTypes, names: args.names),
isResultUsed: isResultUsed);
summary.calleeTime += kPrintTimings ? timer.elapsedMicroseconds : 0;
summary.calleeTime += kPrintTimings ? timer!.elapsedMicroseconds : 0;
if (isInstanceCreation) {
result = argTypes[0];
} else if (isResultUsed) {
final staticResultType = this.staticResultType;
if (staticResultType != null) {
result = result.intersection(staticResultType, typeHierarchy);
}
@@ -302,9 +296,9 @@ class Call extends Statement {
static const int kReceiverMayBeInt = (1 << 6);
static const int kInstanceCreation = (1 << 7);
Member _monomorphicTarget;
Member? _monomorphicTarget;
Member get monomorphicTarget => _monomorphicTarget;
Member? get monomorphicTarget => _monomorphicTarget;
bool get isMonomorphic => (_flags & kMonomorphic) != 0;
@@ -396,18 +390,19 @@ class Extract extends Statement {
"/$paramIndex]${nullability.suffix})";
@override
Type apply(List<Type> computedTypes, TypeHierarchy typeHierarchy,
Type apply(List<Type?> computedTypes, TypeHierarchy typeHierarchy,
CallHandler callHandler) {
Type argType = arg.getComputedType(computedTypes);
Type extractedType;
Type? extractedType;
void extractType(ConcreteType c) {
if (c.typeArgs == null) {
final typeArgs = c.typeArgs;
if (typeArgs == null) {
extractedType = const UnknownType();
} else {
final interfaceOffset = typeHierarchy.genericInterfaceOffsetFor(
c.cls.classNode, referenceClass);
final typeArg = c.typeArgs[interfaceOffset + paramIndex];
final typeArg = typeArgs[interfaceOffset + paramIndex];
Type extracted = typeArg;
if (typeArg is RuntimeType) {
final argNullability = typeArg.nullability;
@@ -472,16 +467,15 @@ class CreateConcreteType extends Statement {
}
@override
Type apply(List<Type> computedTypes, TypeHierarchy typeHierarchy,
Type apply(List<Type?> computedTypes, TypeHierarchy typeHierarchy,
CallHandler callHandler) {
bool hasRuntimeType = false;
final types = new List<Type>.filled(flattenedTypeArgs.length, null);
for (int i = 0; i < types.length; ++i) {
final types = List<Type>.generate(flattenedTypeArgs.length, (int i) {
final computed = flattenedTypeArgs[i].getComputedType(computedTypes);
assert(computed is RuntimeType || computed is UnknownType);
if (computed is RuntimeType) hasRuntimeType = true;
types[i] = computed;
}
return computed;
});
return new ConcreteType(cls, hasRuntimeType ? types : null);
}
}
@@ -505,14 +499,13 @@ class CreateRuntimeType extends Statement {
"${nullability.suffix})";
@override
Type apply(List<Type> computedTypes, TypeHierarchy typeHierarchy,
Type apply(List<Type?> computedTypes, TypeHierarchy typeHierarchy,
CallHandler callHandler) {
final types = new List<RuntimeType>.filled(flattenedTypeArgs.length, null);
for (int i = 0; i < types.length; ++i) {
final computed = flattenedTypeArgs[i].getComputedType(computedTypes);
assert(computed is RuntimeType || computed is UnknownType);
final types = <RuntimeType>[];
for (TypeExpr arg in flattenedTypeArgs) {
final computed = arg.getComputedType(computedTypes);
if (computed is UnknownType) return const UnknownType();
types[i] = computed;
types.add(computed as RuntimeType);
}
DartType dartType;
if (klass == typeHierarchy.coreTypes.deprecatedFutureOrClass) {
@@ -545,17 +538,15 @@ class TypeCheck extends Statement {
// "unchecked" entrypoint.
bool isTestedOnlyOnCheckedEntryPoint;
VariableDeclaration get parameter =>
node is VariableDeclaration ? node : null;
bool get isParameterCheck => node is VariableDeclaration;
VariableDeclaration get parameterVariable => node as VariableDeclaration;
bool alwaysPass = true;
bool alwaysFail = true;
TypeCheck(this.arg, this.type, this.node, this.staticType, this.kind) {
assert(node != null);
isTestedOnlyOnCheckedEntryPoint =
parameter != null && !parameter.isCovariant;
}
TypeCheck(this.arg, this.type, this.node, this.staticType, this.kind)
: isTestedOnlyOnCheckedEntryPoint =
node is VariableDeclaration && !node.isCovariant;
@override
void accept(StatementVisitor visitor) => visitor.visitTypeCheck(this);
@@ -568,7 +559,7 @@ class TypeCheck extends Statement {
}
@override
Type apply(List<Type> computedTypes, TypeHierarchy typeHierarchy,
Type apply(List<Type?> computedTypes, TypeHierarchy typeHierarchy,
CallHandler callHandler) {
Type argType = arg.getComputedType(computedTypes);
Type checkType = type.getComputedType(computedTypes);
@@ -624,11 +615,11 @@ class Summary {
int requiredParameterCount;
List<Statement> _statements = <Statement>[];
TypeExpr result = null;
Type resultType = EmptyType();
TypeExpr result = const EmptyType();
Type resultType = const EmptyType();
// Analysis time of callees. Populated only if kPrintTimings.
int calleeTime;
int calleeTime = 0;
Summary(this.name,
{this.parameterCount: 0,
@@ -658,7 +649,7 @@ class Summary {
/// Apply this summary to the given arguments and return the resulting type.
Type apply(Args<Type> arguments, TypeHierarchy typeHierarchy,
CallHandler callHandler) {
final Stopwatch timer = kPrintTimings ? (new Stopwatch()..start()) : null;
final Stopwatch? timer = kPrintTimings ? (new Stopwatch()..start()) : null;
final int oldCalleeTime = calleeTime;
calleeTime = 0;
final args = arguments.values;
@@ -677,7 +668,7 @@ class Summary {
//
// The first `parameterCount` statements are Parameters.
List<Type> types = new List<Type>.filled(_statements.length, null);
List<Type?> types = new List<Type?>.filled(_statements.length, null);
for (int i = 0; i < positionalArgCount; i++) {
final Parameter param = _statements[i] as Parameter;
@@ -687,9 +678,9 @@ class Summary {
}
final argType = args[i].specialize(typeHierarchy);
param._observeArgumentType(argType, typeHierarchy);
if (param.staticTypeForNarrowing != null) {
types[i] =
argType.intersection(param.staticTypeForNarrowing, typeHierarchy);
final staticTypeForNarrowing = param.staticTypeForNarrowing;
if (staticTypeForNarrowing != null) {
types[i] = argType.intersection(staticTypeForNarrowing, typeHierarchy);
} else {
// TODO(sjindel/tfa): Narrowing is performed inside a [TypeCheck] later.
types[i] = args[i];
@@ -710,9 +701,10 @@ class Summary {
args[positionalArgCount + argIndex].specialize(typeHierarchy);
argIndex++;
param._observeArgumentType(argType, typeHierarchy);
if (param.staticTypeForNarrowing != null) {
final staticTypeForNarrowing = param.staticTypeForNarrowing;
if (staticTypeForNarrowing != null) {
types[i] =
argType.intersection(param.staticTypeForNarrowing, typeHierarchy);
argType.intersection(staticTypeForNarrowing, typeHierarchy);
} else {
types[i] = argType;
}
@@ -741,7 +733,7 @@ class Summary {
resultType = resultType.union(computedType, typeHierarchy);
if (kPrintTimings) {
final dirtyTime = timer.elapsedMicroseconds;
final dirtyTime = timer!.elapsedMicroseconds;
final pureTime = dirtyTime < calleeTime ? 0 : (dirtyTime - calleeTime);
Statistics.numSummaryApplications.add(name);
Statistics.dirtySummaryAnalysisTime.add(name, dirtyTime);
@@ -753,9 +745,9 @@ class Summary {
}
Args<Type> get argumentTypes {
final argTypes = new List<Type>.filled(parameterCount, null);
final argNames = new List<String>.filled(
parameterCount - positionalParameterCount, null);
final argTypes = new List<Type>.filled(parameterCount, const EmptyType());
final argNames =
new List<String>.filled(parameterCount - positionalParameterCount, '');
for (int i = 0; i < parameterCount; i++) {
Parameter param = _statements[i] as Parameter;
argTypes[i] = param.argumentType;
@@ -769,7 +761,7 @@ class Summary {
Type argumentType(Member member, VariableDeclaration memberParam) {
final int firstParamIndex =
numTypeParams(member) + (hasReceiverArg(member) ? 1 : 0);
final positional = member.function.positionalParameters;
final positional = member.function!.positionalParameters;
for (int i = 0; i < positional.length; i++) {
if (positional[i] == memberParam) {
final Parameter param = _statements[firstParamIndex + i] as Parameter;
@@ -791,8 +783,8 @@ class Summary {
for (Statement statement in _statements) {
if (statement is TypeCheck &&
statement.alwaysPass &&
statement.parameter != null) {
params.add(statement.parameter);
statement.isParameterCheck) {
params.add(statement.parameterVariable);
}
}
return params;
@@ -808,17 +800,17 @@ class Summary {
(hasReceiverArg(member) ? 1 : 0) + numTypeParams(member);
final Map<String, Parameter> paramsByName = {};
for (int i = implicit; i < parameterCount; i++) {
final Parameter param = statements[i];
final Parameter param = statements[i] as Parameter;
paramsByName[param.name] = param;
}
FunctionNode function = member.function;
FunctionNode function = member.function!;
statements.length = implicit;
for (VariableDeclaration param in function.positionalParameters) {
statements.add(paramsByName[param.name]);
statements.add(paramsByName[param.name]!);
}
positionalParameterCount = statements.length;
for (VariableDeclaration param in function.namedParameters) {
statements.add(paramsByName[param.name]);
statements.add(paramsByName[param.name]!);
}
parameterCount = statements.length;
requiredParameterCount = implicit + function.requiredParameterCount;
File diff suppressed because it is too large Load Diff
@@ -2,8 +2,6 @@
// 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.
// @dart=2.9
import 'package:kernel/ast.dart';
import 'utils.dart' show UnionFind;
@@ -18,7 +16,7 @@ class TableSelectorAssigner {
final Map<Class, Map<Name, int>> _methodOrSetterMemberIds = {};
final UnionFind _unionFind = UnionFind();
List<int> _selectorIdForMemberId;
late List<int?> _selectorIdForMemberId;
TableSelectorAssigner(Component component) {
for (Library library in component.libraries) {
@@ -44,20 +42,21 @@ class TableSelectorAssigner {
}
}
Map<Name, int> _memberIdsForClass(Class cls, {bool getter}) {
Map<Name, int> _memberIdsForClass(Class? cls, {required bool getter}) {
if (cls == null) return {};
final cache = getter ? _getterMemberIds : _methodOrSetterMemberIds;
// Already computed for this class?
Map<Name, int> memberIds = cache[cls];
if (memberIds != null) return memberIds;
final cachedMemberIds = cache[cls];
if (cachedMemberIds != null) return cachedMemberIds;
// Merge maps from supertypes.
memberIds = Map.from(_memberIdsForClass(cls.superclass, getter: getter));
final memberIds =
Map<Name, int>.from(_memberIdsForClass(cls.superclass, getter: getter));
for (Supertype impl in cls.implementedTypes) {
_memberIdsForClass(impl.classNode, getter: getter).forEach((name, id) {
final int firstId = memberIds[name];
final int? firstId = memberIds[name];
if (firstId == null) {
memberIds[name] = id;
} else if (firstId != id) {
@@ -99,9 +98,9 @@ class TableSelectorAssigner {
return cache[cls] = memberIds;
}
int _selectorIdForMember(Member member, {bool getter}) {
int _selectorIdForMember(Member member, {required bool getter}) {
final map = getter ? _getterMemberIds : _methodOrSetterMemberIds;
int memberId = map[member.enclosingClass][member.name];
int? memberId = map[member.enclosingClass!]![member.name];
if (memberId == null) {
assert(member is Procedure &&
((identical(map, _getterMemberIds) &&
@@ -115,7 +114,7 @@ class TableSelectorAssigner {
return ProcedureAttributesMetadata.kInvalidSelectorId;
}
memberId = _unionFind.find(memberId);
int selectorId = _selectorIdForMemberId[memberId];
int? selectorId = _selectorIdForMemberId[memberId];
if (selectorId == null) {
_selectorIdForMemberId[memberId] = selectorId = metadata.addSelector();
}
@@ -2,10 +2,7 @@
// 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.
// @dart=2.9
/// Transformations based on type flow analysis.
library vm.transformations.type_flow.transformer;
import 'dart:core' hide Type;
@@ -14,7 +11,8 @@ import 'package:kernel/ast.dart' hide Statement, StatementVisitor;
import 'package:kernel/ast.dart' as ast show Statement;
import 'package:kernel/clone.dart' show CloneVisitorNotMembers;
import 'package:kernel/core_types.dart' show CoreTypes;
import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
import 'package:kernel/class_hierarchy.dart'
show ClassHierarchy, ClosedWorldClassHierarchy;
import 'package:kernel/library_index.dart' show LibraryIndex;
import 'package:kernel/type_environment.dart';
@@ -43,16 +41,18 @@ const bool kDumpClassHierarchy =
/// Assumes strong mode and closed world.
Component transformComponent(
Target target, CoreTypes coreTypes, Component component,
{PragmaAnnotationParser matcher,
{PragmaAnnotationParser? matcher,
bool treeShakeSignatures: true,
bool treeShakeWriteOnlyFields: true,
bool treeShakeProtobufs: false}) {
void ignoreAmbiguousSupertypes(Class cls, Supertype a, Supertype b) {}
final hierarchy = new ClassHierarchy(component, coreTypes,
onAmbiguousSupertypes: ignoreAmbiguousSupertypes);
onAmbiguousSupertypes: ignoreAmbiguousSupertypes)
as ClosedWorldClassHierarchy;
final types = new TypeEnvironment(coreTypes, hierarchy);
final libraryIndex = new LibraryIndex.all(component);
final genericInterfacesInfo = new GenericInterfacesInfoImpl(hierarchy);
final genericInterfacesInfo =
new GenericInterfacesInfoImpl(coreTypes, hierarchy);
final protobufHandler = treeShakeProtobufs
? ProtobufHandler.forComponent(component, coreTypes)
: null;
@@ -73,7 +73,7 @@ Component transformComponent(
protobufHandler,
matcher);
Procedure main = component.mainMethod;
Procedure? main = component.mainMethod;
// `main` can be null, roots can also come from @pragma("vm:entry-point").
if (main != null) {
@@ -149,7 +149,7 @@ class MoveFieldInitializers {
if (!f.isStatic &&
!f.isLate &&
f.initializer != null &&
mayHaveSideEffects(f.initializer))
mayHaveSideEffects(f.initializer!))
f
];
if (fields.isEmpty) return;
@@ -173,7 +173,7 @@ class MoveFieldInitializers {
};
final List<Initializer> newInitializers = [];
for (Field f in fields) {
Expression initExpr = f.initializer;
Expression initExpr = f.initializer!;
if (!isFirst) {
initExpr = CloneVisitorNotMembers().clone(initExpr);
}
@@ -204,7 +204,7 @@ class MoveFieldInitializers {
class CleanupAnnotations extends RecursiveVisitor {
final Class externalNameClass;
final Class pragmaClass;
final ProtobufHandler protobufHandler;
final ProtobufHandler? protobufHandler;
CleanupAnnotations(
CoreTypes coreTypes, LibraryIndex index, this.protobufHandler)
@@ -238,7 +238,7 @@ class CleanupAnnotations extends RecursiveVisitor {
return (cls == externalNameClass) ||
(cls == pragmaClass) ||
(protobufHandler != null &&
protobufHandler.usesAnnotationClass(cls));
protobufHandler!.usesAnnotationClass(cls));
}
}
return false;
@@ -255,11 +255,11 @@ class TFADevirtualization extends Devirtualization {
: super(_typeFlowAnalysis.environment.coreTypes, component, hierarchy);
@override
DirectCallMetadata getDirectCall(TreeNode node, Member interfaceTarget,
DirectCallMetadata? getDirectCall(TreeNode node, Member? interfaceTarget,
{bool setter = false}) {
final callSite = _typeFlowAnalysis.callSite(node);
if (callSite != null) {
final Member singleTarget = fieldMorpher
final Member? singleTarget = fieldMorpher
.getMorphedMember(callSite.monomorphicTarget, isSetter: setter);
if (singleTarget != null) {
return new DirectCallMetadata(
@@ -283,12 +283,13 @@ class AnnotateKernel extends RecursiveVisitor {
final UnboxingInfoMetadataRepository _unboxingInfoMetadata;
final UnboxingInfoManager _unboxingInfo;
final Class _intClass;
Constant _nullConstant;
late final Constant _nullConstant = NullConstant();
AnnotateKernel(Component component, this._typeFlowAnalysis, this.fieldMorpher,
this._tableSelectorAssigner, this._unboxingInfo)
: _directCallMetadataRepository =
component.metadata[DirectCallMetadataRepository.repositoryTag],
component.metadata[DirectCallMetadataRepository.repositoryTag]
as DirectCallMetadataRepository,
_inferredTypeMetadata = new InferredTypeMetadataRepository(),
_unreachableNodeMetadata = new UnreachableNodeMetadataRepository(),
_procedureAttributesMetadata =
@@ -308,12 +309,10 @@ class AnnotateKernel extends RecursiveVisitor {
return _directCallMetadataRepository.mapping.containsKey(node);
}
InferredType _convertType(Type type,
InferredType? _convertType(Type type,
{bool skipCheck: false, bool receiverNotInt: false}) {
assert(type != null);
Class concreteClass;
Constant constantValue;
Class? concreteClass;
Constant? constantValue;
bool isInt = false;
final nullable = type is NullableType;
@@ -324,7 +323,7 @@ class AnnotateKernel extends RecursiveVisitor {
if (nullable && type == const EmptyType()) {
concreteClass =
_typeFlowAnalysis.environment.coreTypes.deprecatedNullClass;
constantValue = _nullConstant ??= new NullConstant();
constantValue = _nullConstant;
} else {
concreteClass = type.getConcreteClass(_typeFlowAnalysis.hierarchyCache);
@@ -337,9 +336,9 @@ class AnnotateKernel extends RecursiveVisitor {
}
}
List<DartType> typeArgs;
List<DartType?>? typeArgs;
if (type is ConcreteType && type.typeArgs != null) {
typeArgs = type.typeArgs
typeArgs = type.typeArgs!
.take(type.numImmediateTypeArgs)
.map((t) =>
t is UnknownType ? null : (t as RuntimeType).representedType)
@@ -374,7 +373,7 @@ class AnnotateKernel extends RecursiveVisitor {
_unreachableNodeMetadata.mapping[node] = const UnreachableNode();
}
void _annotateCallSite(TreeNode node, Member interfaceTarget) {
void _annotateCallSite(TreeNode node, Member? interfaceTarget) {
final callSite = _typeFlowAnalysis.callSite(node);
if (callSite == null) return;
if (!callSite.isReachable) {
@@ -405,7 +404,7 @@ class AnnotateKernel extends RecursiveVisitor {
if (interfaceTarget == null ||
_typeFlowAnalysis.hierarchyCache.hierarchy.isSubtypeOf(
_typeFlowAnalysis.hierarchyCache.coreTypes.intClass,
interfaceTarget.enclosingClass)) {
interfaceTarget.enclosingClass!)) {
markReceiverNotInt = true;
}
}
@@ -446,35 +445,33 @@ class AnnotateKernel extends RecursiveVisitor {
void _annotateMember(Member member) {
if (_typeFlowAnalysis.isMemberUsed(member)) {
if (member is Field) {
_setInferredType(member, _typeFlowAnalysis.fieldType(member));
_setInferredType(member, _typeFlowAnalysis.fieldType(member)!);
} else {
Args<Type> argTypes = _typeFlowAnalysis.argumentTypes(member);
Args<Type> argTypes = _typeFlowAnalysis.argumentTypes(member)!;
final uncheckedParameters =
_typeFlowAnalysis.uncheckedParameters(member);
assert(argTypes != null);
final int firstParamIndex =
numTypeParams(member) + (hasReceiverArg(member) ? 1 : 0);
final positionalParams = member.function.positionalParameters;
final positionalParams = member.function!.positionalParameters;
assert(argTypes.positionalCount ==
firstParamIndex + positionalParams.length);
for (int i = 0; i < positionalParams.length; i++) {
_setInferredType(
positionalParams[i], argTypes.values[firstParamIndex + i],
skipCheck: uncheckedParameters.contains(positionalParams[i]));
skipCheck: uncheckedParameters!.contains(positionalParams[i]));
}
// TODO(dartbug.com/32292): make sure parameters are sorted in kernel
// AST and iterate parameters in parallel, without lookup.
final names = argTypes.names;
for (int i = 0; i < names.length; i++) {
final param = findNamedParameter(member.function, names[i]);
assert(param != null);
final param = findNamedParameter(member.function!, names[i])!;
_setInferredType(param,
argTypes.values[firstParamIndex + positionalParams.length + i],
skipCheck: uncheckedParameters.contains(param));
skipCheck: uncheckedParameters!.contains(param));
}
// TODO(alexmarkov): figure out how to pass receiver type.
@@ -521,7 +518,7 @@ class AnnotateKernel extends RecursiveVisitor {
// interface target, and table dispatch calls need selector IDs for all
// interface targets.
if (member.isInstanceMember) {
final original = fieldMorpher.getOriginalMember(member);
final original = fieldMorpher.getOriginalMember(member)!;
final attrs = new ProcedureAttributesMetadata(
methodOrSetterCalledDynamically:
_typeFlowAnalysis.isCalledDynamically(original),
@@ -689,11 +686,11 @@ class TreeShaker {
final Set<Member> _usedMembers = new Set<Member>();
final Set<Extension> _usedExtensions = new Set<Extension>();
final Set<Typedef> _usedTypedefs = new Set<Typedef>();
FieldMorpher fieldMorpher;
_TreeShakerTypeVisitor typeVisitor;
_TreeShakerConstantVisitor constantVisitor;
_TreeShakerPass1 _pass1;
_TreeShakerPass2 _pass2;
late final FieldMorpher fieldMorpher;
late final _TreeShakerTypeVisitor typeVisitor;
late final _TreeShakerConstantVisitor constantVisitor;
late final _TreeShakerPass1 _pass1;
late final _TreeShakerPass2 _pass2;
TreeShaker(Component component, this.typeFlowAnalysis,
{this.treeShakeWriteOnlyFields: true}) {
@@ -734,7 +731,7 @@ class TreeShaker {
(!f.isStatic &&
f.initializer != null &&
isFieldInitializerReachable(f) &&
mayHaveSideEffects(f.initializer)) ||
mayHaveSideEffects(f.initializer!)) ||
(f.isLate && f.isFinal)) ||
isMemberReferencedFromNativeCode(f) ||
_isInstanceFieldOfAllocatedEnum(f);
@@ -745,8 +742,8 @@ class TreeShaker {
bool _isInstanceFieldOfAllocatedEnum(Field node) =>
!node.isStatic &&
node.enclosingClass != null &&
node.enclosingClass.isEnum &&
isClassAllocated(node.enclosingClass);
node.enclosingClass!.isEnum &&
isClassAllocated(node.enclosingClass!);
void addClassUsedInType(Class c) {
if (_classesUsedInType.add(c)) {
@@ -777,7 +774,7 @@ class TreeShaker {
_usedClasses.add(enclosingClass);
}
FunctionNode func = null;
FunctionNode? func = null;
if (m is Field) {
m.type.accept(typeVisitor);
} else if (m is Procedure) {
@@ -786,19 +783,19 @@ class TreeShaker {
m.stubTarget = fieldMorpher.adjustInstanceCallTarget(
m.concreteForwardingStubTarget,
isSetter: m.isSetter);
addUsedMember(m.concreteForwardingStubTarget);
addUsedMember(m.concreteForwardingStubTarget!);
}
if (m.abstractForwardingStubTarget != null) {
m.stubTarget = fieldMorpher.adjustInstanceCallTarget(
m.abstractForwardingStubTarget,
isSetter: m.isSetter);
addUsedMember(m.abstractForwardingStubTarget);
addUsedMember(m.abstractForwardingStubTarget!);
}
if (m.memberSignatureOrigin != null) {
m.stubTarget = fieldMorpher.adjustInstanceCallTarget(
m.memberSignatureOrigin,
isSetter: m.isSetter);
addUsedMember(m.memberSignatureOrigin);
addUsedMember(m.memberSignatureOrigin!);
}
} else if (m is Constructor) {
func = m.function;
@@ -821,8 +818,7 @@ class TreeShaker {
final extension = m.enclosingLibrary.extensions.firstWhere((extension) {
return extension.members
.any((descriptor) => descriptor.member.asMember == m);
}, orElse: () => null);
assert(extension != null);
});
// Ensure we retain the [Extension] itself (though members might be
// shaken)
@@ -844,7 +840,7 @@ class TreeShaker {
if (_usedExtensions.add(node)) {
node.annotations = const <Expression>[];
_pass1.transformTypeParameterList(node.typeParameters, node);
node.onType?.accept(typeVisitor);
node.onType.accept(typeVisitor);
}
}
@@ -898,7 +894,7 @@ class FieldMorpher {
isAbstract: true, fileUri: field.fileUri);
}
accessor.fileOffset = field.fileOffset;
field.enclosingClass.addProcedure(accessor);
field.enclosingClass!.addProcedure(accessor);
_removedFields[accessor] = field;
shaker.addUsedMember(accessor);
return accessor;
@@ -908,7 +904,7 @@ class FieldMorpher {
/// If necessary, creates a getter or setter as a replacement if target is a
/// field which is going to be removed by the tree shaker.
/// This method is used during tree shaker pass 1.
Member adjustInstanceCallTarget(Member target, {bool isSetter = false}) {
Member? adjustInstanceCallTarget(Member? target, {bool isSetter = false}) {
if (target is Field && !shaker.retainField(target)) {
final targets =
isSetter ? _settersForRemovedFields : _gettersForRemovedFields;
@@ -923,9 +919,9 @@ class FieldMorpher {
/// Return a member which replaced [target] in instance calls.
/// This method can be used after tree shaking to discover replacement.
Member getMorphedMember(Member target, {bool isSetter = false}) {
if (target == null) {
return null;
Member? getMorphedMember(Member? target, {bool isSetter = false}) {
if (target is! Field) {
return target;
}
final targets =
isSetter ? _settersForRemovedFields : _gettersForRemovedFields;
@@ -934,7 +930,7 @@ class FieldMorpher {
/// Return original member which was replaced by [target] in instance calls.
/// This method can be used after tree shaking.
Member getOriginalMember(Member target) {
Member? getOriginalMember(Member? target) {
if (target == null) {
return null;
}
@@ -994,16 +990,15 @@ class _TreeShakerPass1 extends RemovingTransformer {
final TreeShaker shaker;
final FieldMorpher fieldMorpher;
final TypeEnvironment environment;
Procedure _unsafeCast;
StaticTypeContext _staticTypeContext;
Member _currentMember;
StaticTypeContext? _staticTypeContext;
Member? _currentMember;
StaticTypeContext get staticTypeContext =>
_staticTypeContext ??= StaticTypeContext(currentMember, environment);
Member get currentMember => _currentMember;
set currentMember(Member m) {
Member get currentMember => _currentMember!;
set currentMember(Member? m) {
_currentMember = m;
_staticTypeContext = null;
}
@@ -1022,7 +1017,7 @@ class _TreeShakerPass1 extends RemovingTransformer {
}
List<Expression> _flattenArguments(Arguments arguments,
{Expression receiver}) {
{Expression? receiver}) {
final args = <Expression>[];
if (receiver != null) {
args.add(receiver);
@@ -1035,9 +1030,9 @@ class _TreeShakerPass1 extends RemovingTransformer {
bool _isThrowExpression(Expression expr) {
for (;;) {
if (expr is Let) {
expr = (expr as Let).body;
expr = expr.body;
} else if (expr is BlockExpression) {
expr = (expr as BlockExpression).value;
expr = expr.value;
} else {
break;
}
@@ -1068,7 +1063,7 @@ class _TreeShakerPass1 extends RemovingTransformer {
return BlockExpression(Block(statements), value);
}
TreeNode _makeUnreachableCall(List<Expression> args) {
Expression _makeUnreachableCall(List<Expression> args) {
Expression node;
final int last = args.indexWhere(_isThrowExpression);
if (last >= 0) {
@@ -1090,12 +1085,12 @@ class _TreeShakerPass1 extends RemovingTransformer {
new VariableDeclaration(null, initializer: _makeUnreachableCall(args)));
}
NarrowNotNull _getNullTest(TreeNode node) =>
NarrowNotNull? _getNullTest(TreeNode node) =>
shaker.typeFlowAnalysis.nullTest(node);
TreeNode _visitAssertNode(TreeNode node, TreeNode removalSentinel) {
TreeNode _visitAssertNode(TreeNode node, TreeNode? removalSentinel) {
if (kRemoveAsserts) {
return removalSentinel;
return removalSentinel!;
} else {
node.transformOrRemoveChildren(this);
return node;
@@ -1103,31 +1098,31 @@ class _TreeShakerPass1 extends RemovingTransformer {
}
@override
DartType visitDartType(DartType node, DartType removalSentinel) {
DartType visitDartType(DartType node, DartType? removalSentinel) {
node.accept(shaker.typeVisitor);
return node;
}
@override
Supertype visitSupertype(Supertype node, Supertype removalSentinel) {
Supertype visitSupertype(Supertype node, Supertype? removalSentinel) {
node.accept(shaker.typeVisitor);
return node;
}
@override
TreeNode visitTypedef(Typedef node, TreeNode removalSentinel) {
TreeNode visitTypedef(Typedef node, TreeNode? removalSentinel) {
return node; // Do not go deeper.
}
@override
Extension visitExtension(Extension node, TreeNode removalSentinel) {
TreeNode visitExtension(Extension node, TreeNode? removalSentinel) {
// The extension can be considered a weak node, we'll only retain it if
// normal code references any of it's members.
return node;
}
@override
TreeNode visitClass(Class node, TreeNode removalSentinel) {
TreeNode visitClass(Class node, TreeNode? removalSentinel) {
if (shaker.isClassAllocated(node) ||
shaker.isClassReferencedFromNativeCode(node)) {
shaker.addClassUsedInType(node);
@@ -1140,7 +1135,7 @@ class _TreeShakerPass1 extends RemovingTransformer {
}
@override
TreeNode defaultMember(Member node, TreeNode removalSentinel) {
TreeNode defaultMember(Member node, TreeNode? removalSentinel) {
currentMember = node;
if (shaker.isMemberBodyReachable(node)) {
if (kPrintTrace) {
@@ -1160,7 +1155,7 @@ class _TreeShakerPass1 extends RemovingTransformer {
}
@override
TreeNode visitField(Field node, TreeNode removalSentinel) {
TreeNode visitField(Field node, TreeNode? removalSentinel) {
currentMember = node;
if (shaker.retainField(node)) {
if (kPrintTrace) {
@@ -1185,21 +1180,21 @@ class _TreeShakerPass1 extends RemovingTransformer {
@override
TreeNode visitInstanceInvocation(
InstanceInvocation node, TreeNode removalSentinel) {
InstanceInvocation node, TreeNode? removalSentinel) {
node.transformOrRemoveChildren(this);
if (_isUnreachable(node)) {
return _makeUnreachableCall(
_flattenArguments(node.arguments, receiver: node.receiver));
}
node.interfaceTarget =
fieldMorpher.adjustInstanceCallTarget(node.interfaceTarget);
node.interfaceTarget = fieldMorpher
.adjustInstanceCallTarget(node.interfaceTarget) as Procedure;
shaker.addUsedMember(node.interfaceTarget);
return node;
}
@override
TreeNode visitDynamicInvocation(
DynamicInvocation node, TreeNode removalSentinel) {
DynamicInvocation node, TreeNode? removalSentinel) {
node.transformOrRemoveChildren(this);
if (_isUnreachable(node)) {
return _makeUnreachableCall(
@@ -1210,7 +1205,7 @@ class _TreeShakerPass1 extends RemovingTransformer {
@override
TreeNode visitLocalFunctionInvocation(
LocalFunctionInvocation node, TreeNode removalSentinel) {
LocalFunctionInvocation node, TreeNode? removalSentinel) {
node.transformOrRemoveChildren(this);
if (_isUnreachable(node)) {
return _makeUnreachableCall(_flattenArguments(node.arguments));
@@ -1220,7 +1215,7 @@ class _TreeShakerPass1 extends RemovingTransformer {
@override
TreeNode visitFunctionInvocation(
FunctionInvocation node, TreeNode removalSentinel) {
FunctionInvocation node, TreeNode? removalSentinel) {
node.transformOrRemoveChildren(this);
if (_isUnreachable(node)) {
return _makeUnreachableCall(
@@ -1230,24 +1225,24 @@ class _TreeShakerPass1 extends RemovingTransformer {
}
@override
TreeNode visitEqualsCall(EqualsCall node, TreeNode removalSentinel) {
TreeNode visitEqualsCall(EqualsCall node, TreeNode? removalSentinel) {
node.transformOrRemoveChildren(this);
if (_isUnreachable(node)) {
return _makeUnreachableCall([node.left, node.right]);
}
node.interfaceTarget =
fieldMorpher.adjustInstanceCallTarget(node.interfaceTarget);
node.interfaceTarget = fieldMorpher
.adjustInstanceCallTarget(node.interfaceTarget) as Procedure;
shaker.addUsedMember(node.interfaceTarget);
return node;
}
@override
TreeNode visitEqualsNull(EqualsNull node, TreeNode removalSentinel) {
TreeNode visitEqualsNull(EqualsNull node, TreeNode? removalSentinel) {
node.transformOrRemoveChildren(this);
if (_isUnreachable(node)) {
return _makeUnreachableCall([node.expression]);
}
final nullTest = _getNullTest(node);
final nullTest = _getNullTest(node)!;
if (nullTest.isAlwaysNull || nullTest.isAlwaysNotNull) {
return _evaluateArguments([node.expression],
BoolLiteral(nullTest.isAlwaysNull)..fileOffset = node.fileOffset);
@@ -1256,13 +1251,13 @@ class _TreeShakerPass1 extends RemovingTransformer {
}
@override
TreeNode visitInstanceGet(InstanceGet node, TreeNode removalSentinel) {
TreeNode visitInstanceGet(InstanceGet node, TreeNode? removalSentinel) {
node.transformOrRemoveChildren(this);
if (_isUnreachable(node)) {
return _makeUnreachableCall([node.receiver]);
} else {
node.interfaceTarget =
fieldMorpher.adjustInstanceCallTarget(node.interfaceTarget);
fieldMorpher.adjustInstanceCallTarget(node.interfaceTarget)!;
shaker.addUsedMember(node.interfaceTarget);
return node;
}
@@ -1270,20 +1265,20 @@ class _TreeShakerPass1 extends RemovingTransformer {
@override
TreeNode visitInstanceTearOff(
InstanceTearOff node, TreeNode removalSentinel) {
InstanceTearOff node, TreeNode? removalSentinel) {
node.transformOrRemoveChildren(this);
if (_isUnreachable(node)) {
return _makeUnreachableCall([node.receiver]);
} else {
node.interfaceTarget =
fieldMorpher.adjustInstanceCallTarget(node.interfaceTarget);
node.interfaceTarget = fieldMorpher
.adjustInstanceCallTarget(node.interfaceTarget) as Procedure;
shaker.addUsedMember(node.interfaceTarget);
return node;
}
}
@override
TreeNode visitDynamicGet(DynamicGet node, TreeNode removalSentinel) {
TreeNode visitDynamicGet(DynamicGet node, TreeNode? removalSentinel) {
node.transformOrRemoveChildren(this);
if (_isUnreachable(node)) {
return _makeUnreachableCall([node.receiver]);
@@ -1294,7 +1289,7 @@ class _TreeShakerPass1 extends RemovingTransformer {
@override
TreeNode visitFunctionTearOff(
FunctionTearOff node, TreeNode removalSentinel) {
FunctionTearOff node, TreeNode? removalSentinel) {
node.transformOrRemoveChildren(this);
if (_isUnreachable(node)) {
return _makeUnreachableCall([node.receiver]);
@@ -1304,20 +1299,20 @@ class _TreeShakerPass1 extends RemovingTransformer {
}
@override
TreeNode visitInstanceSet(InstanceSet node, TreeNode removalSentinel) {
TreeNode visitInstanceSet(InstanceSet node, TreeNode? removalSentinel) {
node.transformOrRemoveChildren(this);
if (_isUnreachable(node)) {
return _makeUnreachableCall([node.receiver, node.value]);
} else {
node.interfaceTarget = fieldMorpher
.adjustInstanceCallTarget(node.interfaceTarget, isSetter: true);
.adjustInstanceCallTarget(node.interfaceTarget, isSetter: true)!;
shaker.addUsedMember(node.interfaceTarget);
return node;
}
}
@override
TreeNode visitDynamicSet(DynamicSet node, TreeNode removalSentinel) {
TreeNode visitDynamicSet(DynamicSet node, TreeNode? removalSentinel) {
node.transformOrRemoveChildren(this);
if (_isUnreachable(node)) {
return _makeUnreachableCall([node.receiver, node.value]);
@@ -1328,15 +1323,15 @@ class _TreeShakerPass1 extends RemovingTransformer {
@override
TreeNode visitSuperMethodInvocation(
SuperMethodInvocation node, TreeNode removalSentinel) {
SuperMethodInvocation node, TreeNode? removalSentinel) {
node.transformOrRemoveChildren(this);
if (_isUnreachable(node)) {
return _makeUnreachableCall(_flattenArguments(node.arguments));
} else {
node.interfaceTarget =
fieldMorpher.adjustInstanceCallTarget(node.interfaceTarget);
node.interfaceTarget = fieldMorpher
.adjustInstanceCallTarget(node.interfaceTarget) as Procedure?;
if (node.interfaceTarget != null) {
shaker.addUsedMember(node.interfaceTarget);
shaker.addUsedMember(node.interfaceTarget!);
}
return node;
}
@@ -1344,7 +1339,7 @@ class _TreeShakerPass1 extends RemovingTransformer {
@override
TreeNode visitSuperPropertyGet(
SuperPropertyGet node, TreeNode removalSentinel) {
SuperPropertyGet node, TreeNode? removalSentinel) {
node.transformOrRemoveChildren(this);
if (_isUnreachable(node)) {
return _makeUnreachableCall([]);
@@ -1352,7 +1347,7 @@ class _TreeShakerPass1 extends RemovingTransformer {
node.interfaceTarget =
fieldMorpher.adjustInstanceCallTarget(node.interfaceTarget);
if (node.interfaceTarget != null) {
shaker.addUsedMember(node.interfaceTarget);
shaker.addUsedMember(node.interfaceTarget!);
}
return node;
}
@@ -1360,7 +1355,7 @@ class _TreeShakerPass1 extends RemovingTransformer {
@override
TreeNode visitSuperPropertySet(
SuperPropertySet node, TreeNode removalSentinel) {
SuperPropertySet node, TreeNode? removalSentinel) {
node.transformOrRemoveChildren(this);
if (_isUnreachable(node)) {
return _makeUnreachableCall([node.value]);
@@ -1368,7 +1363,7 @@ class _TreeShakerPass1 extends RemovingTransformer {
node.interfaceTarget = fieldMorpher
.adjustInstanceCallTarget(node.interfaceTarget, isSetter: true);
if (node.interfaceTarget != null) {
shaker.addUsedMember(node.interfaceTarget);
shaker.addUsedMember(node.interfaceTarget!);
}
return node;
}
@@ -1376,7 +1371,7 @@ class _TreeShakerPass1 extends RemovingTransformer {
@override
TreeNode visitStaticInvocation(
StaticInvocation node, TreeNode removalSentinel) {
StaticInvocation node, TreeNode? removalSentinel) {
node.transformOrRemoveChildren(this);
if (_isUnreachable(node)) {
return _makeUnreachableCall(_flattenArguments(node.arguments));
@@ -1390,7 +1385,7 @@ class _TreeShakerPass1 extends RemovingTransformer {
}
@override
TreeNode visitStaticGet(StaticGet node, TreeNode removalSentinel) {
TreeNode visitStaticGet(StaticGet node, TreeNode? removalSentinel) {
node.transformOrRemoveChildren(this);
if (_isUnreachable(node)) {
return _makeUnreachableCall([]);
@@ -1405,13 +1400,13 @@ class _TreeShakerPass1 extends RemovingTransformer {
}
@override
Constant visitConstant(Constant node, Constant removalSentinel) {
Constant visitConstant(Constant node, Constant? removalSentinel) {
shaker.constantVisitor.analyzeConstant(node);
return node;
}
@override
TreeNode visitStaticSet(StaticSet node, TreeNode removalSentinel) {
TreeNode visitStaticSet(StaticSet node, TreeNode? removalSentinel) {
node.transformOrRemoveChildren(this);
if (_isUnreachable(node)) {
return _makeUnreachableCall([node.value]);
@@ -1428,7 +1423,7 @@ class _TreeShakerPass1 extends RemovingTransformer {
@override
TreeNode visitConstructorInvocation(
ConstructorInvocation node, TreeNode removalSentinel) {
ConstructorInvocation node, TreeNode? removalSentinel) {
node.transformOrRemoveChildren(this);
if (_isUnreachable(node)) {
return _makeUnreachableCall(_flattenArguments(node.arguments));
@@ -1444,7 +1439,7 @@ class _TreeShakerPass1 extends RemovingTransformer {
@override
TreeNode visitRedirectingInitializer(
RedirectingInitializer node, TreeNode removalSentinel) {
RedirectingInitializer node, TreeNode? removalSentinel) {
node.transformOrRemoveChildren(this);
if (_isUnreachable(node)) {
return _makeUnreachableInitializer(_flattenArguments(node.arguments));
@@ -1457,7 +1452,7 @@ class _TreeShakerPass1 extends RemovingTransformer {
@override
TreeNode visitSuperInitializer(
SuperInitializer node, TreeNode removalSentinel) {
SuperInitializer node, TreeNode? removalSentinel) {
node.transformOrRemoveChildren(this);
if (_isUnreachable(node)) {
return _makeUnreachableInitializer(_flattenArguments(node.arguments));
@@ -1469,7 +1464,7 @@ class _TreeShakerPass1 extends RemovingTransformer {
@override
TreeNode visitFieldInitializer(
FieldInitializer node, TreeNode removalSentinel) {
FieldInitializer node, TreeNode? removalSentinel) {
node.transformOrRemoveChildren(this);
if (_isUnreachable(node)) {
return _makeUnreachableInitializer([node.value]);
@@ -1482,7 +1477,7 @@ class _TreeShakerPass1 extends RemovingTransformer {
return LocalInitializer(
VariableDeclaration(null, initializer: node.value));
} else {
return removalSentinel;
return removalSentinel!;
}
}
return node;
@@ -1491,18 +1486,18 @@ class _TreeShakerPass1 extends RemovingTransformer {
@override
TreeNode visitAssertStatement(
AssertStatement node, TreeNode removalSentinel) {
AssertStatement node, TreeNode? removalSentinel) {
return _visitAssertNode(node, removalSentinel);
}
@override
TreeNode visitAssertBlock(AssertBlock node, TreeNode removalSentinel) {
TreeNode visitAssertBlock(AssertBlock node, TreeNode? removalSentinel) {
return _visitAssertNode(node, removalSentinel);
}
@override
TreeNode visitAssertInitializer(
AssertInitializer node, TreeNode removalSentinel) {
AssertInitializer node, TreeNode? removalSentinel) {
return _visitAssertNode(node, removalSentinel);
}
@@ -1520,21 +1515,21 @@ class _TreeShakerPass1 extends RemovingTransformer {
// Returns Block corresponding to the given extended bool literal,
// or null if the expression is a simple bool literal.
Block _getExtendedBoolLiteralBlock(Expression expr) =>
Block? _getExtendedBoolLiteralBlock(Expression expr) =>
(expr is BoolLiteral) ? null : (expr as BlockExpression).body;
@override
TreeNode visitIfStatement(IfStatement node, TreeNode removalSentinel) {
TreeNode visitIfStatement(IfStatement node, TreeNode? removalSentinel) {
final condition = transform(node.condition);
if (_isExtendedBoolLiteral(condition)) {
final bool conditionValue = _getExtendedBoolLiteralValue(condition);
final Block conditionBlock = _getExtendedBoolLiteralBlock(condition);
ast.Statement body;
final Block? conditionBlock = _getExtendedBoolLiteralBlock(condition);
ast.Statement? body;
if (conditionValue) {
body = transform(node.then);
} else {
if (node.otherwise != null) {
body = transformOrRemoveStatement(node.otherwise);
body = transformOrRemoveStatement(node.otherwise!);
}
}
if (conditionBlock != null) {
@@ -1549,7 +1544,7 @@ class _TreeShakerPass1 extends RemovingTransformer {
node.condition = condition..parent = node;
node.then = transform(node.then)..parent = node;
if (node.otherwise != null) {
node.otherwise = transformOrRemoveStatement(node.otherwise);
node.otherwise = transformOrRemoveStatement(node.otherwise!);
node.otherwise?.parent = node;
}
return node;
@@ -1557,7 +1552,7 @@ class _TreeShakerPass1 extends RemovingTransformer {
@override
visitConditionalExpression(
ConditionalExpression node, TreeNode removalSentinel) {
ConditionalExpression node, TreeNode? removalSentinel) {
final condition = transform(node.condition);
if (_isExtendedBoolLiteral(condition)) {
final bool value = _getExtendedBoolLiteralValue(condition);
@@ -1578,7 +1573,7 @@ class _TreeShakerPass1 extends RemovingTransformer {
}
@override
TreeNode visitNot(Not node, TreeNode removalSentinel) {
TreeNode visitNot(Not node, TreeNode? removalSentinel) {
node.transformOrRemoveChildren(this);
final operand = node.operand;
if (_isExtendedBoolLiteral(operand)) {
@@ -1595,7 +1590,7 @@ class _TreeShakerPass1 extends RemovingTransformer {
@override
TreeNode visitLogicalExpression(
LogicalExpression node, TreeNode removalSentinel) {
LogicalExpression node, TreeNode? removalSentinel) {
final left = transform(node.left);
final operatorEnum = node.operatorEnum;
if (_isExtendedBoolLiteral(left)) {
@@ -1621,8 +1616,8 @@ class _TreeShakerPass1 extends RemovingTransformer {
}
@override
TreeNode visitIsExpression(IsExpression node, TreeNode removalSentinel) {
TypeCheck check = shaker.typeFlowAnalysis.isTest(node);
TreeNode visitIsExpression(IsExpression node, TreeNode? removalSentinel) {
TypeCheck? check = shaker.typeFlowAnalysis.isTest(node);
if (check != null && (check.alwaysFail || check.alwaysPass)) {
final operand = transform(node.operand);
final result = BoolLiteral(!check.alwaysFail)
@@ -1634,9 +1629,9 @@ class _TreeShakerPass1 extends RemovingTransformer {
}
@override
TreeNode visitAsExpression(AsExpression node, TreeNode removalSentinel) {
TreeNode visitAsExpression(AsExpression node, TreeNode? removalSentinel) {
node.transformOrRemoveChildren(this);
TypeCheck check = shaker.typeFlowAnalysis.explicitCast(node);
TypeCheck? check = shaker.typeFlowAnalysis.explicitCast(node);
if (check != null && check.alwaysPass) {
return StaticInvocation(
unsafeCast, Arguments([node.operand], types: [node.type]))
@@ -1646,9 +1641,9 @@ class _TreeShakerPass1 extends RemovingTransformer {
}
@override
TreeNode visitNullCheck(NullCheck node, TreeNode removalSentinel) {
TreeNode visitNullCheck(NullCheck node, TreeNode? removalSentinel) {
node.transformOrRemoveChildren(this);
final nullTest = _getNullTest(node);
final nullTest = _getNullTest(node)!;
if (nullTest.isAlwaysNotNull) {
return StaticInvocation(
unsafeCast,
@@ -1659,12 +1654,9 @@ class _TreeShakerPass1 extends RemovingTransformer {
return node;
}
Procedure get unsafeCast {
_unsafeCast ??= shaker.typeFlowAnalysis.environment.coreTypes.index
.getTopLevelMember('dart:_internal', 'unsafeCast');
assert(_unsafeCast != null);
return _unsafeCast;
}
late final Procedure unsafeCast = shaker
.typeFlowAnalysis.environment.coreTypes.index
.getTopLevelProcedure('dart:_internal', 'unsafeCast');
}
/// The second pass of [TreeShaker]. It is called after set of used
@@ -1680,7 +1672,7 @@ class _TreeShakerPass2 extends RemovingTransformer {
void transformComponent(Component component) {
component.transformOrRemoveChildren(this);
for (Source source in component.uriToSource.values) {
source?.constantCoverageConstructors?.removeWhere((Reference reference) {
source.constantCoverageConstructors?.removeWhere((Reference reference) {
Member node = reference.asMember;
return !shaker.isMemberUsed(node);
});
@@ -1688,7 +1680,7 @@ class _TreeShakerPass2 extends RemovingTransformer {
}
@override
TreeNode visitLibrary(Library node, TreeNode removalSentinel) {
TreeNode visitLibrary(Library node, TreeNode? removalSentinel) {
node.transformOrRemoveChildren(this);
// The transformer API does not iterate over `Library.additionalExports`,
// so we manually delete the references to shaken nodes.
@@ -1708,12 +1700,12 @@ class _TreeShakerPass2 extends RemovingTransformer {
}
@override
Typedef visitTypedef(Typedef node, TreeNode removalSentinel) {
return shaker.isTypedefUsed(node) ? node : removalSentinel;
TreeNode visitTypedef(Typedef node, TreeNode? removalSentinel) {
return shaker.isTypedefUsed(node) ? node : removalSentinel!;
}
@override
Class visitClass(Class node, TreeNode removalSentinel) {
TreeNode visitClass(Class node, TreeNode? removalSentinel) {
if (!shaker.isClassUsed(node)) {
debugPrint('Dropped class ${node.name}');
// Ensure that kernel file writer will not be able to
@@ -1724,7 +1716,7 @@ class _TreeShakerPass2 extends RemovingTransformer {
"been repurposed for ${node.reference.node}.");
node.reference.canonicalName?.unbind();
Statistics.classesDropped++;
return removalSentinel; // Remove the class.
return removalSentinel!; // Remove the class.
}
if (!shaker.isClassUsedInType(node)) {
@@ -1755,7 +1747,7 @@ class _TreeShakerPass2 extends RemovingTransformer {
}
@override
Member defaultMember(Member node, TreeNode removalSentinel) {
TreeNode defaultMember(Member node, TreeNode? removalSentinel) {
if (!shaker.isMemberUsed(node)) {
// Ensure that kernel file writer will not be able to
// write a dangling reference to the deleted member.
@@ -1767,10 +1759,10 @@ class _TreeShakerPass2 extends RemovingTransformer {
node.getterReference.canonicalName?.unbind();
if (node.hasSetter) {
assert(
node.setterReference.node == node,
node.setterReference!.node == node,
"Trying to remove canonical name from reference on $node which "
"has been repurposed for ${node.setterReference.node}.");
node.setterReference.canonicalName?.unbind();
"has been repurposed for ${node.setterReference!.node}.");
node.setterReference!.canonicalName?.unbind();
}
} else {
assert(
@@ -1780,13 +1772,13 @@ class _TreeShakerPass2 extends RemovingTransformer {
node.reference.canonicalName?.unbind();
}
Statistics.membersDropped++;
return removalSentinel;
return removalSentinel!;
}
if (!shaker.isMemberBodyReachable(node)) {
if (node is Procedure) {
// Remove body of unused member.
if (!node.isStatic && node.enclosingClass.isAbstract) {
if (!node.isStatic && node.enclosingClass!.isAbstract) {
node.isAbstract = true;
node.function.body = null;
} else {
@@ -1829,7 +1821,7 @@ class _TreeShakerPass2 extends RemovingTransformer {
}
@override
Extension visitExtension(Extension node, TreeNode removalSentinel) {
TreeNode visitExtension(Extension node, TreeNode? removalSentinel) {
if (shaker.isExtensionUsed(node)) {
int writeIndex = 0;
for (int i = 0; i < node.members.length; ++i) {
@@ -1840,7 +1832,7 @@ class _TreeShakerPass2 extends RemovingTransformer {
// member was already removed or it will be removed later.
final Reference memberReference = descriptor.member;
final bool isBound = memberReference.node != null;
if (isBound && shaker.isMemberUsed(memberReference.node)) {
if (isBound && shaker.isMemberUsed(memberReference.asMember)) {
node.members[writeIndex++] = descriptor;
}
}
@@ -1850,7 +1842,7 @@ class _TreeShakerPass2 extends RemovingTransformer {
assert(node.members.length > 0);
return node;
}
return removalSentinel;
return removalSentinel!;
}
void _makeUnreachableBody(FunctionNode function) {
@@ -1871,7 +1863,7 @@ class _TreeShakerPass2 extends RemovingTransformer {
}
@override
TreeNode defaultTreeNode(TreeNode node, TreeNode removalSentinel) {
TreeNode defaultTreeNode(TreeNode node, TreeNode? removalSentinel) {
return node; // Do not traverse into other nodes.
}
}
+62 -66
View File
@@ -2,10 +2,7 @@
// 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.
// @dart=2.9
/// Declares the type system used by global type flow analysis.
library vm.transformations.type_flow.types;
import 'dart:core' hide Type;
@@ -138,10 +135,7 @@ abstract class TypeHierarchy extends TypesBuilder
/// values can flow through the program.
Type specializeTypeCone(TFClass base, {bool allowWideCone = false});
Type _cachedIntType;
Type get intType {
return _cachedIntType ??= fromStaticType(coreTypes.intLegacyRawType, true);
}
late final Type intType = fromStaticType(coreTypes.intLegacyRawType, true);
}
/// Base class for type expressions.
@@ -151,7 +145,7 @@ abstract class TypeExpr {
/// Returns computed type of this type expression.
/// [types] is the list of types computed for the statements in the summary.
Type getComputedType(List<Type> types);
Type getComputedType(List<Type?> types);
}
/// Kind of a subtype test: subtype/cast/'as' test or instance check/'is' test.
@@ -174,7 +168,7 @@ abstract class Type extends TypeExpr {
/// Create a type representing arbitrary nullable object (`dynamic`).
factory Type.nullableAny() => new NullableType(const AnyType());
Class getConcreteClass(TypeHierarchy typeHierarchy) => null;
Class? getConcreteClass(TypeHierarchy typeHierarchy) => null;
bool isSubtypeOf(TypeHierarchy typeHierarchy, Class cls) => false;
@@ -185,7 +179,7 @@ abstract class Type extends TypeExpr {
RuntimeType runtimeType, SubtypeTestKind kind);
@override
Type getComputedType(List<Type> types) => this;
Type getComputedType(List<Type?> types) => this;
/// Order of precedence for evaluation of union/intersection.
int get order;
@@ -260,7 +254,6 @@ class NullableType extends Type {
final Type baseType;
NullableType(this.baseType) {
assert(baseType != null);
assert(baseType is! NullableType);
}
@@ -387,7 +380,9 @@ class AnyType extends Type {
class SetType extends Type {
/// List of concrete types, sorted by classId.
final List<ConcreteType> types;
int _hashCode;
@override
late final int hashCode = _computeHashCode();
/// Creates a new SetType using list of concrete types sorted by classId.
SetType(this.types) {
@@ -395,9 +390,6 @@ class SetType extends Type {
assert(isSorted(types));
}
@override
int get hashCode => _hashCode ??= _computeHashCode();
int _computeHashCode() {
int hash = 1237;
for (var t in types) {
@@ -470,8 +462,8 @@ class SetType extends Type {
return types;
}
static List<ConcreteType> _intersectLists(
List<ConcreteType> types1, List<ConcreteType> types2) {
static List<ConcreteType> _intersectLists(List<ConcreteType> types1,
List<ConcreteType> types2, TypeHierarchy typeHierarchy) {
int i1 = 0;
int i2 = 0;
List<ConcreteType> types = <ConcreteType>[];
@@ -491,9 +483,9 @@ class SetType extends Type {
t2.constant == null) {
types.add(t1);
} else {
final intersect = t1.intersection(t2, null);
final intersect = t1.intersection(t2, typeHierarchy);
if (intersect is! EmptyType) {
types.add(intersect);
types.add(intersect as ConcreteType);
}
}
++i1;
@@ -558,7 +550,8 @@ class SetType extends Type {
return other.intersection(this, typeHierarchy);
}
if (other is SetType) {
List<ConcreteType> list = _intersectLists(types, other.types);
List<ConcreteType> list =
_intersectLists(types, other.types, typeHierarchy);
final size = list.length;
if (size == 0) {
return const EmptyType();
@@ -594,7 +587,7 @@ class ConeType extends Type {
ConeType(this.cls);
@override
Class getConcreteClass(TypeHierarchy typeHierarchy) => typeHierarchy
Class? getConcreteClass(TypeHierarchy typeHierarchy) => typeHierarchy
.specializeTypeCone(cls, allowWideCone: true)
.getConcreteClass(typeHierarchy);
@@ -696,7 +689,7 @@ class WideConeType extends ConeType {
WideConeType(TFClass cls) : super(cls);
@override
Class getConcreteClass(TypeHierarchy typeHierarchy) => null;
Class? getConcreteClass(TypeHierarchy typeHierarchy) => null;
@override
int get hashCode => (cls.id + 41) & kHashMask;
@@ -783,7 +776,9 @@ class WideConeType extends ConeType {
/// or `null` object).
class ConcreteType extends Type implements Comparable<ConcreteType> {
final TFClass cls;
int _hashCode;
@override
late final int hashCode = _computeHashCode();
// May be null if there are no type arguments constraints. The type arguments
// should represent type sets, i.e. `UnknownType` or `RuntimeType`. The type
@@ -796,19 +791,19 @@ class ConcreteType extends Type implements Comparable<ConcreteType> {
// 'numImmediateTypeArgs' is the length of the prefix of 'typeArgs' which
// holds the type arguments to the class itself.
final int numImmediateTypeArgs;
final List<Type> typeArgs;
final List<Type>? typeArgs;
// May be null if constant value is not inferred.
final Constant constant;
final Constant? constant;
ConcreteType(this.cls, [List<Type> typeArgs_, this.constant])
ConcreteType(this.cls, [List<Type>? typeArgs_, this.constant])
: typeArgs = typeArgs_,
numImmediateTypeArgs =
typeArgs_ != null ? cls.classNode.typeParameters.length : 0 {
// TODO(alexmarkov): support closures
assert(!cls.classNode.isAbstract);
assert(typeArgs == null || cls.classNode.typeParameters.isNotEmpty);
assert(typeArgs == null || typeArgs.any((t) => t is RuntimeType));
assert(typeArgs == null || typeArgs!.any((t) => t is RuntimeType));
}
ConcreteType get raw => cls.concreteType;
@@ -839,7 +834,7 @@ class ConcreteType extends Type implements Comparable<ConcreteType> {
if (rhs.typeArguments.isEmpty) return true;
List<Type> usableTypeArgs = typeArgs;
List<Type>? usableTypeArgs = typeArgs;
if (usableTypeArgs == null) {
if (cls.classNode.typeParameters.isEmpty) {
usableTypeArgs =
@@ -862,7 +857,7 @@ class ConcreteType extends Type implements Comparable<ConcreteType> {
}
assert(ta is RuntimeType);
if (!ta.isSubtypeOfRuntimeType(
typeHierarchy, runtimeType.typeArgs[i], SubtypeTestKind.Subtype)) {
typeHierarchy, runtimeType.typeArgs![i], SubtypeTestKind.Subtype)) {
return false;
}
}
@@ -877,29 +872,26 @@ class ConcreteType extends Type implements Comparable<ConcreteType> {
} else {
final interfaceOffset = typeHierarchy.genericInterfaceOffsetFor(
cls.classNode, typeHierarchy.coreTypes.futureClass);
typeArg = typeArgs[interfaceOffset];
typeArg = typeArgs![interfaceOffset];
}
final RuntimeType lhs =
typeArg is RuntimeType ? typeArg : RuntimeType(DynamicType(), null);
return lhs.isSubtypeOfRuntimeType(
typeHierarchy, runtimeType.typeArgs[0], SubtypeTestKind.Subtype);
typeHierarchy, runtimeType.typeArgs![0], SubtypeTestKind.Subtype);
} else {
return isSubtypeOfRuntimeType(
typeHierarchy, runtimeType.typeArgs[0], SubtypeTestKind.Subtype);
typeHierarchy, runtimeType.typeArgs![0], SubtypeTestKind.Subtype);
}
}
return false;
}
@override
int get hashCode => _hashCode ??= _computeHashCode();
int _computeHashCode() {
int hash = cls.hashCode ^ 0x1234 & kHashMask;
// We only need to hash the first type arguments vector, since the type
// arguments of the implemented interfaces are implied by it.
for (int i = 0; i < numImmediateTypeArgs; ++i) {
hash = (((hash * 31) & kHashMask) + typeArgs[i].hashCode) & kHashMask;
hash = (((hash * 31) & kHashMask) + typeArgs![i].hashCode) & kHashMask;
}
hash = ((hash * 31) & kHashMask) + constant.hashCode;
return hash;
@@ -915,7 +907,7 @@ class ConcreteType extends Type implements Comparable<ConcreteType> {
}
if (this.typeArgs != null) {
for (int i = 0; i < numImmediateTypeArgs; ++i) {
if (this.typeArgs[i] != other.typeArgs[i]) {
if (this.typeArgs![i] != other.typeArgs![i]) {
return false;
}
}
@@ -942,10 +934,10 @@ class ConcreteType extends Type implements Comparable<ConcreteType> {
final StringBuffer buf = new StringBuffer();
buf.write("_T (${cls}");
if (typeArgs != null) {
buf.write("<${typeArgs.take(numImmediateTypeArgs).join(', ')}>");
buf.write("<${typeArgs!.take(numImmediateTypeArgs).join(', ')}>");
}
if (constant != null) {
buf.write(", ${nodeToText(constant)}");
buf.write(", ${nodeToText(constant!)}");
}
buf.write(")");
return buf.toString();
@@ -997,17 +989,21 @@ class ConcreteType extends Type implements Comparable<ConcreteType> {
return this;
}
List<Type> mergedTypeArgs;
if (typeArgs == null) {
mergedTypeArgs = other.typeArgs;
} else if (other.typeArgs == null) {
mergedTypeArgs = typeArgs;
List<Type>? mergedTypeArgs;
final thisTypeArgs = this.typeArgs;
final otherTypeArgs = other.typeArgs;
if (thisTypeArgs == null) {
mergedTypeArgs = otherTypeArgs;
} else if (otherTypeArgs == null) {
mergedTypeArgs = thisTypeArgs;
} else {
mergedTypeArgs = new List<Type>.filled(typeArgs.length, null);
assert(thisTypeArgs.length == otherTypeArgs.length);
mergedTypeArgs =
new List<Type>.filled(thisTypeArgs.length, const EmptyType());
bool hasRuntimeType = false;
for (int i = 0; i < typeArgs.length; ++i) {
for (int i = 0; i < thisTypeArgs.length; ++i) {
final merged =
typeArgs[i].intersection(other.typeArgs[i], typeHierarchy);
thisTypeArgs[i].intersection(otherTypeArgs[i], typeHierarchy);
if (merged is EmptyType) {
return const EmptyType();
} else if (merged is RuntimeType) {
@@ -1020,7 +1016,7 @@ class ConcreteType extends Type implements Comparable<ConcreteType> {
}
}
Constant mergedConstant;
Constant? mergedConstant;
if (constant == null) {
mergedConstant = other.constant;
} else if (other.constant == null || constant == other.constant) {
@@ -1062,7 +1058,7 @@ class RuntimeType extends Type {
final DartType _type; // Doesn't contain type args.
final int numImmediateTypeArgs;
final List<RuntimeType> typeArgs;
final List<RuntimeType>? typeArgs;
RuntimeType(DartType type, this.typeArgs)
: _type = type,
@@ -1070,14 +1066,12 @@ class RuntimeType extends Type {
? type.classNode.typeParameters.length
: (type is FutureOrType ? 1 : 0) {
if (_type is InterfaceType && numImmediateTypeArgs > 0) {
assert(typeArgs != null);
assert(typeArgs.length >= numImmediateTypeArgs);
assert(typeArgs!.length >= numImmediateTypeArgs);
assert((_type as InterfaceType)
.typeArguments
.every((t) => t == const DynamicType()));
} else if (_type is FutureOrType) {
assert(typeArgs != null);
assert(typeArgs.length >= numImmediateTypeArgs);
assert(typeArgs!.length >= numImmediateTypeArgs);
DartType typeArgument = (_type as FutureOrType).typeArgument;
assert(typeArgument == const DynamicType());
} else {
@@ -1098,25 +1092,27 @@ class RuntimeType extends Type {
final type = _type;
if (type is InterfaceType && typeArgs != null) {
final klass = type.classNode;
final typeArguments = typeArgs
final typeArguments = typeArgs!
.take(klass.typeParameters.length)
.map((pt) => pt.representedType)
.toList();
return new InterfaceType(klass, type.nullability, typeArguments);
} else if (type is FutureOrType) {
return new FutureOrType(typeArgs[0].representedType, type.nullability);
return new FutureOrType(typeArgs![0].representedType, type.nullability);
} else {
return type;
}
}
@override
int get hashCode {
late final int hashCode = _computeHashCode();
int _computeHashCode() {
int hash = _type.hashCode ^ 0x1234 & kHashMask;
// Only hash by the type arguments of the class. The type arguments of
// supertypes are are implied by them.
for (int i = 0; i < numImmediateTypeArgs; ++i) {
hash = (((hash * 31) & kHashMask) + typeArgs[i].hashCode) & kHashMask;
hash = (((hash * 31) & kHashMask) + typeArgs![i].hashCode) & kHashMask;
}
return hash;
}
@@ -1127,7 +1123,7 @@ class RuntimeType extends Type {
if (other is RuntimeType) {
if (other._type != _type) return false;
assert(numImmediateTypeArgs == other.numImmediateTypeArgs);
return typeArgs == null || listEquals(typeArgs, other.typeArgs);
return typeArgs == null || listEquals(typeArgs!, other.typeArgs!);
}
return false;
}
@@ -1139,7 +1135,7 @@ class RuntimeType extends Type {
: "${nodeToText(_type)}";
final typeArgsStrs = (numImmediateTypeArgs == 0)
? ""
: "<${typeArgs.take(numImmediateTypeArgs).map((t) => "$t").join(", ")}>";
: "<${typeArgs!.take(numImmediateTypeArgs).map((t) => "$t").join(", ")}>";
final nullability = _type.nullability.suffix;
return "$head$typeArgsStrs$nullability";
}
@@ -1200,15 +1196,15 @@ class RuntimeType extends Type {
if (_type is InterfaceType) {
Class thisClass = (_type as InterfaceType).classNode;
if (thisClass == typeHierarchy.coreTypes.futureClass) {
return typeArgs[0].isSubtypeOfRuntimeType(
typeHierarchy, runtimeType.typeArgs[0], SubtypeTestKind.Subtype);
return typeArgs![0].isSubtypeOfRuntimeType(
typeHierarchy, runtimeType.typeArgs![0], SubtypeTestKind.Subtype);
} else {
return isSubtypeOfRuntimeType(
typeHierarchy, runtimeType.typeArgs[0], SubtypeTestKind.Subtype);
typeHierarchy, runtimeType.typeArgs![0], SubtypeTestKind.Subtype);
}
} else if (_type is FutureOrType) {
return typeArgs[0].isSubtypeOfRuntimeType(
typeHierarchy, runtimeType.typeArgs[0], SubtypeTestKind.Subtype);
return typeArgs![0].isSubtypeOfRuntimeType(
typeHierarchy, runtimeType.typeArgs![0], SubtypeTestKind.Subtype);
}
}
@@ -1236,7 +1232,7 @@ class RuntimeType extends Type {
return true;
}
List<Type> usableTypeArgs = typeArgs;
List<Type>? usableTypeArgs = typeArgs;
if (usableTypeArgs == null) {
assert(thisClass.typeParameters.isEmpty);
usableTypeArgs =
@@ -1248,7 +1244,7 @@ class RuntimeType extends Type {
runtimeType.numImmediateTypeArgs);
for (int i = 0; i < runtimeType.numImmediateTypeArgs; ++i) {
if (!usableTypeArgs[interfaceOffset + i].isSubtypeOfRuntimeType(
typeHierarchy, runtimeType.typeArgs[i], SubtypeTestKind.Subtype)) {
typeHierarchy, runtimeType.typeArgs![i], SubtypeTestKind.Subtype)) {
return false;
}
}
@@ -2,8 +2,6 @@
// 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.
// @dart=2.9
import 'package:kernel/ast.dart';
import 'package:kernel/core_types.dart';
import 'package:kernel/external_name.dart' show getExternalName;
@@ -30,12 +28,12 @@ class UnboxingInfoManager {
_coreTypes = typeFlowAnalysis.environment.coreTypes,
_nativeCodeOracle = typeFlowAnalysis.nativeCodeOracle;
UnboxingInfoMetadata getUnboxingInfoOfMember(Member member) {
final UnboxingInfoMetadata info = _memberInfo[member];
UnboxingInfoMetadata? getUnboxingInfoOfMember(Member member) {
final UnboxingInfoMetadata? info = _memberInfo[member];
if (member is Procedure && member.isGetter) {
// Remove placeholder parameter info slot for setters that the getter is
// grouped with.
return UnboxingInfoMetadata(0)..returnInfo = info.returnInfo;
return UnboxingInfoMetadata(0)..returnInfo = info!.returnInfo;
}
return info;
}
@@ -81,8 +79,8 @@ class UnboxingInfoManager {
? (member.hasSetter ? 1 : 0)
: member is Procedure && member.isGetter
? 1
: member.function.requiredParameterCount;
UnboxingInfoMetadata info;
: member.function!.requiredParameterCount;
UnboxingInfoMetadata? info;
if (member.isInstanceMember) {
int selectorId =
member is Field || member is Procedure && member.isGetter
@@ -121,20 +119,18 @@ class UnboxingInfoManager {
void _updateUnboxingInfoOfMember(
Member member, TypeFlowAnalysis typeFlowAnalysis) {
if (typeFlowAnalysis.isMemberUsed(member)) {
final UnboxingInfoMetadata unboxingInfo = _memberInfo[member];
final UnboxingInfoMetadata unboxingInfo = _memberInfo[member]!;
if (_cannotUnbox(member)) {
unboxingInfo.unboxedArgsInfo.length = 0;
unboxingInfo.returnInfo = UnboxingInfoMetadata.kBoxed;
return;
}
if (member is Procedure || member is Constructor) {
final Args<Type> argTypes = typeFlowAnalysis.argumentTypes(member);
assert(argTypes != null);
final Args<Type> argTypes = typeFlowAnalysis.argumentTypes(member)!;
final int firstParamIndex =
numTypeParams(member) + (hasReceiverArg(member) ? 1 : 0);
final positionalParams = member.function.positionalParameters;
final positionalParams = member.function!.positionalParameters;
assert(argTypes.positionalCount ==
firstParamIndex + positionalParams.length);
@@ -2,12 +2,11 @@
// 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.
// @dart=2.9
/// Declares miscellaneous utility functions and constants for type flow
/// analysis.
library vm.transformations.type_flow.utils;
import 'package:collection/collection.dart' show IterableExtension;
import 'package:kernel/ast.dart';
import 'package:kernel/src/printer.dart';
@@ -123,9 +122,8 @@ bool isSorted(List list) {
return true;
}
VariableDeclaration findNamedParameter(FunctionNode function, String name) {
return function.namedParameters
.firstWhere((p) => p.name == name, orElse: () => null);
VariableDeclaration? findNamedParameter(FunctionNode function, String name) {
return function.namedParameters.firstWhereOrNull((p) => p.name == name);
}
class Histogram<K> {
@@ -143,7 +141,7 @@ class Histogram<K> {
print(
'-------------------------------------------------------------------');
List<K> keys = values.keys.toList();
keys.sort((k1, k2) => values[k1].compareTo(values[k2]));
keys.sort((k1, k2) => values[k1]!.compareTo(values[k2]!));
final cut = keys.length < n ? 0 : keys.length - n;
for (int i = keys.length - 1; i >= cut; --i) {
final k = keys[i];
@@ -376,7 +374,7 @@ const nullabilitySuffix = {
};
extension NullabilitySuffix on Nullability {
String get suffix => nullabilitySuffix[this];
String get suffix => nullabilitySuffix[this]!;
}
bool mayHaveSideEffects(Expression node) {
+1
View File
@@ -18,6 +18,7 @@ dependencies:
meta:
path: ../meta
package_config: any
collection: ^1.15.0
dev_dependencies:
expect:
@@ -60,7 +60,7 @@ class FakeEntryPointsListener implements EntryPointsListener {
void recordMemberCalledViaThis(Member target) {}
@override
void recordTearOff(Procedure target) {}
void recordTearOff(Member target) {}
}
class PrintSummaries extends RecursiveVisitor {
@@ -78,7 +78,7 @@ class PrintSummaries extends RecursiveVisitor {
typesBuilder,
new NativeCodeOracle(
null, new ConstantPragmaAnnotationParser(coreTypes)),
new GenericInterfacesInfoImpl(hierarchy),
new GenericInterfacesInfoImpl(coreTypes, hierarchy),
/*_protobufHandler=*/ null);
}