// Copyright (c) 2013, 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.

// @dart = 2.10

part of masks;

enum _FlatTypeMaskKind { empty, exact, subclass, subtype }

/// A flat type mask is a type mask that has been flattened to contain a
/// base type.
class FlatTypeMask extends TypeMask {
  /// Tag used for identifying serialized [FlatTypeMask] objects in a
  /// debugging data stream.
  static const String tag = 'flat-type-mask';

  static const int _NULL_INDEX = 0;
  static const int _LATE_SENTINEL_INDEX = 1;
  static const int _USED_INDICES = 2;

  static const int _NONE_MASK = 0;
  static const int _NULL_MASK = 1 << _NULL_INDEX;
  static const int _LATE_SENTINEL_MASK = 1 << _LATE_SENTINEL_INDEX;
  static const int _ALL_MASK = (1 << _USED_INDICES) - 1;

  final ClassEntity base;
  final int flags;

  static int _computeFlags(_FlatTypeMaskKind kind,
      {bool isNullable = false, bool hasLateSentinel = false}) {
    int mask = _NONE_MASK;
    if (isNullable) mask |= _NULL_MASK;
    if (hasLateSentinel) mask |= _LATE_SENTINEL_MASK;
    return _computeFlagsRaw(kind.index, mask);
  }

  static int _computeFlagsRaw(int kind, int mask) =>
      kind << _USED_INDICES | mask;

  static _FlatTypeMaskKind _lookupKind(int flags) =>
      _FlatTypeMaskKind.values[flags >> _USED_INDICES];

  static bool _hasNullableFlag(int flags) => flags & _NULL_MASK != _NONE_MASK;

  static bool _hasLateSentinelFlag(int flags) =>
      flags & _LATE_SENTINEL_MASK != _NONE_MASK;

  factory FlatTypeMask.exact(ClassEntity base, JClosedWorld world,
          {bool hasLateSentinel = false}) =>
      FlatTypeMask._canonicalize(base, _FlatTypeMaskKind.exact, world,
          isNullable: true, hasLateSentinel: hasLateSentinel);
  factory FlatTypeMask.subclass(ClassEntity base, JClosedWorld world,
          {bool hasLateSentinel = false}) =>
      FlatTypeMask._canonicalize(base, _FlatTypeMaskKind.subclass, world,
          isNullable: true, hasLateSentinel: hasLateSentinel);
  factory FlatTypeMask.subtype(ClassEntity base, JClosedWorld world,
          {bool hasLateSentinel = false}) =>
      FlatTypeMask._canonicalize(base, _FlatTypeMaskKind.subtype, world,
          isNullable: true, hasLateSentinel: hasLateSentinel);

  factory FlatTypeMask.nonNullEmpty({bool hasLateSentinel = false}) =>
      hasLateSentinel
          ? const FlatTypeMask._(null, _LATE_SENTINEL_MASK)
          : const FlatTypeMask._(null, _NONE_MASK);

  factory FlatTypeMask.empty({bool hasLateSentinel = false}) => hasLateSentinel
      ? const FlatTypeMask._(null, _NULL_MASK | _LATE_SENTINEL_MASK)
      : const FlatTypeMask._(null, _NULL_MASK);

  factory FlatTypeMask.nonNullExact(ClassEntity base, JClosedWorld world,
          {bool hasLateSentinel = false}) =>
      FlatTypeMask._canonicalize(base, _FlatTypeMaskKind.exact, world,
          hasLateSentinel: hasLateSentinel);
  factory FlatTypeMask.nonNullSubclass(ClassEntity base, JClosedWorld world,
          {bool hasLateSentinel = false}) =>
      FlatTypeMask._canonicalize(base, _FlatTypeMaskKind.subclass, world,
          hasLateSentinel: hasLateSentinel);
  factory FlatTypeMask.nonNullSubtype(ClassEntity base, JClosedWorld world,
          {bool hasLateSentinel = false}) =>
      FlatTypeMask._canonicalize(base, _FlatTypeMaskKind.subtype, world,
          hasLateSentinel: hasLateSentinel);

  factory FlatTypeMask._canonicalize(
      ClassEntity base, _FlatTypeMaskKind kind, JClosedWorld world,
      {bool isNullable = false, bool hasLateSentinel = false}) {
    if (base == world.commonElements.nullClass) {
      return FlatTypeMask.empty(hasLateSentinel: hasLateSentinel);
    }
    return FlatTypeMask._(
        base,
        _computeFlags(kind,
            isNullable: isNullable, hasLateSentinel: hasLateSentinel));
  }

