mirror of
https://github.com/apple/pkl.git
synced 2026-05-28 01:29:15 +02:00
Fix equals/hashCode/hasCachedValue in delegating listings/mappings (#781)
This fixes issues when a mapping/listing delegates to another mapping/listing. The core issue is that `cachedValues` is not guaranteed to be the complete set of the object's members; they may be stored on the delegate instead. Therefore, it's not correct compute hash code and equality based on `cachedValues`. Instead, it's better to use the `getCachedValue()` method, which has the correct logic for looking up the existing cached value.
This commit is contained in:
@@ -34,6 +34,12 @@ local empty2 = (empty) {
|
||||
local function `_`() = 42
|
||||
}
|
||||
|
||||
local typedMapping: Mapping<String, String> = new {
|
||||
["hello"] = "hellooooo"
|
||||
}
|
||||
|
||||
local delegatingTypedMapping: Mapping<String, String|Int> = typedMapping
|
||||
|
||||
facts {
|
||||
["isEmpty"] {
|
||||
!base.isEmpty
|
||||
@@ -56,6 +62,8 @@ facts {
|
||||
!empty.containsKey("Pigeon")
|
||||
!empty.containsKey("default")
|
||||
!empty2.containsKey("Pigeon")
|
||||
|
||||
delegatingTypedMapping.containsKey("hello")
|
||||
}
|
||||
|
||||
["containsValue()"] {
|
||||
|
||||
@@ -23,3 +23,14 @@ res10 = new Listing { "one" } == new Listing { "one"; default = 9 }
|
||||
res11 = new Listing { x; local x = "one" } == new Listing { "one" }
|
||||
res12 = new Listing { x; local x = "one"; local `_` = "two" } == new Listing { "one"; default = 9 }
|
||||
res13 = new Listing { x; local x = "one" } { y; local y = "two" } == new Listing { "one"; "two" }
|
||||
|
||||
local class Bird { name: String }
|
||||
|
||||
local l1: Listing<Bird> = new {
|
||||
new { name = "Pigeon" }
|
||||
new { name = "Stork" }
|
||||
}
|
||||
|
||||
local l2: Listing<Bird|Int> = l1
|
||||
|
||||
res14 = l1 == l2
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
amends "../snippetTest.pkl"
|
||||
|
||||
local class Bird {
|
||||
name: String
|
||||
}
|
||||
|
||||
facts {
|
||||
local set: Set<Int> = IntSeq(1, 100).fold(Set(), (res, n) -> res.add(n))
|
||||
|
||||
@@ -23,3 +27,31 @@ facts {
|
||||
set.add(listing1).add(listing2).length == 101
|
||||
}
|
||||
}
|
||||
|
||||
examples {
|
||||
["delegating listings compute correct hash codes"] {
|
||||
local l1: Listing<Bird> = new {
|
||||
new { name = "Pigeon" }
|
||||
new { name = "Stork" }
|
||||
}
|
||||
|
||||
local l2: Listing<Bird|Int> = l1
|
||||
|
||||
// need to add 6 other elements here; `EconomicMap` will back shorter collections
|
||||
// with an array and not compute hash code
|
||||
List(1, 2, 3, 4, 5, 6, l2, l1).distinct
|
||||
}
|
||||
|
||||
["delegating listings compute correct hash codes -- re-use hash-code"] {
|
||||
local l1: Listing<Bird> = new {
|
||||
new { name = "Pigeon" }
|
||||
new { name = "Stork" }
|
||||
}
|
||||
|
||||
local l2: Listing<Bird|Int> = l1
|
||||
|
||||
// same as the other test but put `l1` first this time (execute code path where we re-use
|
||||
// already computed hashcode)
|
||||
List(1, 2, 3, 4, 5, 6, l1, l2).distinct
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,3 +24,14 @@ res10 = new Mapping { ["one"] = 1 } == new Mapping { ["one"] = 1; default = 1 }
|
||||
res11 = new Mapping { ["one"] = x; local x = 1 } == new Mapping { ["one"] = 1 }
|
||||
res12 = new Mapping { ["one"] = x; local x = 1; local `_` = "two" } == new Mapping { ["one"] = 1; default = 9 }
|
||||
res13 = new Mapping { ["one"] = x; local x = 1 } { ["two"] = y; local y = 2 } == new Mapping { ["one"] = 1; ["two"] = 2 }
|
||||
|
||||
class Bird { name: String }
|
||||
|
||||
local m1: Mapping<String, Bird> = new {
|
||||
["Pigeon"] = new { name = "Pigeon" }
|
||||
["Stork"] = new { name = "Stork" }
|
||||
}
|
||||
|
||||
local m2: Mapping<String, Bird|Int> = m1
|
||||
|
||||
res14 = m1 == m2
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
amends "../snippetTest.pkl"
|
||||
|
||||
local class Bird { name: String }
|
||||
|
||||
facts {
|
||||
local set: Set<Int> = IntSeq(1, 100).fold(Set(), (res, n) -> res.add(n))
|
||||
|
||||
@@ -23,3 +25,31 @@ facts {
|
||||
set.add(mapping1).add(mapping2).length == 101
|
||||
}
|
||||
}
|
||||
|
||||
examples {
|
||||
["delegating mappings produce correct hash codes"] {
|
||||
local m1: Mapping<String, Bird> = new {
|
||||
["Pigeon"] = new { name = "Pigeon" }
|
||||
["Stork"] = new { name = "Stork" }
|
||||
}
|
||||
|
||||
local m2: Mapping<String, Bird|Int> = m1
|
||||
|
||||
// need to add 6 other elements here; `EconomicMap` will back shorter collections
|
||||
// with an array and not compute hash code
|
||||
List(1, 2, 3, 4, 5, 6, m2, m1).distinct
|
||||
}
|
||||
|
||||
["delegating mappings produce correct hash codes -- re-use hash-code"] {
|
||||
local m1: Mapping<String, Bird> = new {
|
||||
["Pigeon"] = new { name = "Pigeon" }
|
||||
["Stork"] = new { name = "Stork" }
|
||||
}
|
||||
|
||||
local m2: Mapping<String, Bird|Int> = m1
|
||||
|
||||
// same as the other test but put `m1` first this time (execute code path where we re-use
|
||||
// already computed hashcode)
|
||||
List(1, 2, 3, 4, 5, 6, m1, m2).distinct
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ facts {
|
||||
true
|
||||
true
|
||||
true
|
||||
true
|
||||
}
|
||||
["containsValue()"] {
|
||||
true
|
||||
|
||||
@@ -10,3 +10,4 @@ res10 = true
|
||||
res11 = true
|
||||
res12 = true
|
||||
res13 = true
|
||||
res14 = true
|
||||
|
||||
@@ -11,3 +11,25 @@ facts {
|
||||
true
|
||||
}
|
||||
}
|
||||
examples {
|
||||
["delegating listings compute correct hash codes"] {
|
||||
List(1, 2, 3, 4, 5, 6, new {
|
||||
new {
|
||||
name = "Pigeon"
|
||||
}
|
||||
new {
|
||||
name = "Stork"
|
||||
}
|
||||
})
|
||||
}
|
||||
["delegating listings compute correct hash codes -- re-use hash-code"] {
|
||||
List(1, 2, 3, 4, 5, 6, new {
|
||||
new {
|
||||
name = "Pigeon"
|
||||
}
|
||||
new {
|
||||
name = "Stork"
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,3 +11,4 @@ res10 = true
|
||||
res11 = true
|
||||
res12 = true
|
||||
res13 = true
|
||||
res14 = true
|
||||
|
||||
@@ -11,3 +11,25 @@ facts {
|
||||
true
|
||||
}
|
||||
}
|
||||
examples {
|
||||
["delegating mappings produce correct hash codes"] {
|
||||
List(1, 2, 3, 4, 5, 6, new {
|
||||
["Pigeon"] {
|
||||
name = "Pigeon"
|
||||
}
|
||||
["Stork"] {
|
||||
name = "Stork"
|
||||
}
|
||||
})
|
||||
}
|
||||
["delegating mappings produce correct hash codes -- re-use hash-code"] {
|
||||
List(1, 2, 3, 4, 5, 6, new {
|
||||
["Pigeon"] {
|
||||
name = "Pigeon"
|
||||
}
|
||||
["Stork"] {
|
||||
name = "Stork"
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user