From 278815b192e6cb986ee9ef77c99788819a43e02f Mon Sep 17 00:00:00 2001 From: Mayank Patke Date: Tue, 25 Oct 2022 19:24:19 +0000 Subject: [PATCH] [dart2js] Add abstract value domain to distinguish uncomputed values. Normal dart2js invocations will continue using the existing abstract value domains with `emptyType` as the initial type for type graph nodes. When an appropriate debug flag is passed, all abstract values will be wrapped so that the underlying empty type is only used when a value is known to be empty. Abstract values which have not yet been computed will print as "[uncomputed]" in order to aid in debugging but will otherwise behave like the empty type during type graph construction. Change-Id: I1ec41e42e8b566a0a6bfe969c2ff96f4e53d5f4e Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/243844 Commit-Queue: Mayank Patke Reviewed-by: Stephen Adams --- pkg/compiler/lib/src/compiler.dart | 7 +- .../src/inferrer/abstract_value_domain.dart | 6 + pkg/compiler/lib/src/inferrer/computable.dart | 673 ++++++++++++++++++ .../lib/src/inferrer/powersets/powersets.dart | 2 +- pkg/compiler/lib/src/inferrer/trivial.dart | 2 +- .../lib/src/inferrer/type_graph_nodes.dart | 26 +- .../lib/src/inferrer/typemasks/masks.dart | 2 +- pkg/compiler/lib/src/inferrer/wrapped.dart | 2 +- .../powersets/powersets.dart | 2 +- .../src/inferrer_experimental/trivial.dart | 2 +- .../type_graph_nodes.dart | 26 +- .../typemasks/masks.dart | 2 +- .../src/inferrer_experimental/wrapped.dart | 2 +- 13 files changed, 719 insertions(+), 35 deletions(-) create mode 100644 pkg/compiler/lib/src/inferrer/computable.dart diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart index a5686855282..951a49edcc7 100644 --- a/pkg/compiler/lib/src/compiler.dart +++ b/pkg/compiler/lib/src/compiler.dart @@ -38,8 +38,9 @@ import 'elements/entities.dart'; import 'enqueue.dart' show Enqueuer; import 'environment.dart'; import 'inferrer/abstract_value_strategy.dart'; -import 'inferrer/trivial.dart' show TrivialAbstractValueStrategy; +import 'inferrer/computable.dart' show ComputableAbstractValueStrategy; import 'inferrer/powersets/powersets.dart' show PowersetStrategy; +import 'inferrer/trivial.dart' show TrivialAbstractValueStrategy; import 'inferrer/typemasks/masks.dart' show TypeMaskStrategy; import 'inferrer/types.dart' show GlobalTypeInferenceResults, GlobalTypeInferenceTask; @@ -189,6 +190,10 @@ class Compiler } else if (options.experimentalPowersets) { abstractValueStrategy = PowersetStrategy(abstractValueStrategy); } + if (options.debugGlobalInference) { + abstractValueStrategy = + ComputableAbstractValueStrategy(abstractValueStrategy); + } CompilerTask kernelFrontEndTask; selfTask = GenericTask('self', measurer); diff --git a/pkg/compiler/lib/src/inferrer/abstract_value_domain.dart b/pkg/compiler/lib/src/inferrer/abstract_value_domain.dart index 0df88c84322..d27e038f33d 100644 --- a/pkg/compiler/lib/src/inferrer/abstract_value_domain.dart +++ b/pkg/compiler/lib/src/inferrer/abstract_value_domain.dart @@ -92,6 +92,12 @@ class AbstractValueWithPrecision { /// A system that implements an abstraction over runtime values. abstract class AbstractValueDomain { + /// The [AbstractValue] that represents a type which has not yet been + /// computed. Type graph nodes may carry this type during construction of the + /// graph, but it should be replaced by a computed type by the time the graph + /// is queried. + AbstractValue get uncomputedType => emptyType; + /// The [AbstractValue] that represents an unknown runtime value. This /// includes values internal to the implementation, such as late sentinels. AbstractValue get internalTopType; diff --git a/pkg/compiler/lib/src/inferrer/computable.dart b/pkg/compiler/lib/src/inferrer/computable.dart new file mode 100644 index 00000000000..b9380de8ef0 --- /dev/null +++ b/pkg/compiler/lib/src/inferrer/computable.dart @@ -0,0 +1,673 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../constants/values.dart' show ConstantValue, PrimitiveConstantValue; +import '../elements/entities.dart'; +import '../elements/names.dart'; +import '../elements/types.dart' show DartType; +import '../ir/class_relation.dart'; +import '../serialization/serialization.dart'; +import '../universe/selector.dart'; +import '../universe/world_builder.dart'; +import '../universe/use.dart'; +import '../world.dart'; +import 'abstract_value_domain.dart'; +import 'abstract_value_strategy.dart'; + +class ComputableAbstractValue implements AbstractValue { + final AbstractValue? _wrappedValue; + const ComputableAbstractValue(this._wrappedValue); + + bool get isComputed => _wrappedValue != null; + bool get isUncomputed => _wrappedValue == null; + + AbstractValue _unwrapOrThrow() => isUncomputed + ? throw StateError("Uncomputed abstract value") + : _wrappedValue!; + + AbstractValue _unwrapOrEmpty(AbstractValueDomain wrappedDomain) => + isUncomputed ? wrappedDomain.emptyType : _wrappedValue!; + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + if (other is ComputableAbstractValue) { + return _wrappedValue == other._wrappedValue; + } + return false; + } + + @override + int get hashCode => _wrappedValue.hashCode; + + @override + String toString() => + isUncomputed ? "[uncomputed]" : _wrappedValue!.toString(); +} + +class ComputableAbstractValueDomain with AbstractValueDomain { + final AbstractValueDomain _wrappedDomain; + const ComputableAbstractValueDomain(this._wrappedDomain); + + AbstractValue _unwrap(ComputableAbstractValue value) => + value._unwrapOrEmpty(_wrappedDomain); + + AbstractValue? _unwrapOrNull(ComputableAbstractValue? value) => + value?._unwrapOrEmpty(_wrappedDomain); + + @override + AbstractValue get uncomputedType => const ComputableAbstractValue(null); + + @override + AbstractValue get internalTopType => + ComputableAbstractValue(_wrappedDomain.internalTopType); + + @override + AbstractValue get dynamicType => + ComputableAbstractValue(_wrappedDomain.dynamicType); + + @override + AbstractValue get typeType => + ComputableAbstractValue(_wrappedDomain.typeType); + + @override + AbstractValue get functionType => + ComputableAbstractValue(_wrappedDomain.functionType); + + @override + AbstractValue get boolType => + ComputableAbstractValue(_wrappedDomain.boolType); + + @override + AbstractValue get intType => ComputableAbstractValue(_wrappedDomain.intType); + + @override + AbstractValue get numNotIntType => + ComputableAbstractValue(_wrappedDomain.numNotIntType); + + @override + AbstractValue get numType => ComputableAbstractValue(_wrappedDomain.numType); + + @override + AbstractValue get stringType => + ComputableAbstractValue(_wrappedDomain.stringType); + + @override + AbstractValue get listType => + ComputableAbstractValue(_wrappedDomain.listType); + + @override + AbstractValue get setType => ComputableAbstractValue(_wrappedDomain.setType); + + @override + AbstractValue get mapType => ComputableAbstractValue(_wrappedDomain.mapType); + + @override + AbstractValue get nonNullType => + ComputableAbstractValue(_wrappedDomain.nonNullType); + + @override + AbstractValue get nullType => + ComputableAbstractValue(_wrappedDomain.nullType); + + @override + AbstractValue get lateSentinelType => + ComputableAbstractValue(_wrappedDomain.lateSentinelType); + + @override + AbstractValue get growableListType => + ComputableAbstractValue(_wrappedDomain.growableListType); + + @override + AbstractValue get fixedListType => + ComputableAbstractValue(_wrappedDomain.fixedListType); + + @override + AbstractValue get mutableArrayType => + ComputableAbstractValue(_wrappedDomain.mutableArrayType); + + @override + AbstractValue get uint31Type => + ComputableAbstractValue(_wrappedDomain.uint31Type); + + @override + AbstractValue get uint32Type => + ComputableAbstractValue(_wrappedDomain.uint32Type); + + @override + AbstractValue get positiveIntType => + ComputableAbstractValue(_wrappedDomain.positiveIntType); + + @override + AbstractValue get constListType => + ComputableAbstractValue(_wrappedDomain.constListType); + + @override + AbstractValue get constSetType => + ComputableAbstractValue(_wrappedDomain.constSetType); + + @override + AbstractValue get constMapType => + ComputableAbstractValue(_wrappedDomain.constMapType); + + @override + AbstractValue get emptyType => + ComputableAbstractValue(_wrappedDomain.emptyType); + + @override + AbstractValue get syncStarIterableType => + ComputableAbstractValue(_wrappedDomain.syncStarIterableType); + + @override + AbstractValue get asyncFutureType => + ComputableAbstractValue(_wrappedDomain.asyncFutureType); + + @override + AbstractValue get asyncStarStreamType => + ComputableAbstractValue(_wrappedDomain.asyncStarStreamType); + + @override + AbstractValueWithPrecision createFromStaticType(DartType type, + {ClassRelation classRelation = ClassRelation.subtype, + required bool nullable}) { + final unwrapped = _wrappedDomain.createFromStaticType(type, + classRelation: classRelation, nullable: nullable); + return AbstractValueWithPrecision( + ComputableAbstractValue(unwrapped.abstractValue), unwrapped.isPrecise); + } + + @override + AbstractValue createNonNullExact(ClassEntity cls) => + ComputableAbstractValue(_wrappedDomain.createNonNullExact(cls)); + + @override + AbstractValue createNullableExact(ClassEntity cls) => + ComputableAbstractValue(_wrappedDomain.createNullableExact(cls)); + + @override + AbstractValue createNonNullSubclass(ClassEntity cls) => + ComputableAbstractValue(_wrappedDomain.createNonNullSubclass(cls)); + + @override + AbstractValue createNonNullSubtype(ClassEntity cls) => + ComputableAbstractValue(_wrappedDomain.createNonNullSubtype(cls)); + + @override + AbstractValue createNullableSubtype(ClassEntity cls) => + ComputableAbstractValue(_wrappedDomain.createNullableSubtype(cls)); + + @override + AbstractBool isTypedArray(covariant ComputableAbstractValue value) => + _wrappedDomain.isTypedArray(_unwrap(value)); + + @override + AbstractBool couldBeTypedArray(covariant ComputableAbstractValue value) => + _wrappedDomain.couldBeTypedArray(_unwrap(value)); + + @override + AbstractValue excludeNull(covariant ComputableAbstractValue value) => + ComputableAbstractValue(_wrappedDomain.excludeNull(_unwrap(value))); + + @override + AbstractValue includeNull(covariant ComputableAbstractValue value) => + ComputableAbstractValue(_wrappedDomain.includeNull(_unwrap(value))); + + @override + AbstractValue excludeLateSentinel(covariant ComputableAbstractValue value) => + ComputableAbstractValue( + _wrappedDomain.excludeLateSentinel(_unwrap(value))); + + @override + AbstractValue includeLateSentinel(covariant ComputableAbstractValue value) => + ComputableAbstractValue( + _wrappedDomain.includeLateSentinel(_unwrap(value))); + + @override + AbstractBool containsType( + covariant ComputableAbstractValue value, ClassEntity cls) => + _wrappedDomain.containsType(_unwrap(value), cls); + + @override + AbstractBool containsOnlyType( + covariant ComputableAbstractValue value, ClassEntity cls) => + _wrappedDomain.containsOnlyType(_unwrap(value), cls); + + @override + AbstractBool isInstanceOfOrNull( + covariant ComputableAbstractValue value, ClassEntity cls) => + _wrappedDomain.isInstanceOfOrNull(_unwrap(value), cls); + + @override + AbstractBool isInstanceOf( + covariant ComputableAbstractValue value, ClassEntity cls) => + _wrappedDomain.isInstanceOf(_unwrap(value), cls); + + @override + AbstractBool isEmpty(covariant ComputableAbstractValue value) => + _wrappedDomain.isEmpty(_unwrap(value)); + + @override + AbstractBool isExact(covariant ComputableAbstractValue value) => + _wrappedDomain.isExact(_unwrap(value)); + + @override + ClassEntity? getExactClass(covariant ComputableAbstractValue value) => + _wrappedDomain.getExactClass(_unwrap(value)); + + @override + AbstractBool isNull(covariant ComputableAbstractValue value) => + _wrappedDomain.isNull(_unwrap(value)); + + @override + AbstractBool isLateSentinel(covariant ComputableAbstractValue value) => + _wrappedDomain.isLateSentinel(_unwrap(value)); + + @override + AbstractBool isPrimitive(covariant ComputableAbstractValue value) => + _wrappedDomain.isPrimitive(_unwrap(value)); + + @override + AbstractBool isPrimitiveNumber(covariant ComputableAbstractValue value) => + _wrappedDomain.isPrimitiveNumber(_unwrap(value)); + + @override + AbstractBool isPrimitiveBoolean(covariant ComputableAbstractValue value) => + _wrappedDomain.isPrimitiveBoolean(_unwrap(value)); + + @override + AbstractBool isIndexablePrimitive(covariant ComputableAbstractValue value) => + _wrappedDomain.isIndexablePrimitive(_unwrap(value)); + + @override + AbstractBool isFixedArray(covariant ComputableAbstractValue value) => + _wrappedDomain.isFixedArray(_unwrap(value)); + + @override + AbstractBool isExtendableArray(covariant ComputableAbstractValue value) => + _wrappedDomain.isExtendableArray(_unwrap(value)); + + @override + AbstractBool isMutableArray(covariant ComputableAbstractValue value) => + _wrappedDomain.isMutableArray(_unwrap(value)); + + @override + AbstractBool isMutableIndexable(covariant ComputableAbstractValue value) => + _wrappedDomain.isMutableIndexable(_unwrap(value)); + + @override + AbstractBool isArray(covariant ComputableAbstractValue value) => + _wrappedDomain.isArray(_unwrap(value)); + + @override + AbstractBool isPrimitiveString(covariant ComputableAbstractValue value) => + _wrappedDomain.isPrimitiveString(_unwrap(value)); + + @override + AbstractBool isInterceptor(covariant ComputableAbstractValue value) => + _wrappedDomain.isInterceptor(_unwrap(value)); + + @override + AbstractBool isInteger(covariant ComputableAbstractValue value) => + _wrappedDomain.isInteger(_unwrap(value)); + + @override + AbstractBool isUInt32(covariant ComputableAbstractValue value) => + _wrappedDomain.isUInt32(_unwrap(value)); + + @override + AbstractBool isUInt31(covariant ComputableAbstractValue value) => + _wrappedDomain.isUInt31(_unwrap(value)); + + @override + AbstractBool isPositiveInteger(covariant ComputableAbstractValue value) => + _wrappedDomain.isPositiveInteger(_unwrap(value)); + + @override + AbstractBool isPositiveIntegerOrNull( + covariant ComputableAbstractValue value) => + _wrappedDomain.isPositiveIntegerOrNull(_unwrap(value)); + + @override + AbstractBool isIntegerOrNull(covariant ComputableAbstractValue value) => + _wrappedDomain.isIntegerOrNull(_unwrap(value)); + + @override + AbstractBool isNumber(covariant ComputableAbstractValue value) => + _wrappedDomain.isNumber(_unwrap(value)); + + @override + AbstractBool isNumberOrNull(covariant ComputableAbstractValue value) => + _wrappedDomain.isNumberOrNull(_unwrap(value)); + + @override + AbstractBool isBoolean(covariant ComputableAbstractValue value) => + _wrappedDomain.isBoolean(_unwrap(value)); + + @override + AbstractBool isBooleanOrNull(covariant ComputableAbstractValue value) => + _wrappedDomain.isBooleanOrNull(_unwrap(value)); + + @override + AbstractBool isString(covariant ComputableAbstractValue value) => + _wrappedDomain.isString(_unwrap(value)); + + @override + AbstractBool isStringOrNull(covariant ComputableAbstractValue value) => + _wrappedDomain.isStringOrNull(_unwrap(value)); + + @override + AbstractBool isPrimitiveOrNull(covariant ComputableAbstractValue value) => + _wrappedDomain.isPrimitiveOrNull(_unwrap(value)); + + @override + AbstractBool isTruthy(covariant ComputableAbstractValue value) => + _wrappedDomain.isTruthy(_unwrap(value)); + + @override + AbstractValue union(covariant ComputableAbstractValue a, + covariant ComputableAbstractValue b) => + ComputableAbstractValue(_wrappedDomain.union(_unwrap(a), _unwrap(b))); + + @override + AbstractValue unionOfMany(covariant Iterable values) => + ComputableAbstractValue(_wrappedDomain.unionOfMany(values.map( + (AbstractValue value) => _unwrap(value as ComputableAbstractValue)))); + + @override + AbstractValue intersection(covariant ComputableAbstractValue a, + covariant ComputableAbstractValue b) => + ComputableAbstractValue( + _wrappedDomain.intersection(_unwrap(a), _unwrap(b))); + + @override + AbstractBool areDisjoint(covariant ComputableAbstractValue a, + covariant ComputableAbstractValue b) => + _wrappedDomain.areDisjoint(_unwrap(a), _unwrap(b)); + + @override + AbstractBool containsAll(covariant ComputableAbstractValue a) => + _wrappedDomain.containsAll(_unwrap(a)); + + @override + AbstractValue computeAbstractValueForConstant( + covariant ConstantValue value) => + ComputableAbstractValue( + _wrappedDomain.computeAbstractValueForConstant(value)); + + @override + bool isContainer(covariant ComputableAbstractValue value) => + _wrappedDomain.isContainer(_unwrap(value)); + + @override + AbstractValue createContainerValue( + covariant ComputableAbstractValue? originalValue, + Object? allocationNode, + MemberEntity? allocationElement, + covariant ComputableAbstractValue elementType, + int? length) => + ComputableAbstractValue(_wrappedDomain.createContainerValue( + _unwrapOrNull(originalValue), + allocationNode, + allocationElement, + _unwrap(elementType), + length)); + + @override + AbstractValue getContainerElementType( + covariant ComputableAbstractValue value) => + ComputableAbstractValue( + _wrappedDomain.getContainerElementType(_unwrap(value))); + + @override + int? getContainerLength(covariant ComputableAbstractValue value) => + _wrappedDomain.getContainerLength(_unwrap(value)); + + @override + bool isSet(covariant ComputableAbstractValue value) => + _wrappedDomain.isSet(_unwrap(value)); + + @override + AbstractValue createSetValue( + covariant ComputableAbstractValue? originalValue, + Object? allocationNode, + MemberEntity? allocationElement, + covariant ComputableAbstractValue elementType) => + ComputableAbstractValue(_wrappedDomain.createSetValue( + _unwrapOrNull(originalValue), + allocationNode, + allocationElement, + _unwrap(elementType))); + + @override + AbstractValue getSetElementType(covariant ComputableAbstractValue value) => + ComputableAbstractValue(_wrappedDomain.getSetElementType(_unwrap(value))); + + @override + bool isMap(covariant ComputableAbstractValue value) => + _wrappedDomain.isMap(_unwrap(value)); + + @override + AbstractValue createMapValue( + covariant ComputableAbstractValue? originalValue, + Object? allocationNode, + MemberEntity? allocationElement, + covariant ComputableAbstractValue key, + covariant ComputableAbstractValue value) => + ComputableAbstractValue(_wrappedDomain.createMapValue( + _unwrapOrNull(originalValue), + allocationNode, + allocationElement, + _unwrap(key), + _unwrap(value))); + + @override + AbstractValue getMapKeyType(covariant ComputableAbstractValue value) => + ComputableAbstractValue(_wrappedDomain.getMapKeyType(_unwrap(value))); + + @override + AbstractValue getMapValueType(covariant ComputableAbstractValue value) => + ComputableAbstractValue(_wrappedDomain.getMapValueType(_unwrap(value))); + + @override + bool isDictionary(covariant ComputableAbstractValue value) => + _wrappedDomain.isDictionary(_unwrap(value)); + + @override + AbstractValue createDictionaryValue( + covariant ComputableAbstractValue? originalValue, + Object? allocationNode, + MemberEntity? allocationElement, + covariant ComputableAbstractValue key, + covariant ComputableAbstractValue value, + covariant Map mappings) => + ComputableAbstractValue(_wrappedDomain.createDictionaryValue( + _unwrapOrNull(originalValue), + allocationNode, + allocationElement, + _unwrap(key), + _unwrap(value), { + for (final entry in mappings.entries) + entry.key: _unwrap(entry.value as ComputableAbstractValue) + })); + + @override + bool containsDictionaryKey( + covariant ComputableAbstractValue value, String key) => + value.isComputed && + _wrappedDomain.containsDictionaryKey(value._wrappedValue!, key); + + @override + AbstractValue getDictionaryValueForKey( + covariant ComputableAbstractValue value, String key) => + ComputableAbstractValue( + _wrappedDomain.getDictionaryValueForKey(_unwrap(value), key)); + + @override + bool isSpecializationOf(covariant ComputableAbstractValue specialization, + covariant ComputableAbstractValue generalization) => + _wrappedDomain.isSpecializationOf( + _unwrap(specialization), _unwrap(generalization)); + + @override + AbstractValue? getGeneralization(covariant ComputableAbstractValue? value) { + final generalization = + _wrappedDomain.getGeneralization(_unwrapOrNull(value)); + if (generalization == null) return null; + return ComputableAbstractValue(generalization); + } + + @override + Object? getAllocationNode(covariant ComputableAbstractValue value) => + _wrappedDomain.getAllocationNode(_unwrap(value)); + + @override + MemberEntity? getAllocationElement(covariant ComputableAbstractValue value) => + _wrappedDomain.getAllocationElement(_unwrap(value)); + + @override + bool isPrimitiveValue(covariant ComputableAbstractValue value) => + _wrappedDomain.isPrimitiveValue(_unwrap(value)); + + @override + AbstractValue createPrimitiveValue( + covariant ComputableAbstractValue originalValue, + PrimitiveConstantValue value) => + ComputableAbstractValue( + _wrappedDomain.createPrimitiveValue(_unwrap(originalValue), value)); + + @override + PrimitiveConstantValue? getPrimitiveValue( + covariant ComputableAbstractValue value) => + _wrappedDomain.getPrimitiveValue(_unwrap(value)); + + @override + AbstractValue computeReceiver(Iterable members) => + ComputableAbstractValue(_wrappedDomain.computeReceiver(members)); + + @override + AbstractBool isTargetingMember(covariant ComputableAbstractValue receiver, + MemberEntity member, Name name) => + _wrappedDomain.isTargetingMember(_unwrap(receiver), member, name); + + @override + AbstractBool needsNoSuchMethodHandling( + covariant ComputableAbstractValue receiver, Selector selector) => + _wrappedDomain.needsNoSuchMethodHandling(_unwrap(receiver), selector); + + @override + AbstractValue? getAbstractValueForNativeMethodParameterType(DartType type) { + final value = + _wrappedDomain.getAbstractValueForNativeMethodParameterType(type); + if (value == null) return null; + return ComputableAbstractValue(value); + } + + @override + AbstractBool isIn(covariant ComputableAbstractValue subset, + covariant ComputableAbstractValue superset) => + _wrappedDomain.isIn(_unwrap(subset), _unwrap(superset)); + + @override + MemberEntity? locateSingleMember( + covariant ComputableAbstractValue receiver, Selector selector) => + _wrappedDomain.locateSingleMember(_unwrap(receiver), selector); + + @override + AbstractBool isJsIndexable(covariant ComputableAbstractValue value) => + _wrappedDomain.isJsIndexable(_unwrap(value)); + + @override + AbstractBool isJsIndexableAndIterable( + covariant ComputableAbstractValue value) => + _wrappedDomain.isJsIndexableAndIterable(_unwrap(value)); + + @override + AbstractBool isFixedLengthJsIndexable( + covariant ComputableAbstractValue value) => + _wrappedDomain.isFixedLengthJsIndexable(_unwrap(value)); + + @override + String getCompactText(covariant ComputableAbstractValue value) => + _wrappedDomain.getCompactText(_unwrap(value)); + + @override + AbstractValue readAbstractValueFromDataSource(DataSourceReader source) => + ComputableAbstractValue( + _wrappedDomain.readAbstractValueFromDataSource(source)); + + @override + void writeAbstractValueToDataSink( + DataSinkWriter sink, covariant ComputableAbstractValue value) { + _wrappedDomain.writeAbstractValueToDataSink(sink, _unwrap(value)); + } +} + +class ComputableAbstractValueStrategy implements AbstractValueStrategy { + final AbstractValueStrategy _wrappedStrategy; + + const ComputableAbstractValueStrategy(this._wrappedStrategy); + + @override + AbstractValueDomain createDomain(JClosedWorld closedWorld) => + ComputableAbstractValueDomain(_wrappedStrategy.createDomain(closedWorld)); + + @override + SelectorConstraintsStrategy createSelectorStrategy() => + ComputableSelectorStrategy(_wrappedStrategy.createSelectorStrategy()); +} + +class ComputableSelectorStrategy implements SelectorConstraintsStrategy { + final SelectorConstraintsStrategy _wrappedStrategy; + + const ComputableSelectorStrategy(this._wrappedStrategy); + + // There should be no uncomputed values at this point, so throw instead of + // requiring a domain. + AbstractValue? _unwrap(ComputableAbstractValue? value) => + value?._unwrapOrThrow(); + + @override + UniverseSelectorConstraints createSelectorConstraints( + Selector selector, Object? initialConstraint) => + ComputableUniverseSelectorConstraints( + _wrappedStrategy.createSelectorConstraints( + selector, _unwrap(initialConstraint as ComputableAbstractValue))); + + @override + bool appliedUnnamed(DynamicUse dynamicUse, MemberEntity member, + covariant JClosedWorld world) => + _wrappedStrategy.appliedUnnamed( + dynamicUse.withReceiverConstraint(_unwrap( + dynamicUse.receiverConstraint as ComputableAbstractValue)), + member, + world); +} + +class ComputableUniverseSelectorConstraints + implements UniverseSelectorConstraints { + final UniverseSelectorConstraints _universeSelectorConstraints; + + const ComputableUniverseSelectorConstraints( + this._universeSelectorConstraints); + + // There should be no uncomputed values at this point, so throw instead of + // requiring a domain. + AbstractValue? _unwrap(ComputableAbstractValue? value) => + value?._unwrapOrThrow(); + + @override + bool addReceiverConstraint(covariant ComputableAbstractValue constraint) => + _universeSelectorConstraints.addReceiverConstraint(_unwrap(constraint)); + + @override + bool needsNoSuchMethodHandling(Selector selector, World world) => + _universeSelectorConstraints.needsNoSuchMethodHandling(selector, world); + + @override + bool canHit(MemberEntity element, Name name, World world) => + _universeSelectorConstraints.canHit(element, name, world); + + @override + String toString() => 'ComputableUniverseSelectorConstraints:$hashCode'; +} diff --git a/pkg/compiler/lib/src/inferrer/powersets/powersets.dart b/pkg/compiler/lib/src/inferrer/powersets/powersets.dart index 8b53761daf9..0449df32bd6 100644 --- a/pkg/compiler/lib/src/inferrer/powersets/powersets.dart +++ b/pkg/compiler/lib/src/inferrer/powersets/powersets.dart @@ -53,7 +53,7 @@ PowersetValue? wrapOrNull(AbstractValue? abstractValue, int powersetBits) { : PowersetValue(abstractValue, powersetBits); } -class PowersetDomain implements AbstractValueDomain { +class PowersetDomain with AbstractValueDomain { final AbstractValueDomain _abstractValueDomain; final PowersetBitsDomain _powersetBitsDomain; diff --git a/pkg/compiler/lib/src/inferrer/trivial.dart b/pkg/compiler/lib/src/inferrer/trivial.dart index 61dbb612d85..2ee1e5b6e94 100644 --- a/pkg/compiler/lib/src/inferrer/trivial.dart +++ b/pkg/compiler/lib/src/inferrer/trivial.dart @@ -22,7 +22,7 @@ class TrivialAbstractValue implements AbstractValue { String toString() => '?'; } -class TrivialAbstractValueDomain implements AbstractValueDomain { +class TrivialAbstractValueDomain with AbstractValueDomain { const TrivialAbstractValueDomain(); @override diff --git a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart index fa20fb2e636..a6cd6ebc01c 100644 --- a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart +++ b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart @@ -177,7 +177,7 @@ abstract class TypeInformation { bool reset(InferrerEngine inferrer) { if (abandonInferencing) return false; - type = inferrer.abstractValueDomain.emptyType; + type = inferrer.abstractValueDomain.uncomputedType; refineCount = 0; return true; } @@ -247,7 +247,7 @@ abstract class ApplyableTypeInformation implements TypeInformation { class PlaceholderTypeInformation extends TypeInformation { PlaceholderTypeInformation( AbstractValueDomain abstractValueDomain, MemberTypeInformation context) - : super(abstractValueDomain.emptyType, context); + : super(abstractValueDomain.uncomputedType, context); @override void accept(TypeInformationVisitor visitor) { @@ -380,10 +380,11 @@ abstract class ElementTypeInformation extends TypeInformation { ElementTypeInformation._internal( AbstractValueDomain abstractValueDomain, MemberTypeInformation? context) - : super(abstractValueDomain.emptyType, context); + : super(abstractValueDomain.uncomputedType, context); + ElementTypeInformation._withInputs(AbstractValueDomain abstractValueDomain, MemberTypeInformation? context, ParameterInputs inputs) - : super.withInputs(abstractValueDomain.emptyType, context, inputs); + : super.withInputs(abstractValueDomain.uncomputedType, context, inputs); String getInferredSignature(TypeSystem types); @@ -967,9 +968,8 @@ abstract class CallSiteTypeInformation extends TypeInformation this.selector, this.arguments, this.inLoop) - : super.noInputs(abstractValueDomain.emptyType, context) { - assert(_call is ir.Node || (_call == null && selector?.name == '==')); - } + : assert(_call is ir.Node || (_call == null && selector?.name == '==')), + super.noInputs(abstractValueDomain.uncomputedType, context); @override String toString() => 'Call site $debugName $type'; @@ -1603,7 +1603,7 @@ class NarrowTypeInformation extends TypeInformation { NarrowTypeInformation(AbstractValueDomain abstractValueDomain, TypeInformation narrowedType, this.typeAnnotation) - : super(abstractValueDomain.emptyType, narrowedType.context) { + : super(abstractValueDomain.uncomputedType, narrowedType.context) { addInput(narrowedType); } @@ -1643,7 +1643,7 @@ abstract class InferredTypeInformation extends TypeInformation { InferredTypeInformation(AbstractValueDomain abstractValueDomain, MemberTypeInformation? context, TypeInformation? parentType) - : super(abstractValueDomain.emptyType, context) { + : super(abstractValueDomain.uncomputedType, context) { if (parentType != null) addInput(parentType); } @@ -2025,7 +2025,7 @@ class PhiElementTypeInformation extends TypeInformation { PhiElementTypeInformation(AbstractValueDomain abstractValueDomain, MemberTypeInformation? context, this.branchNode, this.variable, {required this.isTry}) - : super(abstractValueDomain.emptyType, context); + : super(abstractValueDomain.uncomputedType, context); @override AbstractValue computeType(InferrerEngine inferrer) { @@ -2062,7 +2062,7 @@ class ClosureTypeInformation extends TypeInformation ClosureTypeInformation(AbstractValueDomain abstractValueDomain, MemberTypeInformation? context, this._element) - : super(abstractValueDomain.emptyType, context); + : super(abstractValueDomain.uncomputedType, context); FunctionEntity get closure => _element; @@ -2126,7 +2126,7 @@ class AwaitTypeInformation extends TypeInformation { AwaitTypeInformation(AbstractValueDomain abstractValueDomain, MemberTypeInformation context, this._node) - : super(abstractValueDomain.emptyType, context); + : super(abstractValueDomain.uncomputedType, context); // TODO(22894): Compute a better type here. @override @@ -2148,7 +2148,7 @@ class YieldTypeInformation extends TypeInformation { YieldTypeInformation(AbstractValueDomain abstractValueDomain, MemberTypeInformation context, this._node) - : super(abstractValueDomain.emptyType, context); + : super(abstractValueDomain.uncomputedType, context); @override AbstractValue computeType(InferrerEngine inferrer) => safeType(inferrer); diff --git a/pkg/compiler/lib/src/inferrer/typemasks/masks.dart b/pkg/compiler/lib/src/inferrer/typemasks/masks.dart index b12d9c38394..bdad0fe179b 100644 --- a/pkg/compiler/lib/src/inferrer/typemasks/masks.dart +++ b/pkg/compiler/lib/src/inferrer/typemasks/masks.dart @@ -35,7 +35,7 @@ part 'type_mask.dart'; part 'union_type_mask.dart'; part 'value_type_mask.dart'; -class CommonMasks implements AbstractValueDomain { +class CommonMasks with AbstractValueDomain { // TODO(sigmund): once we split out the backend common elements, depend // directly on those instead. final JClosedWorld _closedWorld; diff --git a/pkg/compiler/lib/src/inferrer/wrapped.dart b/pkg/compiler/lib/src/inferrer/wrapped.dart index 455c84f4580..dbc10055f03 100644 --- a/pkg/compiler/lib/src/inferrer/wrapped.dart +++ b/pkg/compiler/lib/src/inferrer/wrapped.dart @@ -43,7 +43,7 @@ WrappedAbstractValue? wrapOrNull(AbstractValue? abstractValue) { return abstractValue == null ? null : WrappedAbstractValue(abstractValue); } -class WrappedAbstractValueDomain implements AbstractValueDomain { +class WrappedAbstractValueDomain with AbstractValueDomain { final AbstractValueDomain _abstractValueDomain; const WrappedAbstractValueDomain(this._abstractValueDomain); diff --git a/pkg/compiler/lib/src/inferrer_experimental/powersets/powersets.dart b/pkg/compiler/lib/src/inferrer_experimental/powersets/powersets.dart index 86bad4eb255..0b56518650f 100644 --- a/pkg/compiler/lib/src/inferrer_experimental/powersets/powersets.dart +++ b/pkg/compiler/lib/src/inferrer_experimental/powersets/powersets.dart @@ -53,7 +53,7 @@ PowersetValue? wrapOrNull(AbstractValue? abstractValue, int powersetBits) { : PowersetValue(abstractValue, powersetBits); } -class PowersetDomain implements AbstractValueDomain { +class PowersetDomain with AbstractValueDomain { final AbstractValueDomain _abstractValueDomain; final PowersetBitsDomain _powersetBitsDomain; diff --git a/pkg/compiler/lib/src/inferrer_experimental/trivial.dart b/pkg/compiler/lib/src/inferrer_experimental/trivial.dart index ba3e67ec736..56a01aa1b2f 100644 --- a/pkg/compiler/lib/src/inferrer_experimental/trivial.dart +++ b/pkg/compiler/lib/src/inferrer_experimental/trivial.dart @@ -22,7 +22,7 @@ class TrivialAbstractValue implements AbstractValue { String toString() => '?'; } -class TrivialAbstractValueDomain implements AbstractValueDomain { +class TrivialAbstractValueDomain with AbstractValueDomain { const TrivialAbstractValueDomain(); @override diff --git a/pkg/compiler/lib/src/inferrer_experimental/type_graph_nodes.dart b/pkg/compiler/lib/src/inferrer_experimental/type_graph_nodes.dart index cfd56d845ef..15128e4dd33 100644 --- a/pkg/compiler/lib/src/inferrer_experimental/type_graph_nodes.dart +++ b/pkg/compiler/lib/src/inferrer_experimental/type_graph_nodes.dart @@ -177,7 +177,7 @@ abstract class TypeInformation { bool reset(InferrerEngine inferrer) { if (abandonInferencing) return false; - type = inferrer.abstractValueDomain.emptyType; + type = inferrer.abstractValueDomain.uncomputedType; refineCount = 0; return true; } @@ -247,7 +247,7 @@ abstract class ApplyableTypeInformation implements TypeInformation { class PlaceholderTypeInformation extends TypeInformation { PlaceholderTypeInformation( AbstractValueDomain abstractValueDomain, MemberTypeInformation context) - : super(abstractValueDomain.emptyType, context); + : super(abstractValueDomain.uncomputedType, context); @override void accept(TypeInformationVisitor visitor) { @@ -380,10 +380,11 @@ abstract class ElementTypeInformation extends TypeInformation { ElementTypeInformation._internal( AbstractValueDomain abstractValueDomain, MemberTypeInformation? context) - : super(abstractValueDomain.emptyType, context); + : super(abstractValueDomain.uncomputedType, context); + ElementTypeInformation._withInputs(AbstractValueDomain abstractValueDomain, MemberTypeInformation? context, ParameterInputs inputs) - : super.withInputs(abstractValueDomain.emptyType, context, inputs); + : super.withInputs(abstractValueDomain.uncomputedType, context, inputs); String getInferredSignature(TypeSystem types); @@ -967,9 +968,8 @@ abstract class CallSiteTypeInformation extends TypeInformation this.selector, this.arguments, this.inLoop) - : super.noInputs(abstractValueDomain.emptyType, context) { - assert(_call is ir.Node || (_call == null && selector?.name == '==')); - } + : assert(_call is ir.Node || (_call == null && selector?.name == '==')), + super.noInputs(abstractValueDomain.uncomputedType, context); @override String toString() => 'Call site $debugName $type'; @@ -1596,7 +1596,7 @@ class NarrowTypeInformation extends TypeInformation { NarrowTypeInformation(AbstractValueDomain abstractValueDomain, TypeInformation narrowedType, this.typeAnnotation) - : super(abstractValueDomain.emptyType, narrowedType.context) { + : super(abstractValueDomain.uncomputedType, narrowedType.context) { addInput(narrowedType); } @@ -1636,7 +1636,7 @@ abstract class InferredTypeInformation extends TypeInformation { InferredTypeInformation(AbstractValueDomain abstractValueDomain, MemberTypeInformation? context, TypeInformation? parentType) - : super(abstractValueDomain.emptyType, context) { + : super(abstractValueDomain.uncomputedType, context) { if (parentType != null) addInput(parentType); } @@ -2018,7 +2018,7 @@ class PhiElementTypeInformation extends TypeInformation { PhiElementTypeInformation(AbstractValueDomain abstractValueDomain, MemberTypeInformation? context, this.branchNode, this.variable, {required this.isTry}) - : super(abstractValueDomain.emptyType, context); + : super(abstractValueDomain.uncomputedType, context); @override AbstractValue computeType(InferrerEngine inferrer) { @@ -2055,7 +2055,7 @@ class ClosureTypeInformation extends TypeInformation ClosureTypeInformation(AbstractValueDomain abstractValueDomain, MemberTypeInformation? context, this._element) - : super(abstractValueDomain.emptyType, context); + : super(abstractValueDomain.uncomputedType, context); FunctionEntity get closure => _element; @@ -2119,7 +2119,7 @@ class AwaitTypeInformation extends TypeInformation { AwaitTypeInformation(AbstractValueDomain abstractValueDomain, MemberTypeInformation context, this._node) - : super(abstractValueDomain.emptyType, context); + : super(abstractValueDomain.uncomputedType, context); // TODO(22894): Compute a better type here. @override @@ -2141,7 +2141,7 @@ class YieldTypeInformation extends TypeInformation { YieldTypeInformation(AbstractValueDomain abstractValueDomain, MemberTypeInformation context, this._node) - : super(abstractValueDomain.emptyType, context); + : super(abstractValueDomain.uncomputedType, context); @override AbstractValue computeType(InferrerEngine inferrer) => safeType(inferrer); diff --git a/pkg/compiler/lib/src/inferrer_experimental/typemasks/masks.dart b/pkg/compiler/lib/src/inferrer_experimental/typemasks/masks.dart index 209aa062617..271bd78ca98 100644 --- a/pkg/compiler/lib/src/inferrer_experimental/typemasks/masks.dart +++ b/pkg/compiler/lib/src/inferrer_experimental/typemasks/masks.dart @@ -35,7 +35,7 @@ part 'type_mask.dart'; part 'union_type_mask.dart'; part 'value_type_mask.dart'; -class CommonMasks implements AbstractValueDomain { +class CommonMasks with AbstractValueDomain { // TODO(sigmund): once we split out the backend common elements, depend // directly on those instead. final JClosedWorld _closedWorld; diff --git a/pkg/compiler/lib/src/inferrer_experimental/wrapped.dart b/pkg/compiler/lib/src/inferrer_experimental/wrapped.dart index 2f5f04db512..31188faab14 100644 --- a/pkg/compiler/lib/src/inferrer_experimental/wrapped.dart +++ b/pkg/compiler/lib/src/inferrer_experimental/wrapped.dart @@ -43,7 +43,7 @@ WrappedAbstractValue? wrapOrNull(AbstractValue? abstractValue) { return abstractValue == null ? null : WrappedAbstractValue(abstractValue); } -class WrappedAbstractValueDomain implements AbstractValueDomain { +class WrappedAbstractValueDomain with AbstractValueDomain { final AbstractValueDomain _abstractValueDomain; const WrappedAbstractValueDomain(this._abstractValueDomain);