  const FlatTypeMask._(this.base, this.flags);

  /// Ensures that the generated mask is normalized, i.e., a call to
  /// [TypeMask.assertIsNormalized] with the factory's result returns `true`.
  factory FlatTypeMask.normalized(
      ClassEntity base, int flags, CommonMasks domain) {
    bool isNullable = _hasNullableFlag(flags);
    bool hasLateSentinel = _hasLateSentinelFlag(flags);
    if (base == domain.commonElements.nullClass) {
      return FlatTypeMask.empty(hasLateSentinel: hasLateSentinel);
    }
    _FlatTypeMaskKind kind = _lookupKind(flags);
    if (kind == _FlatTypeMaskKind.empty || kind == _FlatTypeMaskKind.exact) {
      return FlatTypeMask._(base, flags);
    }
    if (kind == _FlatTypeMaskKind.subtype) {
      if (!domain._closedWorld.classHierarchy.hasAnyStrictSubtype(base) ||
          domain._closedWorld.classHierarchy.hasOnlySubclasses(base)) {
        flags = _computeFlags(_FlatTypeMaskKind.subclass,
            isNullable: isNullable, hasLateSentinel: hasLateSentinel);
      }
    }
    if (kind == _FlatTypeMaskKind.subclass &&
        !domain._closedWorld.classHierarchy.hasAnyStrictSubclass(base)) {
      flags = _computeFlags(_FlatTypeMaskKind.exact,
          isNullable: isNullable, hasLateSentinel: hasLateSentinel);
    }
    return domain.getCachedMask(base, flags, () => FlatTypeMask._(base, flags));
  }

  /// Deserializes a [FlatTypeMask] object from [source].
  factory FlatTypeMask.readFromDataSource(
      DataSourceReader source, CommonMasks domain) {
    source.begin(tag);
    ClassEntity base = source.readClassOrNull();
    int flags = source.readInt();
    source.end(tag);
    return domain.getCachedMask(base, flags, () => FlatTypeMask._(base, flags));
  }

  /// Serializes this [FlatTypeMask] to [sink].
  @override
  void writeToDataSink(DataSinkWriter sink) {
    sink.writeEnum(TypeMaskKind.flat);
    sink.begin(tag);
    sink.writeClassOrNull(base);
    sink.writeInt(flags);
    sink.end(tag);
  }

  _FlatTypeMaskKind get _kind => _lookupKind(flags);

  int get _mask => flags & _ALL_MASK;

  ClassQuery get _classQuery => isExact
      ? ClassQuery.EXACT
      : (isSubclass ? ClassQuery.SUBCLASS : ClassQuery.SUBTYPE);

  @override
  bool get isEmpty => isEmptyOrFlagged && _mask == _NONE_MASK;
  @override
  bool get isNull => isEmptyOrFlagged && _mask == _NULL_MASK;
  @override
  bool get isEmptyOrFlagged => _kind == _FlatTypeMaskKind.empty;
  @override
  bool get isExact => _kind == _FlatTypeMaskKind.exact;
  @override
  bool get isNullable => _hasNullableFlag(flags);
  @override
  bool get hasLateSentinel => _hasLateSentinelFlag(flags);
  @override
  AbstractBool get isLateSentinel {
    if (!hasLateSentinel) return AbstractBool.False;
    if (isEmptyOrFlagged && _mask == _LATE_SENTINEL_MASK) {
      return AbstractBool.True;
    }
    return AbstractBool.Maybe;
  }

  @override
  bool get isUnion => false;
  @override
  bool get isContainer => false;
  @override
  bool get isSet => false;
  @override
  bool get isMap => false;
  @override
  bool get isDictionary => false;
  @override
  bool get isForwarding => false;
  @override
  bool get isValue => false;

  // TODO(kasperl): Get rid of these. They should not be a visible
  // part of the implementation because they make it hard to add
  // proper union types if we ever want to.
  bool get isSubclass => _kind == _FlatTypeMaskKind.subclass;
  bool get isSubtype => _kind == _FlatTypeMaskKind.subtype;

