| Index: pkg/compiler/lib/src/types/types.dart
|
| diff --git a/pkg/compiler/lib/src/types/types.dart b/pkg/compiler/lib/src/types/types.dart
|
| index d12b2bd25d832aca05bb2126fbd6540c2e5d9afc..28dc608cb384ef9bfd2da203f58f908c24909ea9 100644
|
| --- a/pkg/compiler/lib/src/types/types.dart
|
| +++ b/pkg/compiler/lib/src/types/types.dart
|
| @@ -4,36 +4,17 @@
|
|
|
| library types;
|
|
|
| -import '../common.dart';
|
| -import '../common/backend_api.dart' show Backend;
|
| import '../common/tasks.dart' show CompilerTask;
|
| import '../compiler.dart' show Compiler;
|
| -import '../constants/values.dart' show PrimitiveConstantValue;
|
| import '../elements/elements.dart';
|
| import '../inferrer/type_graph_inferrer.dart' show TypeGraphInferrer;
|
| import '../tree/tree.dart';
|
| import '../universe/selector.dart' show Selector;
|
| -import '../universe/universe.dart'
|
| - show
|
| - ReceiverConstraint,
|
| - UniverseSelectorConstraints,
|
| - SelectorConstraintsStrategy;
|
| -import '../util/util.dart';
|
| -import '../world.dart' show ClassWorld, World;
|
| -import 'abstract_value_domain.dart' show AbstractValue;
|
|
|
| -part 'container_type_mask.dart';
|
| -part 'dictionary_type_mask.dart';
|
| -part 'flat_type_mask.dart';
|
| -part 'forwarding_type_mask.dart';
|
| -part 'map_type_mask.dart';
|
| -part 'type_mask.dart';
|
| -part 'union_type_mask.dart';
|
| -part 'value_type_mask.dart';
|
| +import 'masks.dart';
|
| +export 'masks.dart';
|
|
|
| -/**
|
| - * Common super class for our type inferrers.
|
| - */
|
| +/// API to interact with the global type-inference engine.
|
| abstract class TypesInferrer {
|
| void analyzeMain(Element element);
|
| TypeMask getReturnTypeOfElement(Element element);
|
| @@ -45,249 +26,24 @@ abstract class TypesInferrer {
|
| bool isFixedArrayCheckedForGrowable(Node node);
|
| }
|
|
|
| -/**
|
| - * The types task infers guaranteed types globally.
|
| - */
|
| -class TypesTask extends CompilerTask {
|
| +/// Global analysis that infers concrete types.
|
| +class GlobalTypeInferenceTask extends CompilerTask {
|
| + // TODO(sigmund): rename at the same time as our benchmarking tools.
|
| final String name = 'Type inference';
|
| - final ClassWorld classWorld;
|
| +
|
| final Compiler compiler;
|
| TypesInferrer typesInferrer;
|
| + CommonMasks masks;
|
|
|
| - TypesTask(Compiler compiler)
|
| - : this.classWorld = compiler.world,
|
| + GlobalTypeInferenceTask(Compiler compiler)
|
| + : masks = new CommonMasks(compiler),
|
| compiler = compiler,
|
| super(compiler.measurer) {
|
| - typesInferrer = new TypeGraphInferrer(compiler);
|
| - }
|
| -
|
| - TypeMask dynamicTypeCache;
|
| - TypeMask nonNullTypeCache;
|
| - TypeMask nullTypeCache;
|
| - TypeMask intTypeCache;
|
| - TypeMask uint32TypeCache;
|
| - TypeMask uint31TypeCache;
|
| - TypeMask positiveIntTypeCache;
|
| - TypeMask doubleTypeCache;
|
| - TypeMask numTypeCache;
|
| - TypeMask boolTypeCache;
|
| - TypeMask functionTypeCache;
|
| - TypeMask listTypeCache;
|
| - TypeMask constListTypeCache;
|
| - TypeMask fixedListTypeCache;
|
| - TypeMask growableListTypeCache;
|
| - TypeMask mapTypeCache;
|
| - TypeMask constMapTypeCache;
|
| - TypeMask stringTypeCache;
|
| - TypeMask typeTypeCache;
|
| - TypeMask syncStarIterableTypeCache;
|
| - TypeMask asyncFutureTypeCache;
|
| - TypeMask asyncStarStreamTypeCache;
|
| -
|
| - TypeMask get dynamicType {
|
| - if (dynamicTypeCache == null) {
|
| - dynamicTypeCache =
|
| - new TypeMask.subclass(classWorld.objectClass, classWorld);
|
| - }
|
| - return dynamicTypeCache;
|
| - }
|
| -
|
| - TypeMask get nonNullType {
|
| - if (nonNullTypeCache == null) {
|
| - nonNullTypeCache =
|
| - new TypeMask.nonNullSubclass(classWorld.objectClass, classWorld);
|
| - }
|
| - return nonNullTypeCache;
|
| - }
|
| -
|
| - TypeMask get intType {
|
| - if (intTypeCache == null) {
|
| - intTypeCache = new TypeMask.nonNullSubclass(
|
| - compiler.backend.intImplementation, classWorld);
|
| - }
|
| - return intTypeCache;
|
| - }
|
| -
|
| - TypeMask get uint32Type {
|
| - if (uint32TypeCache == null) {
|
| - uint32TypeCache = new TypeMask.nonNullSubclass(
|
| - compiler.backend.uint32Implementation, classWorld);
|
| - }
|
| - return uint32TypeCache;
|
| - }
|
| -
|
| - TypeMask get uint31Type {
|
| - if (uint31TypeCache == null) {
|
| - uint31TypeCache = new TypeMask.nonNullExact(
|
| - compiler.backend.uint31Implementation, classWorld);
|
| - }
|
| - return uint31TypeCache;
|
| - }
|
| -
|
| - TypeMask get positiveIntType {
|
| - if (positiveIntTypeCache == null) {
|
| - positiveIntTypeCache = new TypeMask.nonNullSubclass(
|
| - compiler.backend.positiveIntImplementation, classWorld);
|
| - }
|
| - return positiveIntTypeCache;
|
| - }
|
| -
|
| - TypeMask get doubleType {
|
| - if (doubleTypeCache == null) {
|
| - doubleTypeCache = new TypeMask.nonNullExact(
|
| - compiler.backend.doubleImplementation, classWorld);
|
| - }
|
| - return doubleTypeCache;
|
| - }
|
| -
|
| - TypeMask get numType {
|
| - if (numTypeCache == null) {
|
| - numTypeCache = new TypeMask.nonNullSubclass(
|
| - compiler.backend.numImplementation, classWorld);
|
| - }
|
| - return numTypeCache;
|
| - }
|
| -
|
| - TypeMask get boolType {
|
| - if (boolTypeCache == null) {
|
| - boolTypeCache = new TypeMask.nonNullExact(
|
| - compiler.backend.boolImplementation, classWorld);
|
| - }
|
| - return boolTypeCache;
|
| - }
|
| -
|
| - TypeMask get functionType {
|
| - if (functionTypeCache == null) {
|
| - functionTypeCache = new TypeMask.nonNullSubtype(
|
| - compiler.backend.functionImplementation, classWorld);
|
| - }
|
| - return functionTypeCache;
|
| - }
|
| -
|
| - TypeMask get listType {
|
| - if (listTypeCache == null) {
|
| - listTypeCache = new TypeMask.nonNullExact(
|
| - compiler.backend.listImplementation, classWorld);
|
| - }
|
| - return listTypeCache;
|
| - }
|
| -
|
| - TypeMask get constListType {
|
| - if (constListTypeCache == null) {
|
| - constListTypeCache = new TypeMask.nonNullExact(
|
| - compiler.backend.constListImplementation, classWorld);
|
| - }
|
| - return constListTypeCache;
|
| - }
|
| -
|
| - TypeMask get fixedListType {
|
| - if (fixedListTypeCache == null) {
|
| - fixedListTypeCache = new TypeMask.nonNullExact(
|
| - compiler.backend.fixedListImplementation, classWorld);
|
| - }
|
| - return fixedListTypeCache;
|
| + typesInferrer = new TypeGraphInferrer(compiler, masks);
|
| }
|
|
|
| - TypeMask get growableListType {
|
| - if (growableListTypeCache == null) {
|
| - growableListTypeCache = new TypeMask.nonNullExact(
|
| - compiler.backend.growableListImplementation, classWorld);
|
| - }
|
| - return growableListTypeCache;
|
| - }
|
| -
|
| - TypeMask get mapType {
|
| - if (mapTypeCache == null) {
|
| - mapTypeCache = new TypeMask.nonNullSubtype(
|
| - compiler.backend.mapImplementation, classWorld);
|
| - }
|
| - return mapTypeCache;
|
| - }
|
| -
|
| - TypeMask get constMapType {
|
| - if (constMapTypeCache == null) {
|
| - constMapTypeCache = new TypeMask.nonNullSubtype(
|
| - compiler.backend.constMapImplementation, classWorld);
|
| - }
|
| - return constMapTypeCache;
|
| - }
|
| -
|
| - TypeMask get stringType {
|
| - if (stringTypeCache == null) {
|
| - stringTypeCache = new TypeMask.nonNullExact(
|
| - compiler.backend.stringImplementation, classWorld);
|
| - }
|
| - return stringTypeCache;
|
| - }
|
| -
|
| - TypeMask get typeType {
|
| - if (typeTypeCache == null) {
|
| - typeTypeCache = new TypeMask.nonNullExact(
|
| - compiler.backend.typeImplementation, classWorld);
|
| - }
|
| - return typeTypeCache;
|
| - }
|
| -
|
| - TypeMask get syncStarIterableType {
|
| - if (syncStarIterableTypeCache == null) {
|
| - syncStarIterableTypeCache = new TypeMask.nonNullExact(
|
| - compiler.backend.syncStarIterableImplementation, classWorld);
|
| - }
|
| - return syncStarIterableTypeCache;
|
| - }
|
| -
|
| - TypeMask get asyncFutureType {
|
| - if (asyncFutureTypeCache == null) {
|
| - asyncFutureTypeCache = new TypeMask.nonNullExact(
|
| - compiler.backend.asyncFutureImplementation, classWorld);
|
| - }
|
| - return asyncFutureTypeCache;
|
| - }
|
| -
|
| - TypeMask get asyncStarStreamType {
|
| - if (asyncStarStreamTypeCache == null) {
|
| - asyncStarStreamTypeCache = new TypeMask.nonNullExact(
|
| - compiler.backend.asyncStarStreamImplementation, classWorld);
|
| - }
|
| - return asyncStarStreamTypeCache;
|
| - }
|
| -
|
| - TypeMask get nullType {
|
| - if (nullTypeCache == null) {
|
| - // TODO(johnniwinther): Assert that the null type has been resolved.
|
| - nullTypeCache = const TypeMask.empty();
|
| - }
|
| - return nullTypeCache;
|
| - }
|
| -
|
| - /** Helper method for [intersection]. */
|
| - TypeMask _intersection(TypeMask type1, TypeMask type2) {
|
| - if (type1 == null) return type2;
|
| - if (type2 == null) return type1;
|
| - return type1.intersection(type2, classWorld);
|
| - }
|
| -
|
| - /** Computes the intersection of [type1] and [type2] */
|
| - TypeMask intersection(TypeMask type1, TypeMask type2, element) {
|
| - TypeMask result = _intersection(type1, type2);
|
| - return result;
|
| - }
|
| -
|
| - /** Returns true if [type1] is strictly better than [type2]. */
|
| - bool better(TypeMask type1, TypeMask type2) {
|
| - if (type1 == null) return false;
|
| - if (type2 == null) {
|
| - return (type1 != null) && (type1 != dynamicType);
|
| - }
|
| - return (type1 != type2) &&
|
| - type2.containsMask(type1, classWorld) &&
|
| - !type1.containsMask(type2, classWorld);
|
| - }
|
| -
|
| - /**
|
| - * Called when resolution is complete.
|
| - */
|
| - void onResolutionComplete(Element mainElement) {
|
| + /// Runs the global type-inference algorithm once.
|
| + void runGlobalTypeInference(Element mainElement) {
|
| measure(() {
|
| typesInferrer.analyzeMain(mainElement);
|
| typesInferrer.clear();
|
| @@ -300,7 +56,7 @@ class TypesTask extends CompilerTask {
|
| TypeMask getGuaranteedTypeOfElement(Element element) {
|
| // TODO(24489): trust some JsInterop types.
|
| if (compiler.backend.isJsInterop(element)) {
|
| - return dynamicType;
|
| + return masks.dynamicType;
|
| }
|
| TypeMask guaranteedType = typesInferrer.getTypeOfElement(element);
|
| return guaranteedType;
|
| @@ -309,13 +65,27 @@ class TypesTask extends CompilerTask {
|
| TypeMask getGuaranteedReturnTypeOfElement(Element element) {
|
| // TODO(24489): trust some JsInterop types.
|
| if (compiler.backend.isJsInterop(element)) {
|
| - return dynamicType;
|
| + return masks.dynamicType;
|
| }
|
|
|
| TypeMask guaranteedType = typesInferrer.getReturnTypeOfElement(element);
|
| return guaranteedType;
|
| }
|
|
|
| + /// Return whether the global inference algorithm determined that [element]
|
| + /// always throws.
|
| + bool throwsAlways(Element element) {
|
| + // We know the element always throws if the return type was inferred to be
|
| + // non-null empty.
|
| + TypeMask returnType = getGuaranteedReturnTypeOfElement(element);
|
| + return returnType != null && returnType.isEmpty;
|
| + }
|
| +
|
| + bool isFixedArrayCheckedForGrowable(Node send) =>
|
| + typesInferrer.isFixedArrayCheckedForGrowable(send);
|
| +
|
| + bool isCalledOnce(Element element) => typesInferrer.isCalledOnce(element);
|
| +
|
| /**
|
| * Return the (inferred) guaranteed type of [node] or null.
|
| * [node] must be an AST node of [owner].
|
|
|