diff --git a/pkl-core/src/main/java/org/pkl/core/PType.java b/pkl-core/src/main/java/org/pkl/core/PType.java index 4a912156c..8312de05d 100644 --- a/pkl-core/src/main/java/org/pkl/core/PType.java +++ b/pkl-core/src/main/java/org/pkl/core/PType.java @@ -80,6 +80,17 @@ public abstract class PType implements Serializable { public String toString() { return ValueFormatter.basic().formatStringValue(literal, ""); } + + @Override + public boolean equals(@org.jspecify.annotations.Nullable Object obj) { + if (obj == this) return true; + return obj instanceof StringLiteral that && literal.equals(that.literal); + } + + @Override + public int hashCode() { + return literal.hashCode(); + } } public static final class Class extends PType { @@ -125,6 +136,19 @@ public abstract class PType implements Serializable { } return result; } + + @Override + public boolean equals(@org.jspecify.annotations.Nullable Object obj) { + if (obj == this) return true; + return obj instanceof Class that + && pClass.equals(that.pClass) + && typeArguments.equals(that.typeArguments); + } + + @Override + public int hashCode() { + return 31 * pClass.hashCode() + typeArguments.hashCode(); + } } public static final class Nullable extends PType { @@ -146,6 +170,17 @@ public abstract class PType implements Serializable { ? "(" + baseType + ")?" : baseType + "?"; } + + @Override + public boolean equals(@org.jspecify.annotations.Nullable Object obj) { + if (obj == this) return true; + return obj instanceof Nullable that && baseType.equals(that.baseType); + } + + @Override + public int hashCode() { + return baseType.hashCode(); + } } public static final class Constrained extends PType { @@ -176,6 +211,19 @@ public abstract class PType implements Serializable { + String.join(", ", constraints) + ")"; } + + @Override + public boolean equals(@org.jspecify.annotations.Nullable Object obj) { + if (obj == this) return true; + return obj instanceof Constrained that + && baseType.equals(that.baseType) + && constraints.equals(that.constraints); + } + + @Override + public int hashCode() { + return 31 * baseType.hashCode() + constraints.hashCode(); + } } public static final class Alias extends PType { @@ -223,6 +271,19 @@ public abstract class PType implements Serializable { } return result; } + + @Override + public boolean equals(@org.jspecify.annotations.Nullable Object obj) { + if (obj == this) return true; + return obj instanceof Alias that + && typeAlias.equals(that.typeAlias) + && typeArguments.equals(that.typeArguments); + } + + @Override + public int hashCode() { + return 31 * typeAlias.hashCode() + typeArguments.hashCode(); + } } public static final class Function extends PType { @@ -251,6 +312,19 @@ public abstract class PType implements Serializable { + ") -> " + returnType; } + + @Override + public boolean equals(@org.jspecify.annotations.Nullable Object obj) { + if (obj == this) return true; + return obj instanceof Function that + && parameterTypes.equals(that.parameterTypes) + && returnType.equals(that.returnType); + } + + @Override + public int hashCode() { + return 31 * parameterTypes.hashCode() + returnType.hashCode(); + } } public static final class Union extends PType { @@ -270,6 +344,17 @@ public abstract class PType implements Serializable { public String toString() { return elementTypes.stream().map(Object::toString).collect(Collectors.joining(" | ")); } + + @Override + public boolean equals(@org.jspecify.annotations.Nullable Object obj) { + if (obj == this) return true; + return obj instanceof Union that && elementTypes.equals(that.elementTypes); + } + + @Override + public int hashCode() { + return elementTypes.hashCode(); + } } public static final class TypeVariable extends PType { @@ -293,5 +378,16 @@ public abstract class PType implements Serializable { public String toString() { return typeParameter.getName(); } + + @Override + public boolean equals(@org.jspecify.annotations.Nullable Object obj) { + if (obj == this) return true; + return obj instanceof TypeVariable that && typeParameter.equals(that.typeParameter); + } + + @Override + public int hashCode() { + return typeParameter.hashCode(); + } } } diff --git a/pkl-core/src/test/files/LanguageSnippetTests/input/basic/reference.pkl b/pkl-core/src/test/files/LanguageSnippetTests/input/basic/reference.pkl new file mode 100644 index 000000000..f23589f8c --- /dev/null +++ b/pkl-core/src/test/files/LanguageSnippetTests/input/basic/reference.pkl @@ -0,0 +1,55 @@ +amends "../snippetTest.pkl" + +import "pkl:ref" + +local class D extends ref.Domain { + function renderReference(reference: ref.Reference): String = reference.getData().toString() +} + +local const d: D = new {} +local typealias Ref = ref.Reference + +local class Holder { + num: Int + text: String + lit: "literal" + small: Int8 + optional: Mapping + listing: Listing + union: Listing | Listing +} + +local const h: Holder = new { + num = 1 + text = "t" + lit = "literal" + small = 8 + optional { ["k"] = 5 } + listing { 1; 2 } + union = new Listing { 1 } +} + +local hRef1: Ref = ref.Reference(d, Holder, h) +local hRef2: Ref = ref.Reference(d, Holder, h) + +facts { + ["equality"] { + hRef1 == hRef2 + hRef1.num == hRef2.num + hRef1.lit == hRef2.lit + hRef1.small == hRef2.small + hRef1.optional["k"] == hRef2.optional["k"] + hRef1.listing[0] == hRef2.listing[0] + hRef1.union == hRef2.union + } + + ["inequality"] { + hRef1.num != hRef2.text + } + + ["set deduplication"] { + Set(hRef1.num, hRef2.num).length == 1 + Set(hRef1.union, hRef2.union).length == 1 + Set(hRef1.num, hRef2.text).length == 2 + } +} diff --git a/pkl-core/src/test/files/LanguageSnippetTests/output/basic/reference.pcf b/pkl-core/src/test/files/LanguageSnippetTests/output/basic/reference.pcf new file mode 100644 index 000000000..4c176b165 --- /dev/null +++ b/pkl-core/src/test/files/LanguageSnippetTests/output/basic/reference.pcf @@ -0,0 +1,19 @@ +facts { + ["equality"] { + true + true + true + true + true + true + true + } + ["inequality"] { + true + } + ["set deduplication"] { + true + true + true + } +}