  @override
  FlatTypeMask withFlags({bool isNullable, bool hasLateSentinel}) {
    int newFlags = _computeFlags(_kind,
        isNullable: isNullable ?? this.isNullable,
        hasLateSentinel: hasLateSentinel ?? this.hasLateSentinel);
    if (newFlags == flags) return this;
    return FlatTypeMask._(base, newFlags);
  }

  @override
  bool contains(ClassEntity other, JClosedWorld closedWorld) {
    if (isEmptyOrFlagged) {
      return false;
    } else if (identical(base, other)) {
      return true;
    } else if (isExact) {
      return false;
    } else if (isSubclass) {
      return closedWorld.classHierarchy.isSubclassOf(other, base);
    } else {
      assert(isSubtype);
      return closedWorld.classHierarchy.isSubtypeOf(other, base);
    }
  }

  bool _isSingleImplementationOf(ClassEntity cls, JClosedWorld closedWorld) {
    // Special case basic types so that, for example, JSString is the
    // single implementation of String.
    // The general optimization is to realize there is only one class that
    // implements [base] and [base] is not instantiated. We however do
    // not track correctly the list of truly instantiated classes.
    CommonElements commonElements = closedWorld.commonElements;
    if (containsOnlyString(closedWorld)) {
      return cls == closedWorld.commonElements.stringClass ||
          cls == commonElements.jsStringClass;
    }
    if (containsOnlyBool(closedWorld)) {
      return cls == closedWorld.commonElements.boolClass ||
          cls == commonElements.jsBoolClass;
    }
    if (containsOnlyInt(closedWorld)) {
      return cls == closedWorld.commonElements.intClass ||
          cls == commonElements.jsIntClass ||
          cls == commonElements.jsPositiveIntClass ||
          cls == commonElements.jsUInt32Class ||
          cls == commonElements.jsUInt31Class;
    }
    return false;
  }

  @override
  bool isInMask(TypeMask other, JClosedWorld closedWorld) {
    // Quick check whether to handle null.
    if (isNullable && !other.isNullable) return false;
    if (hasLateSentinel && !other.hasLateSentinel) {
      return false;
    }
    // The empty type contains no classes.
    if (isEmptyOrFlagged) return true;
    if (other.isEmptyOrFlagged) return false;
    other = TypeMask.nonForwardingMask(other);
    // If other is union, delegate to UnionTypeMask.containsMask.
    if (other is! FlatTypeMask) return other.containsMask(this, closedWorld);
    // The other must be flat, so compare base and flags.
    FlatTypeMask flatOther = other;
    ClassEntity otherBase = flatOther.base;
    // If other is exact, it only contains its base.
    // TODO(herhut): Get rid of _isSingleImplementationOf.
    if (flatOther.isExact) {
      return (isExact && base == otherBase) ||
          _isSingleImplementationOf(otherBase, closedWorld);
    }
    // If other is subclass, this has to be subclass, as well. Unless
    // flatOther.base covers all subtypes of this. Currently, we only
    // consider object to behave that way.
    // TODO(herhut): Add check whether flatOther.base is superclass of
    //               all subclasses of this.base.
    if (flatOther.isSubclass) {
      if (isSubtype)
        return (otherBase == closedWorld.commonElements.objectClass);
      return closedWorld.classHierarchy.isSubclassOf(base, otherBase);
    }
    assert(flatOther.isSubtype);
    // Check whether this TypeMask satisfies otherBase's interface.
    return satisfies(otherBase, closedWorld);
  }

  @override
  bool containsMask(TypeMask other, JClosedWorld closedWorld) {
    return other.isInMask(this, closedWorld);
  }

  @override
  bool containsOnlyInt(JClosedWorld closedWorld) {
    CommonElements commonElements = closedWorld.commonElements;
    return base == commonElements.intClass ||
        base == commonElements.jsIntClass ||
        base == commonElements.jsPositiveIntClass ||
        base == commonElements.jsUInt31Class ||
        base == commonElements.jsUInt32Class;
  }

  @override
  bool containsOnlyNum(JClosedWorld closedWorld) {
    return containsOnlyInt(closedWorld) ||
        base == closedWorld.commonElements.doubleClass ||
        base == closedWorld.commonElements.jsNumNotIntClass ||
        base == closedWorld.commonElements.numClass ||
        base == closedWorld.commonElements.jsNumberClass;
  }

  @override
  bool containsOnlyBool(JClosedWorld closedWorld) {
    return base == closedWorld.commonElements.boolClass ||
        base == closedWorld.commonElements.jsBoolClass;
  }

