blob: 0b1ffb6e7b3aee14a3634e6bb889754deafc4ccd [file] [log] [blame]
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of masks;
/// A [SetTypeMask] is a [TypeMask] for a specific allocation site of a set
/// (currently only the internal Set class) that will get specialized once the
/// [TypeGraphInferrer] phase finds an element type for it.
class SetTypeMask extends AllocationTypeMask {
/// Tag used for identifying serialized [SetTypeMask] objects in a debugging
/// data stream.
static const String tag = 'set-type-mask';
@override
final TypeMask forwardTo;
@override
final ir.Node allocationNode;
@override
final MemberEntity allocationElement;
// The element type of this set.
final TypeMask elementType;
SetTypeMask(this.forwardTo, this.allocationNode, this.allocationElement,
this.elementType);
/// Deserializes a [SetTypeMask] object from [source].
factory SetTypeMask.readFromDataSource(
DataSource source, JClosedWorld closedWorld) {
source.begin(tag);
TypeMask forwardTo = new TypeMask.readFromDataSource(source, closedWorld);
ir.TreeNode allocationNode = source.readTreeNodeOrNull();
MemberEntity allocationElement = source.readMemberOrNull();
TypeMask elementType = new TypeMask.readFromDataSource(source, closedWorld);
source.end(tag);
return new SetTypeMask(
forwardTo, allocationNode, allocationElement, elementType);
}
/// Serializes this [SetTypeMask] to [sink].
@override
void writeToDataSink(DataSink sink) {
sink.writeEnum(TypeMaskKind.set);
sink.begin(tag);
forwardTo.writeToDataSink(sink);
sink.writeTreeNodeOrNull(allocationNode);
sink.writeMemberOrNull(allocationElement);
elementType.writeToDataSink(sink);
sink.end(tag);
}
@override
TypeMask nullable() => isNullable
? this
: new SetTypeMask(
forwardTo.nullable(), allocationNode, allocationElement, elementType);
@override
TypeMask nonNullable() => isNullable
? new SetTypeMask(forwardTo.nonNullable(), allocationNode,
allocationElement, elementType)
: this;
@override
bool get isSet => true;
@override
bool get isExact => true;
@override
bool equalsDisregardNull(other) {
if (other is! SetTypeMask) return false;
return super.equalsDisregardNull(other) &&
allocationNode == other.allocationNode &&
elementType == other.elementType;
}
@override
TypeMask intersection(TypeMask other, JClosedWorld closedWorld) {
TypeMask forwardIntersection = forwardTo.intersection(other, closedWorld);
if (forwardIntersection.isEmptyOrNull) return forwardIntersection;
return forwardIntersection.isNullable ? nullable() : nonNullable();
}
@override
TypeMask union(dynamic other, JClosedWorld closedWorld) {
if (this == other) {
return this;
} else if (equalsDisregardNull(other)) {
return other.isNullable ? other : this;
} else if (other.isEmptyOrNull) {
return other.isNullable ? this.nullable() : this;
} else if (other.isSet &&
elementType != null &&
other.elementType != null) {
TypeMask newElementType =
elementType.union(other.elementType, closedWorld);
TypeMask newForwardTo = forwardTo.union(other.forwardTo, closedWorld);
return new SetTypeMask(newForwardTo, null, null, newElementType);
} else {
return forwardTo.union(other, closedWorld);
}
}
@override
bool operator ==(other) => super == other;
@override
int get hashCode =>
computeHashCode(allocationNode, isNullable, elementType, forwardTo);
@override
String toString() => 'Set($forwardTo, element: $elementType)';
}