Fix encoding for mapping with local members (#1152)

Fixes an issue where local members are included in
the mapping entry count.

Also: avoid re-computing Mapping.length
This commit is contained in:
Daniel Chao
2025-07-28 10:13:45 -07:00
committed by GitHub
parent a3cc2f0ea6
commit 20e7e251ec
5 changed files with 54 additions and 32 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@ package org.pkl.core.runtime;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.frame.MaterializedFrame;
import java.util.HashSet;
import java.util.Map;
import javax.annotation.concurrent.GuardedBy;
import org.graalvm.collections.UnmodifiableEconomicMap;
@@ -25,10 +26,10 @@ import org.pkl.core.ast.member.ObjectMember;
import org.pkl.core.util.CollectionUtils;
import org.pkl.core.util.EconomicMaps;
import org.pkl.core.util.LateInit;
import org.pkl.core.util.MutableLong;
public final class VmMapping extends VmListingOrMapping {
private int cachedEntryCount = -1;
private long cachedLength = -1;
@GuardedBy("this")
private @LateInit VmSet __allKeys;
@@ -124,7 +125,7 @@ public final class VmMapping extends VmListingOrMapping {
// could use shallow force, but deep force is cached
force(false);
other.force(false);
if (getEntryCount() != other.getEntryCount()) return false;
if (getLength() != other.getLength()) return false;
var cursor = cachedValues.getEntries();
while (cursor.advance()) {
@@ -162,16 +163,21 @@ public final class VmMapping extends VmListingOrMapping {
return result;
}
// assumes mapping has been forced
public int getEntryCount() {
if (cachedEntryCount != -1) return cachedEntryCount;
var result = 0;
for (var key : cachedValues.getKeys()) {
if (key instanceof Identifier) continue;
result += 1;
}
cachedEntryCount = result;
return result;
@TruffleBoundary
public long getLength() {
if (cachedLength != -1) return cachedLength;
var count = new MutableLong(0);
var visited = new HashSet<>();
iterateMembers(
(key, member) -> {
var alreadyVisited = !visited.add(key);
// important to record hidden member as visited before skipping it
// because any overriding member won't carry a `hidden` identifier
if (alreadyVisited || member.isLocalOrExternalOrHidden()) return true;
count.getAndIncrement();
return true;
});
cachedLength = count.get();
return cachedLength;
}
}

View File

@@ -18,7 +18,6 @@ package org.pkl.core.stdlib.base;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.IndirectCallNode;
import java.util.HashSet;
import org.pkl.core.ast.lambda.ApplyVmFunction1Node;
import org.pkl.core.ast.lambda.ApplyVmFunction2Node;
import org.pkl.core.ast.lambda.ApplyVmFunction2NodeGen;
@@ -31,7 +30,6 @@ import org.pkl.core.stdlib.ExternalMethod2Node;
import org.pkl.core.stdlib.ExternalPropertyNode;
import org.pkl.core.util.EconomicMaps;
import org.pkl.core.util.MutableBoolean;
import org.pkl.core.util.MutableLong;
import org.pkl.core.util.MutableReference;
public final class MappingNodes {
@@ -53,20 +51,8 @@ public final class MappingNodes {
public abstract static class length extends ExternalPropertyNode {
@Specialization
@TruffleBoundary
protected long eval(VmMapping self) {
var count = new MutableLong(0);
var visited = new HashSet<>();
self.iterateMembers(
(key, member) -> {
var alreadyVisited = !visited.add(key);
// important to record hidden member as visited before skipping it
// because any overriding member won't carry a `hidden` identifier
if (alreadyVisited || member.isLocalOrExternalOrHidden()) return true;
count.getAndIncrement();
return true;
});
return count.get();
return self.getLength();
}
}

View File

@@ -221,7 +221,7 @@ internal class BinaryEvaluator(
override fun visitMapping(value: VmMapping) {
packer.packArrayHeader(2)
packer.packInt(CODE_MAPPING.toInt())
packer.packMapHeader(value.entryCount)
packer.packMapHeader(value.length.toInt())
value.iterateAlreadyForcedMemberValues { key, _, memberValue ->
visit(key)
visit(memberValue)

View File

@@ -13,3 +13,9 @@ res4: Mapping = new {
["bar"] = 2
}
}
// https://github.com/apple/pkl/issues/1151
res5: Mapping = new {
local self = this
["foo"] = new Dynamic { name = "foo" }
["bar"] = new Dynamic { name = self["foo"].name + "bar" }
}

View File

@@ -41,4 +41,28 @@
:
- 3
-
bar: 2
bar: 2
-
- 16
- res5
-
- 3
-
foo:
- 1
- Dynamic
- pkl:base
-
-
- 16
- name
- foo
bar:
- 1
- Dynamic
- pkl:base
-
-
- 16
- name
- foobar