  @override
  bool containsOnlyString(JClosedWorld closedWorld) {
    return base == closedWorld.commonElements.stringClass ||
        base == closedWorld.commonElements.jsStringClass;
  }

  @override
  bool containsOnly(ClassEntity cls) {
    return base == cls;
  }

  @override
  bool satisfies(ClassEntity cls, JClosedWorld closedWorld) {
    if (isEmptyOrFlagged) return false;
    if (closedWorld.classHierarchy.isSubtypeOf(base, cls)) return true;
    return false;
  }

  @override
  ClassEntity singleClass(JClosedWorld closedWorld) {
    if (isEmptyOrFlagged) return null;
    if (isNullable) return null; // It is Null and some other class.
    if (hasLateSentinel) return null;
    if (isExact) {
      return base;
    } else if (isSubclass) {
      return closedWorld.classHierarchy.hasAnyStrictSubclass(base)
          ? null
          : base;
    } else {
      assert(isSubtype);
      return null;
    }
  }

  @override
  bool containsAll(JClosedWorld closedWorld) {
    if (isEmptyOrFlagged || isExact) return false;
    return identical(base, closedWorld.commonElements.objectClass);
  }

  @override
  TypeMask union(TypeMask other, CommonMasks domain) {
    JClosedWorld closedWorld = domain._closedWorld;
    assert(other != null);
    assert(TypeMask.assertIsNormalized(this, closedWorld));
    assert(TypeMask.assertIsNormalized(other, closedWorld));
    if (other is! FlatTypeMask) return other.union(this, domain);
    FlatTypeMask flatOther = other;
    bool isNullable = this.isNullable || flatOther.isNullable;
    bool hasLateSentinel = this.hasLateSentinel || flatOther.hasLateSentinel;
    if (isEmptyOrFlagged) {
      return flatOther.withFlags(
          isNullable: isNullable, hasLateSentinel: hasLateSentinel);
    } else if (flatOther.isEmptyOrFlagged) {
      return withFlags(
          isNullable: isNullable, hasLateSentinel: hasLateSentinel);
    } else if (base == flatOther.base) {
      return unionSame(flatOther, domain);
    } else if (closedWorld.classHierarchy.isSubclassOf(flatOther.base, base)) {
      return unionStrictSubclass(flatOther, domain);
    } else if (closedWorld.classHierarchy.isSubclassOf(base, flatOther.base)) {
      return flatOther.unionStrictSubclass(this, domain);
    } else if (closedWorld.classHierarchy.isSubtypeOf(flatOther.base, base)) {
      return unionStrictSubtype(flatOther, domain);
    } else if (closedWorld.classHierarchy.isSubtypeOf(base, flatOther.base)) {
      return flatOther.unionStrictSubtype(this, domain);
    } else {
      return UnionTypeMask._internal(
          <FlatTypeMask>[withoutFlags(), flatOther.withoutFlags()],
          isNullable: isNullable, hasLateSentinel: hasLateSentinel);
    }
  }

  TypeMask unionSame(FlatTypeMask other, CommonMasks domain) {
    assert(base == other.base);
    assert(TypeMask.assertIsNormalized(this, domain._closedWorld));
    assert(TypeMask.assertIsNormalized(other, domain._closedWorld));
    // The two masks share the base type, so we must chose the least
    // constraining kind (the highest) of the two. If either one of
    // the masks are nullable the result should be nullable too.
    // As both masks are normalized, the result will be, too.
    int combined =
        (flags > other.flags) ? flags | other._mask : other.flags | _mask;
    if (flags == combined) {
      return this;
    } else if (other.flags == combined) {
      return other;
    } else {
      return FlatTypeMask.normalized(base, combined, domain);
    }
  }

