Skip to content

Commit 6bd5bfc

Browse files
committed
yer
1 parent 19661d3 commit 6bd5bfc

9 files changed

Lines changed: 152 additions & 94 deletions

File tree

pkl-core/src/main/java/org/pkl/core/ast/type/TypeNode.java

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
2121
import com.oracle.truffle.api.dsl.Cached;
2222
import com.oracle.truffle.api.dsl.Fallback;
23+
import com.oracle.truffle.api.dsl.ImportStatic;
2324
import com.oracle.truffle.api.dsl.Specialization;
2425
import com.oracle.truffle.api.frame.Frame;
2526
import com.oracle.truffle.api.frame.FrameDescriptor;
@@ -1948,8 +1949,9 @@ protected boolean isParametric() {
19481949
}
19491950
}
19501951

1951-
public static final class ReferenceTypeNode extends ObjectSlotTypeNode {
1952-
@Child private TypeNode valueTypeNode;
1952+
@ImportStatic(BaseModule.class)
1953+
public abstract static class ReferenceTypeNode extends ObjectSlotTypeNode {
1954+
private TypeNode valueTypeNode;
19531955
@Child private ExpressionNode getModuleNode;
19541956

19551957
public ReferenceTypeNode(SourceSection sourceSection, TypeNode valueTypeNode) {
@@ -1958,30 +1960,27 @@ public ReferenceTypeNode(SourceSection sourceSection, TypeNode valueTypeNode) {
19581960
this.getModuleNode = new GetModuleNode(sourceSection);
19591961
}
19601962

1961-
@Override
1962-
protected Object executeLazily(VirtualFrame frame, Object value) {
1963-
return doExecute(frame, value);
1964-
}
1965-
1966-
@Override
1967-
public Object executeEagerly(VirtualFrame frame, Object value) {
1968-
return doExecute(frame, value);
1969-
}
1963+
@SuppressWarnings("unused")
1964+
@Specialization(guards = "value.getVmClass() == getReferenceClass()")
1965+
protected Object eval(VirtualFrame frame, VmReference value) {
1966+
if (valueTypeNode.isNoopTypeCheck()) {
1967+
return value;
1968+
}
19701969

1971-
private Object doExecute(VirtualFrame frame, Object value) {
1972-
if (value instanceof VmReference vmReference) {
1973-
var module = (VmTyped) getModuleNode.executeGeneric(frame);
1974-
if (vmReference.checkType(TypeNode.export(valueTypeNode), module.getVmClass().export())) {
1975-
return value;
1976-
}
1977-
// TODO better exceptions?
1978-
throw new VmExceptionBuilder()
1979-
.adhocEvalError(
1980-
"reference type mismatch Reference<%s> and %s",
1981-
vmReference.getCandidateTypes(), TypeNode.export(valueTypeNode))
1982-
.build();
1970+
var module = (VmTyped) getModuleNode.executeGeneric(frame);
1971+
if (value.checkType(TypeNode.export(valueTypeNode), module.getVmClass().export())) {
1972+
return value;
19831973
}
1974+
// TODO better exceptions?
1975+
throw new VmExceptionBuilder()
1976+
.adhocEvalError(
1977+
"reference type mismatch Reference<%s> and %s",
1978+
value.getCandidateTypes(), TypeNode.export(valueTypeNode))
1979+
.build();
1980+
}
19841981

1982+
@Fallback
1983+
protected Object fallback(Object value) {
19851984
throw typeMismatch(value, BaseModule.getReferenceClass());
19861985
}
19871986

@@ -2008,6 +2007,11 @@ protected boolean doIsEquivalentTo(TypeNode other) {
20082007
return valueTypeNode.isEquivalentTo(referenceTypeNode.valueTypeNode);
20092008
}
20102009

2010+
@Override
2011+
public boolean isNoopTypeCheck() {
2012+
return valueTypeNode.isNoopTypeCheck();
2013+
}
2014+
20112015
@Override
20122016
protected PType doExport() {
20132017
return new PType.Class(BaseModule.getReferenceClass().export(), valueTypeNode.doExport());

pkl-core/src/main/java/org/pkl/core/ast/type/UnresolvedTypeNode.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ public TypeNode execute(VirtualFrame frame) {
288288
}
289289

290290
if (clazz.isReferenceClass()) {
291-
return new ReferenceTypeNode(sourceSection, typeArgumentNodes[0].execute(frame));
291+
return ReferenceTypeNodeGen.create(sourceSection, typeArgumentNodes[0].execute(frame));
292292
}
293293

294294
throw exceptionBuilder()

pkl-core/src/main/java/org/pkl/core/runtime/VmClass.java

Lines changed: 52 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -616,54 +616,66 @@ public VmMap getAllMethodMirrors() {
616616
@TruffleBoundary
617617
public PClass export() {
618618
synchronized (pClassLock) {
619-
if (__pClass == null) {
620-
var exportedAnnotations = new ArrayList<PObject>();
621-
var properties =
622-
CollectionUtils.<String, PClass.Property>newLinkedHashMap(
623-
EconomicMaps.size(declaredProperties));
624-
var methods =
625-
CollectionUtils.<String, PClass.Method>newLinkedHashMap(
626-
EconomicMaps.size(declaredMethods));
627-
628-
// set pClass before exporting class members to prevent
629-
// infinite recursion in case of cyclic references
630-
__pClass =
631-
new PClass(
632-
VmUtils.exportDocComment(docComment),
633-
new SourceLocation(headerSection.getStartLine(), sourceSection.getEndLine()),
634-
VmModifier.export(modifiers, true),
635-
exportedAnnotations,
636-
classInfo,
637-
typeParameters,
638-
properties,
639-
methods,
640-
classInfo.isModuleClass() ? null : getModule().getVmClass().export());
641-
642-
for (var parameter : typeParameters) {
643-
parameter.initOwner(__pClass);
644-
}
619+
if (__pClass != null) {
620+
return __pClass;
621+
}
645622

646-
if (supertypeNode != null) {
647-
assert superclass != null;
648-
__pClass.initSupertype(TypeNode.export(supertypeNode), superclass.export());
649-
}
623+
// if this is not a module class, export this class's module's class first to break the cycle
624+
PClass moduleClass = null;
625+
if (!classInfo.isModuleClass()) {
626+
moduleClass = getModule().getVmClass().export();
627+
}
628+
// then if the cached value is still null, initialize it
629+
if (__pClass != null) {
630+
return __pClass;
631+
}
650632

651-
VmUtils.exportAnnotations(annotations, exportedAnnotations);
633+
var exportedAnnotations = new ArrayList<PObject>();
634+
var properties =
635+
CollectionUtils.<String, PClass.Property>newLinkedHashMap(
636+
EconomicMaps.size(declaredProperties));
637+
var methods =
638+
CollectionUtils.<String, PClass.Method>newLinkedHashMap(
639+
EconomicMaps.size(declaredMethods));
640+
641+
// set pClass before exporting class members to prevent
642+
// infinite recursion in case of cyclic references
643+
__pClass =
644+
new PClass(
645+
VmUtils.exportDocComment(docComment),
646+
new SourceLocation(headerSection.getStartLine(), sourceSection.getEndLine()),
647+
VmModifier.export(modifiers, true),
648+
exportedAnnotations,
649+
classInfo,
650+
typeParameters,
651+
properties,
652+
methods,
653+
moduleClass);
654+
655+
for (var parameter : typeParameters) {
656+
parameter.initOwner(__pClass);
657+
}
652658

653-
for (var property : EconomicMaps.getValues(declaredProperties)) {
654-
if (isClassPropertyDefinition(property)) {
655-
properties.put(property.getName().toString(), property.export(__pClass));
656-
}
657-
}
659+
if (supertypeNode != null) {
660+
assert superclass != null;
661+
__pClass.initSupertype(TypeNode.export(supertypeNode), superclass.export());
662+
}
663+
664+
VmUtils.exportAnnotations(annotations, exportedAnnotations);
658665

659-
for (var method : EconomicMaps.getValues(declaredMethods)) {
660-
if (method.isLocal()) continue;
661-
methods.put(method.getName().toString(), method.export(__pClass));
666+
for (var property : EconomicMaps.getValues(declaredProperties)) {
667+
if (isClassPropertyDefinition(property)) {
668+
properties.put(property.getName().toString(), property.export(__pClass));
662669
}
663670
}
664671

665-
return __pClass;
672+
for (var method : EconomicMaps.getValues(declaredMethods)) {
673+
if (method.isLocal()) continue;
674+
methods.put(method.getName().toString(), method.export(__pClass));
675+
}
666676
}
677+
678+
return __pClass;
667679
}
668680

669681
@Override

pkl-core/src/main/java/org/pkl/core/runtime/VmPklBinaryEncoder.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.util.Deque;
2020
import org.msgpack.core.MessageBufferPacker;
2121
import org.pkl.core.PklBugException;
22+
import org.pkl.core.runtime.VmReference.Access;
2223
import org.pkl.core.stdlib.AbstractRenderer;
2324
import org.pkl.core.stdlib.PklConverter;
2425
import org.pkl.core.util.pklbinary.PklBinaryCode;
@@ -324,6 +325,38 @@ public void visitFunction(VmFunction value) {
324325
}
325326
}
326327

328+
@Override
329+
public void visitReference(VmReference value) {
330+
try {
331+
packer.packArrayHeader(3);
332+
packCode(PklBinaryCode.REFERENCE);
333+
visit(value.getRootValue());
334+
packer.packArrayHeader(value.getPath().size());
335+
for (var access : value.getPath()) {
336+
visit(access);
337+
}
338+
} catch (IOException e) {
339+
throw PklBugException.unreachableCode();
340+
}
341+
}
342+
343+
@Override
344+
public void visitReferenceAccess(Access value) {
345+
try {
346+
packer.packArrayHeader(3);
347+
packCode(PklBinaryCode.REFERENCE_ACCESS);
348+
if (value.isProperty()) {
349+
packer.packString(value.getProperty());
350+
packer.packNil();
351+
} else {
352+
packer.packNil();
353+
visit(value.getKey());
354+
}
355+
} catch (IOException e) {
356+
throw PklBugException.unreachableCode();
357+
}
358+
}
359+
327360
@Override
328361
protected void visitEntryKey(Object key, boolean isFirst) {
329362
visit(key);

pkl-core/src/main/java/org/pkl/core/runtime/VmReference.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ public final class VmReference extends VmValue {
4545
private boolean forced = false;
4646

4747
private static final PType nullType = new PType.Class(BaseModule.getNullClass().export());
48-
4948
private static final Set<TypeAlias> intAliasTypes = getIntAliasTypes();
5049
private static final Set<TypeAlias> preservedAliasTypes = intAliasTypes;
5150

@@ -169,7 +168,9 @@ private static void getCandidatePropertyType(PType type, String property, Set<PT
169168
return;
170169
}
171170
if (klass.getPClass().getInfo() == PClassInfo.Listing
172-
|| klass.getPClass().getInfo() == PClassInfo.Mapping) {
171+
|| klass.getPClass().getInfo() == PClassInfo.List
172+
|| klass.getPClass().getInfo() == PClassInfo.Mapping
173+
|| klass.getPClass().getInfo() == PClassInfo.Map) {
173174
return;
174175
}
175176
// Typed
@@ -193,13 +194,15 @@ private static void getCandidateSubscriptType(PType type, Object key, Set<PType>
193194
result.add(PType.UNKNOWN);
194195
return;
195196
}
196-
if (klass.getPClass().getInfo() == PClassInfo.Listing) {
197+
if (klass.getPClass().getInfo() == PClassInfo.Listing
198+
|| klass.getPClass().getInfo() == PClassInfo.List) {
197199
if (key instanceof Long) {
198200
simplifyType(klass.getTypeArguments().get(0), klass.getPClass().getModuleClass(), result);
199201
}
200202
return;
201203
}
202-
if (klass.getPClass().getInfo() == PClassInfo.Mapping) {
204+
if (klass.getPClass().getInfo() == PClassInfo.Mapping
205+
|| klass.getPClass().getInfo() == PClassInfo.Map) {
203206
var typeArgs = klass.getTypeArguments();
204207
var keyTypes = simplifyType(typeArgs.get(0), klass.getPClass().getModuleClass());
205208
for (var kt : keyTypes) {

pkl-core/src/main/java/org/pkl/core/util/pklbinary/PklBinaryCode.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ public enum PklBinaryCode {
3333
TYPEALIAS((byte) 0x0D),
3434
FUNCTION((byte) 0x0E),
3535
BYTES((byte) 0x0F),
36+
REFERENCE((byte) 0x20),
37+
REFERENCE_ACCESS((byte) 0x21),
3638

3739
PROPERTY((byte) 0x10),
3840
ENTRY((byte) 0x11),

pkl-core/src/test/files/LanguageSnippetTests/input/api/reference.pkl

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ class AProperties {
1818
}
1919

2020
class B extends Resource {
21-
aId: String|Reference<String>
22-
aProperties: AProperties|Reference<AProperties>
23-
aValues: Listing<Int|Reference<Int>>
21+
aId: String | Reference<String>
22+
aProperties: AProperties | Reference<AProperties>
23+
aValues: Listing<Int | Reference<Int>>
2424
}
2525

2626
a: A = new {
@@ -45,11 +45,17 @@ b: B = new {
4545

4646
function renderReference(ref: Reference): String =
4747
if (ref.getRootValue() is Resource)
48-
(ref.getRootValue() as Resource).name + ref.getPath().toList().map((elem) ->
49-
if (elem.isProperty) ".\(elem.property)"
50-
else "[\(elem.key)]"
51-
).join("")
52-
else throw("can only render references rooted to Resource instances")
48+
let (resource = ref.getRootValue() as Resource)
49+
let (
50+
path =
51+
ref
52+
.getPath()
53+
.toList()
54+
.map((elem) -> if (elem.isProperty) ".\(elem.property)" else "[\(elem.key)]")
55+
)
56+
"${\(resource.name)\(path.join(""))}"
57+
else
58+
throw("can only render references rooted to Resource instances")
5359

5460
output {
5561
renderer {

pkl-core/src/test/files/LanguageSnippetTests/output/api/reference.err

Lines changed: 0 additions & 18 deletions
This file was deleted.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
a {
2+
name = "a"
3+
id = "some-a-value"
4+
}
5+
b {
6+
name = "b"
7+
aId = "${a.id}"
8+
aProperties = "${a.outputs}"
9+
aValues {
10+
"${a.outputs.foo}"
11+
"${a.outputs.someMapping[key]}"
12+
"${a.outputs.someMap[123]}"
13+
"${a.outputs.someListing[0]}"
14+
"${a.outputs.someList[9223372036854775807]}"
15+
}
16+
}

0 commit comments

Comments
 (0)