  TypeMask unionStrictSubclass(FlatTypeMask other, CommonMasks domain) {
    assert(base != other.base);
    assert(domain._closedWorld.classHierarchy.isSubclassOf(other.base, base));
    assert(TypeMask.assertIsNormalized(this, domain._closedWorld));
    assert(TypeMask.assertIsNormalized(other, domain._closedWorld));
    int combined;
    if ((isExact && other.isExact) ||
        base == domain.commonElements.objectClass) {
      // Since the other mask is a subclass of this mask, we need the
      // resulting union to be a subclass too. If either one of the
      // masks are nullable the result should be nullable too.
      combined = _computeFlagsRaw(
          _FlatTypeMaskKind.subclass.index, _mask | other._mask);
    } else {
      // Both masks are at least subclass masks, so we pick the least
      // constraining kind (the highest) of the two. If either one of
      // the masks are nullable the result should be nullable too.
      combined =
          (flags > other.flags) ? flags | other._mask : other.flags | _mask;
    }
    // If we weaken the constraint on this type, we have to make sure that
    // the result is normalized.
    return flags != combined
        ? FlatTypeMask.normalized(base, combined, domain)
        : this;
  }

  TypeMask unionStrictSubtype(FlatTypeMask other, CommonMasks domain) {
    assert(base != other.base);
    assert(!domain._closedWorld.classHierarchy.isSubclassOf(other.base, base));
    assert(domain._closedWorld.classHierarchy.isSubtypeOf(other.base, base));
    assert(TypeMask.assertIsNormalized(this, domain._closedWorld));
    assert(TypeMask.assertIsNormalized(other, domain._closedWorld));
    // Since the other mask is a subtype of this mask, we need the
    // resulting union to be a subtype too. If either one of the masks
    // are nullable the result should be nullable too.
    int combined =
        _computeFlagsRaw(_FlatTypeMaskKind.subtype.index, _mask | other._mask);
    // We know there is at least one subtype, [other.base], so no need
    // to normalize.
    return flags != combined
        ? FlatTypeMask.normalized(base, combined, domain)
        : this;
  }

  @override
  TypeMask intersection(TypeMask other, CommonMasks domain) {
    assert(other != null);
    if (other is! FlatTypeMask) return other.intersection(this, domain);
    assert(TypeMask.assertIsNormalized(this, domain._closedWorld));
    assert(TypeMask.assertIsNormalized(other, domain._closedWorld));
    FlatTypeMask flatOther = other;

    ClassEntity otherBase = flatOther.base;

    bool includeNull = isNullable && flatOther.isNullable;
    bool includeLateSentinel = hasLateSentinel && flatOther.hasLateSentinel;

    if (isEmptyOrFlagged) {
      return withFlags(
          isNullable: includeNull, hasLateSentinel: includeLateSentinel);
    } else if (flatOther.isEmptyOrFlagged) {
      return other.withFlags(
          isNullable: includeNull, hasLateSentinel: includeLateSentinel);
    }

    SubclassResult result = domain._closedWorld.classHierarchy
        .commonSubclasses(base, _classQuery, otherBase, flatOther._classQuery);

    switch (result.kind) {
      case SubclassResultKind.EMPTY:
        return includeNull
            ? TypeMask.empty(hasLateSentinel: includeLateSentinel)
            : TypeMask.nonNullEmpty(hasLateSentinel: includeLateSentinel);
      case SubclassResultKind.EXACT1:
        assert(isExact);
        return withFlags(
            isNullable: includeNull, hasLateSentinel: includeLateSentinel);
      case SubclassResultKind.EXACT2:
        assert(other.isExact);
        return other.withFlags(
            isNullable: includeNull, hasLateSentinel: includeLateSentinel);
      case SubclassResultKind.SUBCLASS1:
        assert(isSubclass);
        return withFlags(
            isNullable: includeNull, hasLateSentinel: includeLateSentinel);
      case SubclassResultKind.SUBCLASS2:
        assert(flatOther.isSubclass);
        return other.withFlags(
            isNullable: includeNull, hasLateSentinel: includeLateSentinel);
      case SubclassResultKind.SUBTYPE1:
        assert(isSubtype);
        return withFlags(
            isNullable: includeNull, hasLateSentinel: includeLateSentinel);
      case SubclassResultKind.SUBTYPE2:
        assert(flatOther.isSubtype);
        return other.withFlags(
            isNullable: includeNull, hasLateSentinel: includeLateSentinel);
      case SubclassResultKind.SET:
      default:
        if (result.classes.isEmpty) {
          return includeNull
              ? TypeMask.empty(hasLateSentinel: includeLateSentinel)
              : TypeMask.nonNullEmpty(hasLateSentinel: includeLateSentinel);
        } else if (result.classes.length == 1) {
          ClassEntity cls = result.classes.first;
          return includeNull
              ? TypeMask.subclass(cls, domain._closedWorld,
                  hasLateSentinel: includeLateSentinel)
              : TypeMask.nonNullSubclass(cls, domain._closedWorld,
                  hasLateSentinel: includeLateSentinel);
        }

        List<FlatTypeMask> masks = List.from(result.classes.map(
            (ClassEntity cls) =>
                TypeMask.nonNullSubclass(cls, domain._closedWorld)));
        if (masks.length > UnionTypeMask.MAX_UNION_LENGTH) {
          return UnionTypeMask.flatten(masks, domain,
              includeNull: includeNull,
              includeLateSentinel: includeLateSentinel);
        }
        return UnionTypeMask._internal(masks,
            isNullable: includeNull, hasLateSentinel: includeLateSentinel);
    }
  }

  @override
  bool isDisjoint(TypeMask other, JClosedWorld closedWorld) {
    if (other is! FlatTypeMask) return other.isDisjoint(this, closedWorld);
    FlatTypeMask flatOther = other;

    if (isNullable && flatOther.isNullable) return false;
    if (hasLateSentinel && flatOther.hasLateSentinel) return false;
    if (isEmptyOrFlagged || flatOther.isEmptyOrFlagged) return true;
    if (base == flatOther.base) return false;
    if (isExact && flatOther.isExact) return true;

    if (isExact) return !flatOther.contains(base, closedWorld);
    if (flatOther.isExact) return !contains(flatOther.base, closedWorld);

    // Normalization guarantees that isExact === !isSubclass && !isSubtype.
    // Both are subclass or subtype masks, so if there is a subclass
    // relationship, they are not disjoint.
    if (closedWorld.classHierarchy.isSubclassOf(flatOther.base, base)) {
      return false;
    }
    if (closedWorld.classHierarchy.isSubclassOf(base, flatOther.base)) {
      return false;
    }

    // Two different base classes have no common subclass unless one is a
    // subclass of the other (checked above).
    if (isSubclass && flatOther.isSubclass) return true;

    return _isDisjointHelper(this, flatOther, closedWorld);
  }

  static bool _isDisjointHelper(
      FlatTypeMask a, FlatTypeMask b, JClosedWorld closedWorld) {
    if (!a.isSubclass && b.isSubclass) {
      return _isDisjointHelper(b, a, closedWorld);
    }
    assert(a.isSubclass || a.isSubtype);
    assert(b.isSubtype);
    var elements = a.isSubclass
        ? closedWorld.classHierarchy.strictSubclassesOf(a.base)
        : closedWorld.classHierarchy.strictSubtypesOf(a.base);
    for (var element in elements) {
      if (closedWorld.classHierarchy.isSubtypeOf(element, b.base)) return false;
    }
    return true;
  }

  TypeMask intersectionSame(FlatTypeMask other, CommonMasks domain) {
    assert(base == other.base);
    // The two masks share the base type, so we must chose the most
    // constraining kind (the lowest) of the two. Only if both masks
    // are nullable, will the result be nullable too.
    // The result will be normalized, as the two inputs are normalized, too.
    int combined = (flags < other.flags)
        ? flags & (other._mask | ~_ALL_MASK)
        : other.flags & (_mask | ~_ALL_MASK);
    if (flags == combined) {
      return this;
    } else if (other.flags == combined) {
      return other;
    } else {
      return FlatTypeMask.normalized(base, combined, domain);
    }
  }

  TypeMask intersectionStrictSubclass(FlatTypeMask other, CommonMasks domain) {
    assert(base != other.base);
    assert(domain._closedWorld.classHierarchy.isSubclassOf(other.base, base));
    // If this mask isn't at least a subclass mask, then the
    // intersection with the other mask is empty.
    if (isExact) return intersectionEmpty(other);
    // Only the other mask puts constraints on the intersection mask,
    // so base the combined flags on the other mask. Only if both
    // masks are nullable, will the result be nullable too.
    // The result is guaranteed to be normalized, as the other type
    // was normalized.
    int combined = other.flags & (_mask | ~_ALL_MASK);
    if (other.flags == combined) {
      return other;
    } else {
      return FlatTypeMask.normalized(other.base, combined, domain);
    }
  }

  TypeMask intersectionEmpty(FlatTypeMask other) {
    bool isNullable = this.isNullable && other.isNullable;
    bool hasLateSentinel = this.hasLateSentinel && other.hasLateSentinel;
    return isNullable
        ? TypeMask.empty(hasLateSentinel: hasLateSentinel)
        : TypeMask.nonNullEmpty(hasLateSentinel: hasLateSentinel);
  }

  @override
  bool canHit(MemberEntity element, Name name, JClosedWorld closedWorld) {
    CommonElements commonElements = closedWorld.commonElements;
    assert(element.name == name.text);
    if (isEmptyOrFlagged) {
      return isNullable &&
          closedWorld.hasElementIn(commonElements.jsNullClass, name, element);
    }

    ClassEntity other = element.enclosingClass;
    if (other == commonElements.jsNullClass) {
      return isNullable;
    } else if (isExact) {
      return closedWorld.hasElementIn(base, name, element);
    } else if (isSubclass) {
      return closedWorld.hasElementIn(base, name, element) ||
          closedWorld.classHierarchy.isSubclassOf(other, base) ||
          closedWorld.hasAnySubclassThatMixes(base, other);
    } else {
      assert(isSubtype);
      bool result = closedWorld.hasElementIn(base, name, element) ||
          closedWorld.classHierarchy.isSubtypeOf(other, base) ||
          closedWorld.hasAnySubclassThatImplements(other, base) ||
          closedWorld.hasAnySubclassOfMixinUseThatImplements(other, base);
      if (result) return true;
      // If the class is used as a mixin, we have to check if the element
      // can be hit from any of the mixin applications.
      Iterable<ClassEntity> mixinUses = closedWorld.mixinUsesOf(base);
      return mixinUses.any((mixinApplication) =>
          closedWorld.hasElementIn(mixinApplication, name, element) ||
          closedWorld.classHierarchy.isSubclassOf(other, mixinApplication) ||
          closedWorld.hasAnySubclassThatMixes(mixinApplication, other));
    }
  }

  @override
  bool needsNoSuchMethodHandling(
      Selector selector, covariant JClosedWorld closedWorld) {
    // A call on an empty type mask is either dead code, or a call on
    // `null`.
    if (isEmptyOrFlagged) return false;
    // A call on an exact mask for an abstract class is dead code.
    // TODO(johnniwinther): A type mask cannot be abstract. Remove the need
    // for this noise (currently used for super-calls in inference and mirror
    // usage).
    if (isExact && base.isAbstract) return false;

    return closedWorld.needsNoSuchMethod(base, selector, _classQuery);
  }

  @override
  MemberEntity locateSingleMember(Selector selector, CommonMasks domain) {
    if (isEmptyOrFlagged) return null;
    JClosedWorld closedWorld = domain._closedWorld;
    if (closedWorld.includesClosureCallInDomain(selector, this, domain))
      return null;
    Iterable<MemberEntity> targets =
        closedWorld.locateMembersInDomain(selector, this, domain);
    if (targets.length != 1) return null;
    MemberEntity result = targets.first;
    ClassEntity enclosing = result.enclosingClass;
    // We only return the found element if it is guaranteed to be implemented on
    // all classes in the receiver type [this]. It could be found only in a
    // subclass or in an inheritance-wise unrelated class in case of subtype
    // selectors.
    if (isSubtype) {
      // if (closedWorld.isUsedAsMixin(enclosing)) {
      if (closedWorld.everySubtypeIsSubclassOfOrMixinUseOf(base, enclosing)) {
        return result;
      }
      //}
      return null;
    } else {
      if (closedWorld.classHierarchy.isSubclassOf(base, enclosing)) {
        return result;
      }
      if (closedWorld.isSubclassOfMixinUseOf(base, enclosing)) return result;
    }
    return null;
  }

  @override
  bool operator ==(var other) {
    if (identical(this, other)) return true;
    if (other is! FlatTypeMask) return false;
    FlatTypeMask otherMask = other;
    return (flags == otherMask.flags) && (base == otherMask.base);
  }

  @override
  int get hashCode {
    return (base == null ? 0 : base.hashCode) + 31 * flags.hashCode;
  }

  @override
  String toString() {
    StringBuffer buffer = StringBuffer('[');
    buffer.writeAll([
      if (isEmpty) 'empty',
      if (isNullable) 'null',
      if (hasLateSentinel) 'sentinel',
      if (isExact) 'exact=${base.name}',
      if (isSubclass) 'subclass=${base.name}',
      if (isSubtype) 'subtype=${base.name}',
    ], '|');
    buffer.write(']');
    return buffer.toString();
  }
}
