mirror of
https://github.com/apple/pkl.git
synced 2026-06-25 06:46:18 +02:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f61a5cf541 | |||
| dd6939ab3f | |||
| f7cac257ad | |||
| 1bf00b84ea | |||
| 15f089b275 | |||
| 8a43e51e6b | |||
| b3015a09cc | |||
| ffc755f9c1 | |||
| 112a89468f | |||
| bfac0d66ed | |||
| fc8fe86e5a |
@@ -13,10 +13,13 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
import java.nio.file.AtomicMoveNotSupportedException
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
|
import java.nio.file.Path
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
import java.nio.file.StandardCopyOption
|
import java.nio.file.StandardCopyOption
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import java.util.zip.ZipInputStream
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.io.path.createDirectories
|
import kotlin.io.path.createDirectories
|
||||||
import org.gradle.api.DefaultTask
|
import org.gradle.api.DefaultTask
|
||||||
@@ -41,19 +44,14 @@ constructor(
|
|||||||
@TaskAction
|
@TaskAction
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
fun run() {
|
fun run() {
|
||||||
// minimize chance of corruption by extract-to-random-dir-and-flip-symlink
|
// minimize chance of corruption by extract-to-random-dir-and-publish
|
||||||
val distroDir = Paths.get(graalVm.get().homeDir, UUID.randomUUID().toString())
|
val distroDir = Paths.get(graalVm.get().homeDir, UUID.randomUUID().toString())
|
||||||
try {
|
try {
|
||||||
distroDir.createDirectories()
|
distroDir.createDirectories()
|
||||||
println("Extracting ${graalVm.get().downloadFile} into $distroDir")
|
println("Extracting ${graalVm.get().downloadFile} into $distroDir")
|
||||||
// faster and more reliable than Gradle's `copy { from tarTree() }`
|
|
||||||
execOperations.exec {
|
|
||||||
workingDir = distroDir.toFile()
|
|
||||||
executable = "tar"
|
|
||||||
args("--strip-components=1", "-xzf", graalVm.get().downloadFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
val os = org.gradle.internal.os.OperatingSystem.current()
|
val os = org.gradle.internal.os.OperatingSystem.current()
|
||||||
|
if (os.isWindows) extractZip(distroDir) else extractTarGz(distroDir)
|
||||||
|
|
||||||
val distroBinDir =
|
val distroBinDir =
|
||||||
if (os.isMacOsX) distroDir.resolve("Contents/Home/bin") else distroDir.resolve("bin")
|
if (os.isMacOsX) distroDir.resolve("Contents/Home/bin") else distroDir.resolve("bin")
|
||||||
|
|
||||||
@@ -70,17 +68,7 @@ constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
println("Creating symlink ${graalVm.get().installDir} for $distroDir")
|
publishInstallDir(distroDir, os)
|
||||||
val tempLink = Paths.get(graalVm.get().homeDir, UUID.randomUUID().toString())
|
|
||||||
Files.createSymbolicLink(tempLink, distroDir)
|
|
||||||
try {
|
|
||||||
Files.move(tempLink, graalVm.get().installDir.toPath(), StandardCopyOption.ATOMIC_MOVE)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
try {
|
|
||||||
fileOperations.delete(tempLink.toFile())
|
|
||||||
} catch (ignored: Exception) {}
|
|
||||||
throw e
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
try {
|
try {
|
||||||
fileOperations.delete(distroDir)
|
fileOperations.delete(distroDir)
|
||||||
@@ -88,4 +76,75 @@ constructor(
|
|||||||
throw e
|
throw e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun extractTarGz(distroDir: Path) {
|
||||||
|
// faster and more reliable than Gradle's `copy { from tarTree() }`
|
||||||
|
execOperations.exec {
|
||||||
|
workingDir = distroDir.toFile()
|
||||||
|
executable = "tar"
|
||||||
|
args("--strip-components=1", "-xzf", graalVm.get().downloadFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun extractZip(distroDir: Path) {
|
||||||
|
val targetDir = distroDir.toAbsolutePath().normalize()
|
||||||
|
ZipInputStream(graalVm.get().downloadFile.inputStream().buffered()).use { zipInput ->
|
||||||
|
var entry = zipInput.nextEntry
|
||||||
|
while (entry != null) {
|
||||||
|
try {
|
||||||
|
val strippedPath = stripFirstPathComponent(entry.name)
|
||||||
|
if (strippedPath != null) {
|
||||||
|
val target = targetDir.resolve(strippedPath).normalize()
|
||||||
|
require(target.startsWith(targetDir)) {
|
||||||
|
"GraalVM archive entry escapes destination directory: ${entry.name}"
|
||||||
|
}
|
||||||
|
if (entry.isDirectory) {
|
||||||
|
target.createDirectories()
|
||||||
|
} else {
|
||||||
|
target.parent?.createDirectories()
|
||||||
|
Files.copy(zipInput, target)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
zipInput.closeEntry()
|
||||||
|
}
|
||||||
|
entry = zipInput.nextEntry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun stripFirstPathComponent(path: String): String? {
|
||||||
|
val normalizedPath = path.replace('\\', '/').trimStart('/')
|
||||||
|
val separatorIndex = normalizedPath.indexOf('/')
|
||||||
|
if (separatorIndex == -1) return null
|
||||||
|
return normalizedPath.substring(separatorIndex + 1).takeIf { it.isNotEmpty() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun publishInstallDir(distroDir: Path, os: org.gradle.internal.os.OperatingSystem) {
|
||||||
|
if (os.isWindows) {
|
||||||
|
println("Installing ${graalVm.get().installDir} from $distroDir")
|
||||||
|
moveAtomicallyOrRegularly(distroDir, graalVm.get().installDir.toPath())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
println("Creating symlink ${graalVm.get().installDir} for $distroDir")
|
||||||
|
val tempLink = Paths.get(graalVm.get().homeDir, UUID.randomUUID().toString())
|
||||||
|
Files.createSymbolicLink(tempLink, distroDir)
|
||||||
|
try {
|
||||||
|
moveAtomicallyOrRegularly(tempLink, graalVm.get().installDir.toPath())
|
||||||
|
} catch (e: Exception) {
|
||||||
|
try {
|
||||||
|
fileOperations.delete(tempLink.toFile())
|
||||||
|
} catch (ignored: Exception) {}
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun moveAtomicallyOrRegularly(source: Path, target: Path) {
|
||||||
|
try {
|
||||||
|
Files.move(source, target, StandardCopyOption.ATOMIC_MOVE)
|
||||||
|
} catch (e: AtomicMoveNotSupportedException) {
|
||||||
|
Files.move(source, target)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ endif::[]
|
|||||||
|
|
||||||
:uri-stdlib-baseModule: {uri-pkl-stdlib-docs}/base
|
:uri-stdlib-baseModule: {uri-pkl-stdlib-docs}/base
|
||||||
:uri-stdlib-CommandModule: {uri-pkl-stdlib-docs}/Command
|
:uri-stdlib-CommandModule: {uri-pkl-stdlib-docs}/Command
|
||||||
|
:uri-stdlib-refModule: {uri-pkl-stdlib-docs}/ref
|
||||||
:uri-stdlib-analyzeModule: {uri-pkl-stdlib-docs}/analyze
|
:uri-stdlib-analyzeModule: {uri-pkl-stdlib-docs}/analyze
|
||||||
:uri-stdlib-jsonnetModule: {uri-pkl-stdlib-docs}/jsonnet
|
:uri-stdlib-jsonnetModule: {uri-pkl-stdlib-docs}/jsonnet
|
||||||
:uri-stdlib-reflectModule: {uri-pkl-stdlib-docs}/reflect
|
:uri-stdlib-reflectModule: {uri-pkl-stdlib-docs}/reflect
|
||||||
@@ -160,6 +161,8 @@ endif::[]
|
|||||||
:uri-stdlib-Command-CountedFlag: {uri-stdlib-CommandModule}/CountedFlag
|
:uri-stdlib-Command-CountedFlag: {uri-stdlib-CommandModule}/CountedFlag
|
||||||
:uri-stdlib-Command-Argument: {uri-stdlib-CommandModule}/Argument
|
:uri-stdlib-Command-Argument: {uri-stdlib-CommandModule}/Argument
|
||||||
:uri-stdlib-Command-Import: {uri-stdlib-CommandModule}/Import
|
:uri-stdlib-Command-Import: {uri-stdlib-CommandModule}/Import
|
||||||
|
:uri-stdlib-ref-Reference: {uri-stdlib-baseModule}/Reference
|
||||||
|
:uri-stdlib-ref-Access: {uri-stdlib-baseModule}/Access
|
||||||
|
|
||||||
:uri-messagepack: https://msgpack.org/index.html
|
:uri-messagepack: https://msgpack.org/index.html
|
||||||
:uri-messagepack-spec: https://github.com/msgpack/msgpack/blob/master/spec.md
|
:uri-messagepack-spec: https://github.com/msgpack/msgpack/blob/master/spec.md
|
||||||
|
|||||||
@@ -187,7 +187,15 @@ The array's length is the number of slots that are filled. For example, xref:{ur
|
|||||||
|
|
|
|
||||||
|
|
|
|
||||||
|
|
|
|
||||||
|===
|
|
||||||
|
|link:{uri-stdlib-ref-Reference}[Reference]
|
||||||
|
|`0x20`
|
||||||
|
|`<value>` (Typed)
|
||||||
|
|Domain
|
||||||
|
|`<value>`
|
||||||
|
|Data
|
||||||
|
|link:{uri-messagepack-array}[array]
|
||||||
|
|Array of link:{uri-stdlib-ref-Access}[`pkl.ref#Access`] values
|
||||||
|
|
||||||
[[type-name-encoding]]
|
[[type-name-encoding]]
|
||||||
[NOTE]
|
[NOTE]
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,7 @@ checksumPlugin = "1.4.0"
|
|||||||
clikt = "5.0.3"
|
clikt = "5.0.3"
|
||||||
commonMark = "0.28.0"
|
commonMark = "0.28.0"
|
||||||
downloadTaskPlugin = "5.7.0"
|
downloadTaskPlugin = "5.7.0"
|
||||||
errorProne = "2.49.0"
|
errorProne = "2.50.0"
|
||||||
errorPronePlugin = "5.1.0"
|
errorPronePlugin = "5.1.0"
|
||||||
geantyref = "2.0.1"
|
geantyref = "2.0.1"
|
||||||
#noinspection UnusedVersionCatalogEntry
|
#noinspection UnusedVersionCatalogEntry
|
||||||
@@ -54,7 +54,7 @@ ktfmt = "0.62"
|
|||||||
log4j = "2.17.1"
|
log4j = "2.17.1"
|
||||||
msgpack = "0.9.12"
|
msgpack = "0.9.12"
|
||||||
nexusPublishPlugin = "2.0.0"
|
nexusPublishPlugin = "2.0.0"
|
||||||
nullaway = "0.13.4"
|
nullaway = "0.13.6"
|
||||||
nullawayPlugin = "3.0.0"
|
nullawayPlugin = "3.0.0"
|
||||||
nuValidator = "26.5.29"
|
nuValidator = "26.5.29"
|
||||||
paguro = "3.10.3"
|
paguro = "3.10.3"
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ public final class PClass extends Member implements Value {
|
|||||||
private final List<TypeParameter> typeParameters;
|
private final List<TypeParameter> typeParameters;
|
||||||
private final Map<String, Property> properties;
|
private final Map<String, Property> properties;
|
||||||
private final Map<String, Method> methods;
|
private final Map<String, Method> methods;
|
||||||
|
private final @Nullable PClass moduleClass;
|
||||||
|
|
||||||
private @Nullable PType supertype;
|
private @Nullable PType supertype;
|
||||||
private @Nullable PClass superclass;
|
private @Nullable PClass superclass;
|
||||||
@@ -42,12 +43,14 @@ public final class PClass extends Member implements Value {
|
|||||||
PClassInfo<?> classInfo,
|
PClassInfo<?> classInfo,
|
||||||
List<TypeParameter> typeParameters,
|
List<TypeParameter> typeParameters,
|
||||||
Map<String, Property> properties,
|
Map<String, Property> properties,
|
||||||
Map<String, Method> methods) {
|
Map<String, Method> methods,
|
||||||
|
@Nullable PClass moduleClass) {
|
||||||
super(docComment, sourceLocation, modifiers, annotations, classInfo.getSimpleName());
|
super(docComment, sourceLocation, modifiers, annotations, classInfo.getSimpleName());
|
||||||
this.classInfo = classInfo;
|
this.classInfo = classInfo;
|
||||||
this.typeParameters = typeParameters;
|
this.typeParameters = typeParameters;
|
||||||
this.properties = properties;
|
this.properties = properties;
|
||||||
this.methods = methods;
|
this.methods = methods;
|
||||||
|
this.moduleClass = moduleClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initSupertype(PType supertype, PClass superclass) {
|
public void initSupertype(PType supertype, PClass superclass) {
|
||||||
@@ -57,7 +60,7 @@ public final class PClass extends Member implements Value {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the name of the module that this class is declared in. Note that a module name is not
|
* Returns the name of the module that this class is declared in. Note that a module name is not
|
||||||
* guaranteed to be unique, especially if it not declared but inferred from the module URI.
|
* guaranteed to be unique, especially if it is not declared but inferred from the module URI.
|
||||||
*/
|
*/
|
||||||
public String getModuleName() {
|
public String getModuleName() {
|
||||||
return classInfo.getModuleName();
|
return classInfo.getModuleName();
|
||||||
@@ -119,6 +122,11 @@ public final class PClass extends Member implements Value {
|
|||||||
return allMethods;
|
return allMethods;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns the class's containing module's class, or this class if it is a module class. */
|
||||||
|
public PClass getModuleClass() {
|
||||||
|
return moduleClass != null ? moduleClass : this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void accept(ValueVisitor visitor) {
|
public void accept(ValueVisitor visitor) {
|
||||||
visitor.visitClass(this);
|
visitor.visitClass(this);
|
||||||
@@ -138,6 +146,10 @@ public final class PClass extends Member implements Value {
|
|||||||
return getDisplayName();
|
return getDisplayName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isSubclassOf(PClass other) {
|
||||||
|
return this == other || getSuperclass() != null && getSuperclass().isSubclassOf(other);
|
||||||
|
}
|
||||||
|
|
||||||
public abstract static class ClassMember extends Member {
|
public abstract static class ClassMember extends Member {
|
||||||
@Serial private static final long serialVersionUID = 0L;
|
@Serial private static final long serialVersionUID = 0L;
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ public final class PClassInfo<T> implements Serializable {
|
|||||||
public static final URI pklSemverUri = URI.create("pkl:semver");
|
public static final URI pklSemverUri = URI.create("pkl:semver");
|
||||||
public static final URI pklSettingsUri = URI.create("pkl:settings");
|
public static final URI pklSettingsUri = URI.create("pkl:settings");
|
||||||
public static final URI pklProjectUri = URI.create("pkl:Project");
|
public static final URI pklProjectUri = URI.create("pkl:Project");
|
||||||
|
public static final URI pklRefUri = URI.create("pkl:ref");
|
||||||
|
|
||||||
public static final PClassInfo<Void> Any = pklBaseClassInfo("Any", Void.class);
|
public static final PClassInfo<Void> Any = pklBaseClassInfo("Any", Void.class);
|
||||||
public static final PClassInfo<PNull> Null = pklBaseClassInfo("Null", PNull.class);
|
public static final PClassInfo<PNull> Null = pklBaseClassInfo("Null", PNull.class);
|
||||||
@@ -82,9 +83,11 @@ public final class PClassInfo<T> implements Serializable {
|
|||||||
public static final PClassInfo<PObject> Version =
|
public static final PClassInfo<PObject> Version =
|
||||||
new PClassInfo<>("pkl.semver", "Version", PObject.class, pklSemverUri);
|
new PClassInfo<>("pkl.semver", "Version", PObject.class, pklSemverUri);
|
||||||
public static final PClassInfo<PObject> Project =
|
public static final PClassInfo<PObject> Project =
|
||||||
new PClassInfo<>("pkl.Project", "ModuleClass", PObject.class, pklProjectUri);
|
new PClassInfo<>("pkl.Project", MODULE_CLASS_NAME, PObject.class, pklProjectUri);
|
||||||
public static final PClassInfo<PObject> Settings =
|
public static final PClassInfo<PObject> Settings =
|
||||||
new PClassInfo<>("pkl.settings", "ModuleClass", PObject.class, pklSettingsUri);
|
new PClassInfo<>("pkl.settings", MODULE_CLASS_NAME, PObject.class, pklSettingsUri);
|
||||||
|
public static final PClassInfo<Reference> Reference =
|
||||||
|
new PClassInfo<>("pkl.ref", "Reference", Reference.class, pklRefUri);
|
||||||
|
|
||||||
public static final PClassInfo<Object> Unavailable =
|
public static final PClassInfo<Object> Unavailable =
|
||||||
new PClassInfo<>("unavailable", "unavailable", Object.class, URI.create("pkl:unavailable"));
|
new PClassInfo<>("unavailable", "unavailable", Object.class, URI.create("pkl:unavailable"));
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -18,6 +18,7 @@ package org.pkl.core;
|
|||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/** A Pkl type as used in type annotations. */
|
/** A Pkl type as used in type annotations. */
|
||||||
public abstract class PType implements Serializable {
|
public abstract class PType implements Serializable {
|
||||||
@@ -27,18 +28,33 @@ public abstract class PType implements Serializable {
|
|||||||
public static final PType UNKNOWN =
|
public static final PType UNKNOWN =
|
||||||
new PType() {
|
new PType() {
|
||||||
@Serial private static final long serialVersionUID = 0L;
|
@Serial private static final long serialVersionUID = 0L;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** The bottom type. */
|
/** The bottom type. */
|
||||||
public static final PType NOTHING =
|
public static final PType NOTHING =
|
||||||
new PType() {
|
new PType() {
|
||||||
@Serial private static final long serialVersionUID = 0L;
|
@Serial private static final long serialVersionUID = 0L;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "nothing";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** The type of the enclosing module. */
|
/** The type of the enclosing module. */
|
||||||
public static final PType MODULE =
|
public static final PType MODULE =
|
||||||
new PType() {
|
new PType() {
|
||||||
@Serial private static final long serialVersionUID = 0L;
|
@Serial private static final long serialVersionUID = 0L;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "module";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private PType() {}
|
private PType() {}
|
||||||
@@ -59,6 +75,22 @@ public abstract class PType implements Serializable {
|
|||||||
public String getLiteral() {
|
public String getLiteral() {
|
||||||
return literal;
|
return literal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
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 {
|
public static final class Class extends PType {
|
||||||
@@ -92,6 +124,31 @@ public abstract class PType implements Serializable {
|
|||||||
public List<PType> getTypeArguments() {
|
public List<PType> getTypeArguments() {
|
||||||
return typeArguments;
|
return typeArguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
var result = pClass.getDisplayName();
|
||||||
|
if (!typeArguments.isEmpty()) {
|
||||||
|
result +=
|
||||||
|
"<"
|
||||||
|
+ typeArguments.stream().map(Object::toString).collect(Collectors.joining(", "))
|
||||||
|
+ ">";
|
||||||
|
}
|
||||||
|
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 {
|
public static final class Nullable extends PType {
|
||||||
@@ -106,6 +163,24 @@ public abstract class PType implements Serializable {
|
|||||||
public PType getBaseType() {
|
public PType getBaseType() {
|
||||||
return baseType;
|
return baseType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return baseType instanceof Function || baseType instanceof Union
|
||||||
|
? "(" + 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 {
|
public static final class Constrained extends PType {
|
||||||
@@ -126,6 +201,29 @@ public abstract class PType implements Serializable {
|
|||||||
public List<String> getConstraints() {
|
public List<String> getConstraints() {
|
||||||
return constraints;
|
return constraints;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return (baseType instanceof Function || baseType instanceof Union
|
||||||
|
? "(" + baseType + ")"
|
||||||
|
: baseType)
|
||||||
|
+ "("
|
||||||
|
+ 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 {
|
public static final class Alias extends PType {
|
||||||
@@ -161,6 +259,31 @@ public abstract class PType implements Serializable {
|
|||||||
public PType getAliasedType() {
|
public PType getAliasedType() {
|
||||||
return aliasedType;
|
return aliasedType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
var result = typeAlias.getDisplayName();
|
||||||
|
if (!typeArguments.isEmpty()) {
|
||||||
|
result +=
|
||||||
|
"<"
|
||||||
|
+ typeArguments.stream().map(Object::toString).collect(Collectors.joining(", "))
|
||||||
|
+ ">";
|
||||||
|
}
|
||||||
|
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 {
|
public static final class Function extends PType {
|
||||||
@@ -181,6 +304,27 @@ public abstract class PType implements Serializable {
|
|||||||
public PType getReturnType() {
|
public PType getReturnType() {
|
||||||
return returnType;
|
return returnType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "("
|
||||||
|
+ parameterTypes.stream().map(Object::toString).collect(Collectors.joining(", "))
|
||||||
|
+ ") -> "
|
||||||
|
+ 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 {
|
public static final class Union extends PType {
|
||||||
@@ -195,6 +339,22 @@ public abstract class PType implements Serializable {
|
|||||||
public List<PType> getElementTypes() {
|
public List<PType> getElementTypes() {
|
||||||
return elementTypes;
|
return elementTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
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 {
|
public static final class TypeVariable extends PType {
|
||||||
@@ -213,5 +373,21 @@ public abstract class PType implements Serializable {
|
|||||||
public TypeParameter getTypeParameter() {
|
public TypeParameter getTypeParameter() {
|
||||||
return typeParameter;
|
return typeParameter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -177,6 +177,13 @@ final class PropertiesRenderer implements ValueRenderer {
|
|||||||
"Values of type `Regex` cannot be rendered as Properties. Value: %s", value));
|
"Values of type `Regex` cannot be rendered as Properties. Value: %s", value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String convertReference(Reference value) {
|
||||||
|
throw new RendererException(
|
||||||
|
String.format(
|
||||||
|
"Values of type `Reference` cannot be rendered as Properties. Value: %s", value));
|
||||||
|
}
|
||||||
|
|
||||||
private void doVisitMap(@Nullable String keyPrefix, Map<?, ?> map) {
|
private void doVisitMap(@Nullable String keyPrefix, Map<?, ?> map) {
|
||||||
for (Map.Entry<?, ?> entry : map.entrySet()) {
|
for (Map.Entry<?, ?> entry : map.entrySet()) {
|
||||||
doVisitKeyAndValue(keyPrefix, entry.getKey(), entry.getValue());
|
doVisitKeyAndValue(keyPrefix, entry.getKey(), entry.getValue());
|
||||||
|
|||||||
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2026 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.pkl.core;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Reference implements Value {
|
||||||
|
@Serial private static final long serialVersionUID = 0L;
|
||||||
|
|
||||||
|
private final Composite domain;
|
||||||
|
private final Object data;
|
||||||
|
private final List<Composite> path;
|
||||||
|
private final PType referentType;
|
||||||
|
|
||||||
|
/** Constructs a reference. */
|
||||||
|
public Reference(Composite domain, Object data, List<Composite> path, PType referentType) {
|
||||||
|
this.domain = domain;
|
||||||
|
this.data = data;
|
||||||
|
this.path = path;
|
||||||
|
this.referentType = referentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the domain object of this reference. */
|
||||||
|
public Composite getDomain() {
|
||||||
|
return domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the data object of this reference. */
|
||||||
|
public Object getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the access path of this reference.
|
||||||
|
*
|
||||||
|
* <p>All elements are exported {@code pkl.ref#Access} instances.
|
||||||
|
*/
|
||||||
|
public List<Composite> getPath() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the referent type of this reference. */
|
||||||
|
public PType getReferentType() {
|
||||||
|
return referentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void accept(ValueVisitor visitor) {
|
||||||
|
visitor.visitReference(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T accept(ValueConverter<T> converter) {
|
||||||
|
return converter.convertReference(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean equals(Object o) {
|
||||||
|
if (!(o instanceof Reference reference)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return domain.equals(reference.domain)
|
||||||
|
&& data.equals(reference.data)
|
||||||
|
&& path.equals(reference.path)
|
||||||
|
&& referentType.equals(reference.referentType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PClassInfo<?> getClassInfo() {
|
||||||
|
return PClassInfo.Reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = domain.hashCode();
|
||||||
|
result = 31 * result + data.hashCode();
|
||||||
|
result = 31 * result + path.hashCode();
|
||||||
|
result = 31 * result + referentType.hashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return super.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,6 +28,7 @@ public final class TypeAlias extends Member implements Value {
|
|||||||
private final String moduleName;
|
private final String moduleName;
|
||||||
private final String qualifiedName;
|
private final String qualifiedName;
|
||||||
private final List<TypeParameter> typeParameters;
|
private final List<TypeParameter> typeParameters;
|
||||||
|
private final PClass moduleClass;
|
||||||
|
|
||||||
@LateInit private PType aliasedType;
|
@LateInit private PType aliasedType;
|
||||||
|
|
||||||
@@ -39,11 +40,13 @@ public final class TypeAlias extends Member implements Value {
|
|||||||
String simpleName,
|
String simpleName,
|
||||||
String moduleName,
|
String moduleName,
|
||||||
String qualifiedName,
|
String qualifiedName,
|
||||||
List<TypeParameter> typeParameters) {
|
List<TypeParameter> typeParameters,
|
||||||
|
PClass moduleClass) {
|
||||||
super(docComment, sourceLocation, modifiers, annotations, simpleName);
|
super(docComment, sourceLocation, modifiers, annotations, simpleName);
|
||||||
this.moduleName = moduleName;
|
this.moduleName = moduleName;
|
||||||
this.qualifiedName = qualifiedName;
|
this.qualifiedName = qualifiedName;
|
||||||
this.typeParameters = typeParameters;
|
this.typeParameters = typeParameters;
|
||||||
|
this.moduleClass = moduleClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initAliasedType(PType type) {
|
public void initAliasedType(PType type) {
|
||||||
@@ -79,6 +82,10 @@ public final class TypeAlias extends Member implements Value {
|
|||||||
return typeParameters;
|
return typeParameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PClass getModuleClass() {
|
||||||
|
return moduleClass;
|
||||||
|
}
|
||||||
|
|
||||||
/** Returns the type that this type alias stands for. */
|
/** Returns the type that this type alias stands for. */
|
||||||
public PType getAliasedType() {
|
public PType getAliasedType() {
|
||||||
//noinspection ConstantValue
|
//noinspection ConstantValue
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -57,6 +57,8 @@ public interface ValueConverter<T> {
|
|||||||
|
|
||||||
T convertRegex(Pattern value);
|
T convertRegex(Pattern value);
|
||||||
|
|
||||||
|
T convertReference(Reference value);
|
||||||
|
|
||||||
default T convert(Object value) {
|
default T convert(Object value) {
|
||||||
if (value instanceof Value v) {
|
if (value instanceof Value v) {
|
||||||
return (v.accept(this));
|
return (v.accept(this));
|
||||||
|
|||||||
@@ -93,6 +93,10 @@ public interface ValueVisitor {
|
|||||||
visitDefault(value);
|
visitDefault(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default void visitReference(Reference value) {
|
||||||
|
visitDefault(value);
|
||||||
|
}
|
||||||
|
|
||||||
default void visit(Object value) {
|
default void visit(Object value) {
|
||||||
if (value instanceof Value v) {
|
if (value instanceof Value v) {
|
||||||
v.accept(this);
|
v.accept(this);
|
||||||
|
|||||||
@@ -1476,8 +1476,6 @@ public class AstBuilder extends AbstractAstBuilder<Object> {
|
|||||||
var scope = (ModuleScope) symbolTable.getCurrentScope();
|
var scope = (ModuleScope) symbolTable.getCurrentScope();
|
||||||
scope.setModifiers(modifiers);
|
scope.setModifiers(modifiers);
|
||||||
|
|
||||||
checkAbstractMembersAllowed(modifiers, mod.getProperties(), mod.getMethods());
|
|
||||||
|
|
||||||
// visit imports first so that we already have the object member name available
|
// visit imports first so that we already have the object member name available
|
||||||
var imports = mod.getImports();
|
var imports = mod.getImports();
|
||||||
var importMembers = new ObjectMember[imports.size()];
|
var importMembers = new ObjectMember[imports.size()];
|
||||||
@@ -1722,7 +1720,6 @@ public class AstBuilder extends AbstractAstBuilder<Object> {
|
|||||||
List<ClassProperty> properties = bodyNode != null ? bodyNode.getProperties() : List.of();
|
List<ClassProperty> properties = bodyNode != null ? bodyNode.getProperties() : List.of();
|
||||||
List<ClassMethod> methods = bodyNode != null ? bodyNode.getMethods() : List.of();
|
List<ClassMethod> methods = bodyNode != null ? bodyNode.getMethods() : List.of();
|
||||||
registerClassScopeNames(scope, properties, methods);
|
registerClassScopeNames(scope, properties, methods);
|
||||||
checkAbstractMembersAllowed(modifiers, properties, methods);
|
|
||||||
|
|
||||||
var supertypeCtx = clazz.getSuperClass();
|
var supertypeCtx = clazz.getSuperClass();
|
||||||
|
|
||||||
@@ -1813,30 +1810,6 @@ public class AstBuilder extends AbstractAstBuilder<Object> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkAbstractMembersAllowed(
|
|
||||||
int enclosingModifiers, List<ClassProperty> properties, List<ClassMethod> methods) {
|
|
||||||
if (VmModifier.isAbstract(enclosingModifiers)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (var property : properties) {
|
|
||||||
checkMemberNotAbstract(property.getModifiers());
|
|
||||||
}
|
|
||||||
for (var method : methods) {
|
|
||||||
checkMemberNotAbstract(method.getModifiers());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkMemberNotAbstract(List<Modifier> modifiers) {
|
|
||||||
for (var modifier : modifiers) {
|
|
||||||
if (modifier.getValue() == ModifierValue.ABSTRACT) {
|
|
||||||
throw exceptionBuilder()
|
|
||||||
.evalError("abstractMemberInNonAbstractClass")
|
|
||||||
.withSourceSection(createSourceSection(modifier.span()))
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private UnresolvedPropertyNode[] doVisitClassProperties(
|
private UnresolvedPropertyNode[] doVisitClassProperties(
|
||||||
List<ClassProperty> propertyContexts, Set<String> propertyNames) {
|
List<ClassProperty> propertyContexts, Set<String> propertyNames) {
|
||||||
var propertyNodes = new UnresolvedPropertyNode[propertyContexts.size()];
|
var propertyNodes = new UnresolvedPropertyNode[propertyContexts.size()];
|
||||||
|
|||||||
@@ -100,6 +100,20 @@ public abstract class SubscriptNode extends BinaryExpressionNode {
|
|||||||
return readMember(dynamic, key, callNode);
|
return readMember(dynamic, key, callNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Specialization
|
||||||
|
protected VmReference eval(VmReference reference, Object key) {
|
||||||
|
var result = reference.withSubscriptAccess(key);
|
||||||
|
if (result != null) return result;
|
||||||
|
|
||||||
|
CompilerDirectives.transferToInterpreter();
|
||||||
|
throw exceptionBuilder()
|
||||||
|
.evalError(
|
||||||
|
"operatorNotDefined2", getShortName(), reference.exportType(), VmUtils.getClass(key))
|
||||||
|
.withProgramValue("Left operand", reference)
|
||||||
|
.withProgramValue("Right operand", key)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
@Specialization
|
@Specialization
|
||||||
protected long eval(VmBytes receiver, long index) {
|
protected long eval(VmBytes receiver, long index) {
|
||||||
if (index < 0 || index >= receiver.getLength()) {
|
if (index < 0 || index >= receiver.getLength()) {
|
||||||
|
|||||||
@@ -61,6 +61,18 @@ public abstract class ReadPropertyNode extends ExpressionNode {
|
|||||||
this(sourceSection, propertyName, MemberLookupMode.EXPLICIT_RECEIVER, false);
|
this(sourceSection, propertyName, MemberLookupMode.EXPLICIT_RECEIVER, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Specialization
|
||||||
|
protected VmReference evalReference(VmReference receiver) {
|
||||||
|
assert lookupMode == MemberLookupMode.EXPLICIT_RECEIVER;
|
||||||
|
var result = receiver.withPropertyAccess(propertyName);
|
||||||
|
if (result != null) return result;
|
||||||
|
|
||||||
|
CompilerDirectives.transferToInterpreter();
|
||||||
|
throw exceptionBuilder()
|
||||||
|
.evalError("cannotFindPropertyInReference", propertyName, receiver.exportType())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
// This method effectively covers `VmObject receiver` but is implemented in a more
|
// This method effectively covers `VmObject receiver` but is implemented in a more
|
||||||
// efficient way. See:
|
// efficient way. See:
|
||||||
// https://www.graalvm.org/22.0/graalvm-as-a-platform/language-implementation-framework/TruffleLibraries/#strategy-2-java-interfaces
|
// https://www.graalvm.org/22.0/graalvm-as-a-platform/language-implementation-framework/TruffleLibraries/#strategy-2-java-interfaces
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -20,6 +20,7 @@ import com.oracle.truffle.api.dsl.Cached;
|
|||||||
import com.oracle.truffle.api.dsl.Fallback;
|
import com.oracle.truffle.api.dsl.Fallback;
|
||||||
import com.oracle.truffle.api.dsl.Specialization;
|
import com.oracle.truffle.api.dsl.Specialization;
|
||||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||||
|
import com.oracle.truffle.api.nodes.DirectCallNode;
|
||||||
import com.oracle.truffle.api.source.SourceSection;
|
import com.oracle.truffle.api.source.SourceSection;
|
||||||
import org.pkl.core.ast.ExpressionNode;
|
import org.pkl.core.ast.ExpressionNode;
|
||||||
import org.pkl.core.ast.MemberLookupMode;
|
import org.pkl.core.ast.MemberLookupMode;
|
||||||
@@ -62,10 +63,18 @@ public abstract class ToStringNode extends UnaryExpressionNode {
|
|||||||
VmTyped value,
|
VmTyped value,
|
||||||
@Cached(value = "createInvokeNode()", neverDefault = true)
|
@Cached(value = "createInvokeNode()", neverDefault = true)
|
||||||
InvokeMethodVirtualNode invokeNode) {
|
InvokeMethodVirtualNode invokeNode) {
|
||||||
|
|
||||||
return (String) invokeNode.executeWith(frame, value, value.getVmClass());
|
return (String) invokeNode.executeWith(frame, value, value.getVmClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Specialization
|
||||||
|
protected String evalReference(
|
||||||
|
VirtualFrame frame,
|
||||||
|
VmReference value,
|
||||||
|
@Cached(value = "createReferenceCallNode(value)", neverDefault = true)
|
||||||
|
DirectCallNode callNode) {
|
||||||
|
return (String) callNode.call(value, value.getVmClass().getPrototype());
|
||||||
|
}
|
||||||
|
|
||||||
@Fallback
|
@Fallback
|
||||||
@Override
|
@Override
|
||||||
@TruffleBoundary
|
@TruffleBoundary
|
||||||
@@ -74,7 +83,6 @@ public abstract class ToStringNode extends UnaryExpressionNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected InvokeMethodVirtualNode createInvokeNode() {
|
protected InvokeMethodVirtualNode createInvokeNode() {
|
||||||
//noinspection ConstantConditions
|
|
||||||
return InvokeMethodVirtualNodeGen.create(
|
return InvokeMethodVirtualNodeGen.create(
|
||||||
sourceSection,
|
sourceSection,
|
||||||
Identifier.TO_STRING,
|
Identifier.TO_STRING,
|
||||||
@@ -83,4 +91,10 @@ public abstract class ToStringNode extends UnaryExpressionNode {
|
|||||||
null,
|
null,
|
||||||
null);
|
null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected DirectCallNode createReferenceCallNode(VmReference reference) {
|
||||||
|
var toStringMethod = reference.getVmClass().getDeclaredMethod(Identifier.TO_STRING);
|
||||||
|
assert toStringMethod != null;
|
||||||
|
return DirectCallNode.create(toStringMethod.getCallTarget());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2127,6 +2127,125 @@ public abstract class TypeNode extends PklNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract static class ReferenceTypeNode extends ObjectSlotTypeNode {
|
||||||
|
@Child private TypeNode domainTypeNode;
|
||||||
|
@Child private TypeNode referentTypeNode;
|
||||||
|
@Child private ExpressionNode getModuleNode;
|
||||||
|
|
||||||
|
public ReferenceTypeNode(
|
||||||
|
SourceSection sourceSection, TypeNode domainTypeNode, TypeNode referentTypeNode) {
|
||||||
|
super(sourceSection);
|
||||||
|
this.domainTypeNode = domainTypeNode;
|
||||||
|
this.referentTypeNode = referentTypeNode;
|
||||||
|
this.getModuleNode = new GetModuleNode(sourceSection);
|
||||||
|
validateTypeArguments(sourceSection);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Specialization
|
||||||
|
protected Object eval(VirtualFrame frame, VmReference value) {
|
||||||
|
if (domainTypeNode.isNoopTypeCheck() && referentTypeNode.isNoopTypeCheck()) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
domainTypeNode.execute(frame, value.getDomain());
|
||||||
|
} catch (VmTypeMismatchException e) {
|
||||||
|
CompilerDirectives.transferToInterpreter();
|
||||||
|
throw new VmTypeMismatchException.Reference(
|
||||||
|
sourceSection,
|
||||||
|
value,
|
||||||
|
TypeNode.export(domainTypeNode),
|
||||||
|
TypeNode.export(referentTypeNode));
|
||||||
|
}
|
||||||
|
|
||||||
|
var module = (VmTyped) getModuleNode.executeGeneric(frame);
|
||||||
|
return doEval(value, module);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TruffleBoundary
|
||||||
|
private Object doEval(VmReference value, VmTyped module) {
|
||||||
|
var referentType = TypeNode.export(referentTypeNode);
|
||||||
|
if (value.referentTypeIsSubtypeOf(referentType, module.getVmClass().export())) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new VmTypeMismatchException.Reference(
|
||||||
|
sourceSection, value, TypeNode.export(domainTypeNode), referentType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void validateTypeArguments(@Nullable SourceSection aliasSourceSection) {
|
||||||
|
// constraints may not be used in Reference type annotation referents
|
||||||
|
// walk the type and throw if any part of the referent is constrained
|
||||||
|
|
||||||
|
// TODO improve error message when this type node and/or referent constraint are behind type
|
||||||
|
// aliases
|
||||||
|
referentTypeNode.acceptTypeNode(
|
||||||
|
true,
|
||||||
|
(typeNode) -> {
|
||||||
|
if (typeNode instanceof ConstrainedTypeNode) {
|
||||||
|
CompilerDirectives.transferToInterpreter();
|
||||||
|
var err =
|
||||||
|
exceptionBuilder().evalError("invalidReferenceTypeAnnotationWithConstraint");
|
||||||
|
if (aliasSourceSection != null) {
|
||||||
|
err.withSourceSection(aliasSourceSection);
|
||||||
|
}
|
||||||
|
throw err.build();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Fallback
|
||||||
|
protected Object fallback(Object value) {
|
||||||
|
throw typeMismatch(value, RefModule.getReferenceClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean acceptTypeNode(boolean visitTypeArguments, TypeNodeConsumer consumer) {
|
||||||
|
if (visitTypeArguments)
|
||||||
|
return consumer.accept(this)
|
||||||
|
&& consumer.accept(domainTypeNode)
|
||||||
|
&& consumer.accept(referentTypeNode);
|
||||||
|
return consumer.accept(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VmClass getVmClass() {
|
||||||
|
return RefModule.getReferenceClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VmList getTypeArgumentMirrors() {
|
||||||
|
return VmList.of(domainTypeNode.getMirror(), referentTypeNode.getMirror());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean doIsEquivalentTo(TypeNode other) {
|
||||||
|
if (!(other instanceof ReferenceTypeNode referenceTypeNode)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return referentTypeNode.isEquivalentTo(referenceTypeNode.referentTypeNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isNoopTypeCheck() {
|
||||||
|
return domainTypeNode.isNoopTypeCheck() && referentTypeNode.isNoopTypeCheck();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PType doExport() {
|
||||||
|
return new PType.Class(
|
||||||
|
RefModule.getReferenceClass().export(),
|
||||||
|
domainTypeNode.doExport(),
|
||||||
|
referentTypeNode.doExport());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isParametric() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static final class PairTypeNode extends ObjectSlotTypeNode {
|
public static final class PairTypeNode extends ObjectSlotTypeNode {
|
||||||
@Child private TypeNode firstTypeNode;
|
@Child private TypeNode firstTypeNode;
|
||||||
@Child private TypeNode secondTypeNode;
|
@Child private TypeNode secondTypeNode;
|
||||||
@@ -2584,7 +2703,7 @@ public abstract class TypeNode extends PklNode {
|
|||||||
|
|
||||||
this.typeAlias = typeAlias;
|
this.typeAlias = typeAlias;
|
||||||
this.typeArgumentNodes = typeArgumentNodes;
|
this.typeArgumentNodes = typeArgumentNodes;
|
||||||
aliasedTypeNode = typeAlias.instantiate(typeArgumentNodes);
|
aliasedTypeNode = typeAlias.instantiate(typeArgumentNodes, sourceSection);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TypeNode getAliasedTypeNode() {
|
public TypeNode getAliasedTypeNode() {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -287,6 +287,13 @@ public abstract class UnresolvedTypeNode extends PklNode {
|
|||||||
return new VarArgsTypeNode(sourceSection, typeArgumentNodes[0].execute(frame));
|
return new VarArgsTypeNode(sourceSection, typeArgumentNodes[0].execute(frame));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (clazz.isReferenceClass()) {
|
||||||
|
return ReferenceTypeNodeGen.create(
|
||||||
|
sourceSection,
|
||||||
|
typeArgumentNodes[0].execute(frame),
|
||||||
|
typeArgumentNodes[1].execute(frame));
|
||||||
|
}
|
||||||
|
|
||||||
throw exceptionBuilder()
|
throw exceptionBuilder()
|
||||||
.evalError("notAParameterizableClass", clazz.getDisplayName())
|
.evalError("notAParameterizableClass", clazz.getDisplayName())
|
||||||
.withSourceSection(typeArgumentNodes[0].sourceSection)
|
.withSourceSection(typeArgumentNodes[0].sourceSection)
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import com.oracle.truffle.api.source.SourceSection;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
import org.pkl.core.PType;
|
||||||
import org.pkl.core.StackFrame;
|
import org.pkl.core.StackFrame;
|
||||||
import org.pkl.core.ValueFormatter;
|
import org.pkl.core.ValueFormatter;
|
||||||
import org.pkl.core.ast.type.TypeNode.UnionTypeNode;
|
import org.pkl.core.ast.type.TypeNode.UnionTypeNode;
|
||||||
@@ -333,4 +334,44 @@ public abstract class VmTypeMismatchException extends ControlFlowException {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static final class Reference extends VmTypeMismatchException {
|
||||||
|
|
||||||
|
private final PType expectedDomainType;
|
||||||
|
private final PType expectedReferentType;
|
||||||
|
|
||||||
|
public Reference(
|
||||||
|
SourceSection sourceSection,
|
||||||
|
VmReference actualValue,
|
||||||
|
PType expectedDomainType,
|
||||||
|
PType expectedReferentType) {
|
||||||
|
super(sourceSection, actualValue);
|
||||||
|
this.expectedDomainType = expectedDomainType;
|
||||||
|
this.expectedReferentType = expectedReferentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void buildMessage(
|
||||||
|
AnsiStringBuilder builder, String indent, boolean withPowerAssertions) {
|
||||||
|
builder
|
||||||
|
.append(
|
||||||
|
ErrorMessages.createIndented(
|
||||||
|
"typeMismatch",
|
||||||
|
indent,
|
||||||
|
new PType.Class(
|
||||||
|
RefModule.getReferenceClass().export(),
|
||||||
|
expectedDomainType,
|
||||||
|
expectedReferentType),
|
||||||
|
((VmReference) actualValue).exportType()))
|
||||||
|
.append("\n")
|
||||||
|
.append(indent)
|
||||||
|
.append("Value: ")
|
||||||
|
.append(VmValueRenderer.singleLine(80 - indent.length()).render(actualValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Boolean hasHint() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ import java.util.stream.StreamSupport;
|
|||||||
import java.util.zip.ZipInputStream;
|
import java.util.zip.ZipInputStream;
|
||||||
import org.graalvm.collections.EconomicMap;
|
import org.graalvm.collections.EconomicMap;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
import org.pkl.core.PklBugException;
|
||||||
import org.pkl.core.SecurityManager;
|
import org.pkl.core.SecurityManager;
|
||||||
import org.pkl.core.SecurityManagerException;
|
import org.pkl.core.SecurityManagerException;
|
||||||
import org.pkl.core.http.HttpClient;
|
import org.pkl.core.http.HttpClient;
|
||||||
@@ -456,10 +457,17 @@ final class PackageResolvers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Path getRelativePath(PackageUri uri) {
|
private Path getRelativePath(PackageUri uri) {
|
||||||
return Path.of(
|
var relativePath =
|
||||||
CACHE_DIR_PREFIX,
|
Path.of(
|
||||||
IoUtils.encodePath(uri.getUri().getAuthority()),
|
CACHE_DIR_PREFIX,
|
||||||
getEffectivePackageUriPath(uri));
|
IoUtils.encodePath(uri.getUri().getAuthority()),
|
||||||
|
getEffectivePackageUriPath(uri));
|
||||||
|
// ensure the derived path cannot escape the cache directory
|
||||||
|
var resolved = cacheDir.resolve(relativePath).normalize();
|
||||||
|
if (!resolved.startsWith(cacheDir.normalize())) {
|
||||||
|
throw new PklBugException("Package URI escapes the cache directory");
|
||||||
|
}
|
||||||
|
return relativePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getLastSegmentName(PackageUri packageUri) {
|
private String getLastSegmentName(PackageUri packageUri) {
|
||||||
|
|||||||
@@ -61,6 +61,13 @@ public final class PackageUri {
|
|||||||
throw new URISyntaxException(
|
throw new URISyntaxException(
|
||||||
uri.toString(), ErrorMessages.create("missingPathInPackageUri", uri));
|
uri.toString(), ErrorMessages.create("missingPathInPackageUri", uri));
|
||||||
}
|
}
|
||||||
|
// reject `..` segments, percent-encoded or not
|
||||||
|
for (var segment : path.split("/", -1)) {
|
||||||
|
if (segment.equals("..")) {
|
||||||
|
throw new URISyntaxException(
|
||||||
|
uri.toString(), ErrorMessages.create("invalidRelativePathInPackageUri"));
|
||||||
|
}
|
||||||
|
}
|
||||||
var versionIdx = path.lastIndexOf('@');
|
var versionIdx = path.lastIndexOf('@');
|
||||||
if (versionIdx == -1) {
|
if (versionIdx == -1) {
|
||||||
throw new URISyntaxException(
|
throw new URISyntaxException(
|
||||||
|
|||||||
@@ -165,6 +165,10 @@ public final class Identifier implements Comparable<Identifier> {
|
|||||||
|
|
||||||
public static final Identifier ILLEGAL = get("`");
|
public static final Identifier ILLEGAL = get("`");
|
||||||
|
|
||||||
|
// members of pkl.ref
|
||||||
|
public static final Identifier PROPERTY = get("property");
|
||||||
|
public static final Identifier KEY = get("key");
|
||||||
|
|
||||||
// common in lambdas etc
|
// common in lambdas etc
|
||||||
public static final Identifier IT = get("it");
|
public static final Identifier IT = get("it");
|
||||||
|
|
||||||
|
|||||||
@@ -104,6 +104,8 @@ public final class ModuleCache {
|
|||||||
return PlatformModule.getModule();
|
return PlatformModule.getModule();
|
||||||
case "project":
|
case "project":
|
||||||
return ProjectModule.getModule();
|
return ProjectModule.getModule();
|
||||||
|
case "ref":
|
||||||
|
return RefModule.getModule();
|
||||||
case "reflect":
|
case "reflect":
|
||||||
return ReflectModule.getModule();
|
return ReflectModule.getModule();
|
||||||
case "release":
|
case "release":
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2026 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.pkl.core.runtime;
|
||||||
|
|
||||||
|
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
public class RefModule extends StdLibModule {
|
||||||
|
private static final VmTyped instance = VmUtils.createEmptyModule();
|
||||||
|
|
||||||
|
static {
|
||||||
|
loadModule(URI.create("pkl:ref"), instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static VmClass getReferenceClass() {
|
||||||
|
return ReferenceClass.instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static VmClass getAccessClass() {
|
||||||
|
return AccessClass.instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class ReferenceClass {
|
||||||
|
static final VmClass instance = loadClass("Reference");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class AccessClass {
|
||||||
|
static final VmClass instance = loadClass("Access");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TruffleBoundary
|
||||||
|
private static VmClass loadClass(String className) {
|
||||||
|
var theModule = getModule();
|
||||||
|
return (VmClass) VmUtils.readMember(theModule, Identifier.get(className));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static VmTyped getModule() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -445,6 +445,11 @@ public final class VmClass extends VmValue {
|
|||||||
return isClass(BaseModule.getVarArgsClass(), "pkl.base#VarArgs");
|
return isClass(BaseModule.getVarArgsClass(), "pkl.base#VarArgs");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Idempotent
|
||||||
|
public boolean isReferenceClass() {
|
||||||
|
return isClass(RefModule.getReferenceClass(), "pkl.ref#Reference");
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isClass(@Nullable VmClass clazz, String qualifiedClassName) {
|
private boolean isClass(@Nullable VmClass clazz, String qualifiedClassName) {
|
||||||
// may be null during evaluation of base module
|
// may be null during evaluation of base module
|
||||||
return clazz != null ? this == clazz : getQualifiedName().equals(qualifiedClassName);
|
return clazz != null ? this == clazz : getQualifiedName().equals(qualifiedClassName);
|
||||||
@@ -621,49 +626,62 @@ public final class VmClass extends VmValue {
|
|||||||
public PClass export() {
|
public PClass export() {
|
||||||
synchronized (pClassLock) {
|
synchronized (pClassLock) {
|
||||||
//noinspection ConstantValue
|
//noinspection ConstantValue
|
||||||
if (__pClass == null) {
|
if (__pClass != null) {
|
||||||
var exportedAnnotations = new ArrayList<PObject>();
|
return __pClass;
|
||||||
var properties =
|
}
|
||||||
CollectionUtils.<String, PClass.Property>newLinkedHashMap(
|
|
||||||
EconomicMaps.size(declaredProperties));
|
|
||||||
var methods =
|
|
||||||
CollectionUtils.<String, PClass.Method>newLinkedHashMap(
|
|
||||||
EconomicMaps.size(declaredMethods));
|
|
||||||
|
|
||||||
// set pClass before exporting class members to prevent
|
// if this is not a module class, export this class's module's class first to break the cycle
|
||||||
// infinite recursion in case of cyclic references
|
PClass moduleClass = null;
|
||||||
__pClass =
|
if (!classInfo.isModuleClass()) {
|
||||||
new PClass(
|
moduleClass = getModule().getVmClass().export();
|
||||||
VmUtils.exportDocComment(docComment),
|
}
|
||||||
new SourceLocation(headerSection.getStartLine(), sourceSection.getEndLine()),
|
// then if the cached value is still null, initialize it
|
||||||
VmModifier.export(modifiers, true),
|
if (__pClass != null) {
|
||||||
exportedAnnotations,
|
return __pClass;
|
||||||
classInfo,
|
}
|
||||||
typeParameters,
|
|
||||||
properties,
|
|
||||||
methods);
|
|
||||||
|
|
||||||
for (var parameter : typeParameters) {
|
var exportedAnnotations = new ArrayList<PObject>();
|
||||||
parameter.initOwner(__pClass);
|
var properties =
|
||||||
|
CollectionUtils.<String, PClass.Property>newLinkedHashMap(
|
||||||
|
EconomicMaps.size(declaredProperties));
|
||||||
|
var methods =
|
||||||
|
CollectionUtils.<String, PClass.Method>newLinkedHashMap(
|
||||||
|
EconomicMaps.size(declaredMethods));
|
||||||
|
|
||||||
|
// set pClass before exporting class members to prevent
|
||||||
|
// infinite recursion in case of cyclic references
|
||||||
|
__pClass =
|
||||||
|
new PClass(
|
||||||
|
VmUtils.exportDocComment(docComment),
|
||||||
|
new SourceLocation(headerSection.getStartLine(), sourceSection.getEndLine()),
|
||||||
|
VmModifier.export(modifiers, true),
|
||||||
|
exportedAnnotations,
|
||||||
|
classInfo,
|
||||||
|
typeParameters,
|
||||||
|
properties,
|
||||||
|
methods,
|
||||||
|
moduleClass);
|
||||||
|
|
||||||
|
for (var parameter : typeParameters) {
|
||||||
|
parameter.initOwner(__pClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supertypeNode != null) {
|
||||||
|
assert superclass != null;
|
||||||
|
__pClass.initSupertype(TypeNode.export(supertypeNode), superclass.export());
|
||||||
|
}
|
||||||
|
|
||||||
|
VmUtils.exportAnnotations(annotations, exportedAnnotations);
|
||||||
|
|
||||||
|
for (var property : EconomicMaps.getValues(declaredProperties)) {
|
||||||
|
if (isClassPropertyDefinition(property)) {
|
||||||
|
properties.put(property.getName().toString(), property.export(__pClass));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (supertypeNode != null) {
|
for (var method : EconomicMaps.getValues(declaredMethods)) {
|
||||||
assert superclass != null;
|
if (method.isLocal()) continue;
|
||||||
__pClass.initSupertype(TypeNode.export(supertypeNode), superclass.export());
|
methods.put(method.getName().toString(), method.export(__pClass));
|
||||||
}
|
|
||||||
|
|
||||||
VmUtils.exportAnnotations(annotations, exportedAnnotations);
|
|
||||||
|
|
||||||
for (var property : EconomicMaps.getValues(declaredProperties)) {
|
|
||||||
if (isClassPropertyDefinition(property)) {
|
|
||||||
properties.put(property.getName().toString(), property.export(__pClass));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var method : EconomicMaps.getValues(declaredMethods)) {
|
|
||||||
if (method.isLocal()) continue;
|
|
||||||
methods.put(method.getName().toString(), method.export(__pClass));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return __pClass;
|
return __pClass;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -87,4 +87,9 @@ public final class VmObjectBuilder {
|
|||||||
members,
|
members,
|
||||||
elementCount);
|
elementCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public VmTyped toTyped(VmClass clazz) {
|
||||||
|
return new VmTyped(
|
||||||
|
VmUtils.createEmptyMaterializedFrame(), clazz.getPrototype(), clazz, members);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -324,6 +324,22 @@ public class VmPklBinaryEncoder extends AbstractRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitReference(VmReference value) {
|
||||||
|
try {
|
||||||
|
packer.packArrayHeader(4);
|
||||||
|
packCode(PklBinaryCode.REFERENCE);
|
||||||
|
visit(value.getDomain());
|
||||||
|
visit(value.getData());
|
||||||
|
packer.packArrayHeader(value.getPath().size());
|
||||||
|
for (var access : value.getPath()) {
|
||||||
|
visit(access);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw PklBugException.unreachableCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void visitEntryKey(Object key, boolean isFirst) {
|
protected void visitEntryKey(Object key, boolean isFirst) {
|
||||||
visit(key);
|
visit(key);
|
||||||
|
|||||||
@@ -0,0 +1,484 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2025-2026 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.pkl.core.runtime;
|
||||||
|
|
||||||
|
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
|
||||||
|
import com.oracle.truffle.api.nodes.DirectCallNode;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
import org.pkl.core.Composite;
|
||||||
|
import org.pkl.core.PClass;
|
||||||
|
import org.pkl.core.PClassInfo;
|
||||||
|
import org.pkl.core.PType;
|
||||||
|
import org.pkl.core.Reference;
|
||||||
|
import org.pkl.core.TypeAlias;
|
||||||
|
import org.pkl.core.util.paguro.RrbTree;
|
||||||
|
import org.pkl.core.util.paguro.RrbTree.ImRrbt;
|
||||||
|
|
||||||
|
public final class VmReference extends VmValue {
|
||||||
|
|
||||||
|
private final VmTyped domain;
|
||||||
|
private final Object data;
|
||||||
|
private final ImRrbt<VmTyped> path;
|
||||||
|
// candidate types can only be: PType.Class, PType.Alias (only preservedAliasTypes),
|
||||||
|
// PType.StringLiteral, PType.UNKNOWN, or PType.Union (containing only the previous; flattened)
|
||||||
|
private final PType referentType;
|
||||||
|
|
||||||
|
private boolean forced = false;
|
||||||
|
|
||||||
|
private static VmTyped newAccess(@Nullable String property, @Nullable Object key) {
|
||||||
|
return new VmObjectBuilder()
|
||||||
|
.addProperty(Identifier.PROPERTY, property == null ? VmNull.withoutDefault() : property)
|
||||||
|
.addProperty(Identifier.KEY, key == null ? VmNull.withoutDefault() : key)
|
||||||
|
.toTyped(RefModule.getAccessClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
@TruffleBoundary
|
||||||
|
public VmReference(VmTyped domain, VmClass clazz, Object data) {
|
||||||
|
this(
|
||||||
|
domain,
|
||||||
|
data,
|
||||||
|
RrbTree.empty(),
|
||||||
|
normalizeTypes(new PType.Class(clazz.export()), clazz.getModule().getVmClass().export()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public VmReference(VmTyped domain, Object data, ImRrbt<VmTyped> path, PType referentType) {
|
||||||
|
this.domain = domain;
|
||||||
|
this.data = data;
|
||||||
|
this.referentType = referentType;
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VmTyped getDomain() {
|
||||||
|
return domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<VmTyped> getPath() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PType getReferentType() {
|
||||||
|
return referentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
// simplifies a type by:
|
||||||
|
// * erasing constraints
|
||||||
|
// * transforming T? into T|Null
|
||||||
|
// * dereferencing aliases (except for well-known stdlib alias types)
|
||||||
|
// * flattening unions
|
||||||
|
// * when moduleClass is supplied, replace PType.MODULE with appropriate PType.Class
|
||||||
|
// * drop PType.Function and PType.TypeVariable
|
||||||
|
private static PType normalizeTypes(PType type, PClass moduleClass) {
|
||||||
|
var types = new HashSet<PType>();
|
||||||
|
normalizeTypes(type, moduleClass, types);
|
||||||
|
return minimizeTypes(types);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PType minimizeTypes(Set<PType> types) {
|
||||||
|
if (types.size() == 1) return types.iterator().next();
|
||||||
|
// optimization: unknown allows all references, erase all candidates to only unknown
|
||||||
|
if (types.contains(PType.UNKNOWN)) return PType.UNKNOWN;
|
||||||
|
// optimization: All allows all references, erase all candidates to only All
|
||||||
|
if (containsClass(types, BaseModule.getAnyClass().export()))
|
||||||
|
return new PType.Class(BaseModule.getAnyClass().export());
|
||||||
|
var typesList = new ArrayList<>(types);
|
||||||
|
typesList.sort(Comparator.comparing(Object::toString));
|
||||||
|
return new PType.Union(typesList);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void normalizeTypes(PType type, PClass moduleClass, Set<PType> result) {
|
||||||
|
if (type == PType.UNKNOWN || type == PType.NOTHING || type instanceof PType.StringLiteral) {
|
||||||
|
result.add(type);
|
||||||
|
} else if (type instanceof PType.Class clazz) {
|
||||||
|
if (clazz.getTypeArguments().isEmpty()) {
|
||||||
|
// if a generic type is used without type arguments, it needs to be normalized so all args
|
||||||
|
// are unknown; i.e. with bare List/Map/etc. type annotations (via FinalClassTypeNode).
|
||||||
|
var typeParameterCount = clazz.getPClass().getTypeParameters().size();
|
||||||
|
result.add(
|
||||||
|
typeParameterCount == 0
|
||||||
|
? clazz
|
||||||
|
: new PType.Class(
|
||||||
|
clazz.getPClass(), Collections.nCopies(typeParameterCount, PType.UNKNOWN)));
|
||||||
|
} else {
|
||||||
|
var typeArgs = new ArrayList<PType>(clazz.getTypeArguments().size());
|
||||||
|
for (var arg : clazz.getTypeArguments()) {
|
||||||
|
typeArgs.add(normalizeTypes(arg, moduleClass));
|
||||||
|
}
|
||||||
|
result.add(new PType.Class(clazz.getPClass(), typeArgs));
|
||||||
|
}
|
||||||
|
} else if (type instanceof PType.Nullable nullable) {
|
||||||
|
normalizeTypes(nullable.getBaseType(), moduleClass, result);
|
||||||
|
result.add(new PType.Class(BaseModule.getNullClass().export()));
|
||||||
|
} else if (type instanceof PType.Constrained constrained) {
|
||||||
|
normalizeTypes(constrained.getBaseType(), moduleClass, result);
|
||||||
|
} else if (type instanceof PType.Alias alias) {
|
||||||
|
if (isPreservedTypeAlias(alias.getTypeAlias())) {
|
||||||
|
result.add(alias);
|
||||||
|
} else {
|
||||||
|
normalizeTypes(alias.getAliasedType(), alias.getTypeAlias().getModuleClass(), result);
|
||||||
|
}
|
||||||
|
} else if (type instanceof PType.Union union) {
|
||||||
|
for (var t : union.getElementTypes()) {
|
||||||
|
normalizeTypes(t, moduleClass, result);
|
||||||
|
}
|
||||||
|
} else if (type == PType.MODULE) {
|
||||||
|
result.add(new PType.Class(moduleClass));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Iterable<PType> iterateTypes(PType t) {
|
||||||
|
if (t instanceof PType.Union union) return union.getElementTypes();
|
||||||
|
return Collections.singleton(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable VmReference withPropertyAccess(Identifier property) {
|
||||||
|
var propString = property.toString();
|
||||||
|
return withAccess(
|
||||||
|
(t, candidates) -> getCandidatePropertyType(t, propString, candidates),
|
||||||
|
() -> newAccess(property.toString(), null));
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable VmReference withSubscriptAccess(Object key) {
|
||||||
|
return withAccess(
|
||||||
|
(t, candidates) -> getCandidateSubscriptType(t, key, candidates),
|
||||||
|
() -> newAccess(null, key));
|
||||||
|
}
|
||||||
|
|
||||||
|
@TruffleBoundary
|
||||||
|
private @Nullable VmReference withAccess(
|
||||||
|
BiConsumer<PType, Set<PType>> checkCandidate, Supplier<VmTyped> makeAccess) {
|
||||||
|
Set<PType> candidates = new HashSet<>();
|
||||||
|
for (var t : iterateTypes(referentType)) {
|
||||||
|
checkCandidate.accept(t, candidates);
|
||||||
|
}
|
||||||
|
if (candidates.isEmpty()) {
|
||||||
|
return null; // no valid access found
|
||||||
|
}
|
||||||
|
return new VmReference(domain, data, path.append(makeAccess.get()), minimizeTypes(candidates));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("DuplicatedCode")
|
||||||
|
private static void getCandidatePropertyType(PType type, String property, Set<PType> result) {
|
||||||
|
if (type == PType.UNKNOWN) {
|
||||||
|
result.add(type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// restriction: only class types can have their properties referenced
|
||||||
|
if (!(type instanceof PType.Class clazz)) return;
|
||||||
|
// restriction: cannot reference properties of external classes
|
||||||
|
if (clazz.getPClass().isExternal()) return;
|
||||||
|
if (clazz.getPClass().getInfo() == PClassInfo.Dynamic) {
|
||||||
|
// restriction: cannot reference Dynamic.default
|
||||||
|
if (!property.equals("default")) result.add(PType.UNKNOWN);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// restriction: cannot reference Listing/Mapping.default
|
||||||
|
if (clazz.getPClass().getInfo() == PClassInfo.Listing
|
||||||
|
|| clazz.getPClass().getInfo() == PClassInfo.Mapping) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// restriction: cannot reference Module.output.
|
||||||
|
// generalized: properties originally defined in external classes; the only extant example.
|
||||||
|
// This is implemented specifically because this is the only case where an external class
|
||||||
|
// containing a property can be subclassed.
|
||||||
|
// And this can't check prop.getOwner().isExternal() because fully overriding the property with
|
||||||
|
// a new type annotation means the owner isn't Module.
|
||||||
|
if (clazz.getPClass().isSubclassOf(BaseModule.getModuleClass().export())
|
||||||
|
&& property.equals("output")) return;
|
||||||
|
|
||||||
|
var prop = clazz.getPClass().getAllProperties().get(property);
|
||||||
|
// restriction: cannot reference external properties
|
||||||
|
if (prop == null || prop.isExternal()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
normalizeTypes(prop.getType(), clazz.getPClass().getModuleClass(), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("DuplicatedCode")
|
||||||
|
private static void getCandidateSubscriptType(PType type, Object key, Set<PType> result) {
|
||||||
|
if (type == PType.UNKNOWN) {
|
||||||
|
result.add(type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!(type instanceof PType.Class clazz)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (clazz.getPClass().getInfo() == PClassInfo.Dynamic) {
|
||||||
|
result.add(PType.UNKNOWN);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (clazz.getPClass().getInfo() == PClassInfo.Listing
|
||||||
|
|| clazz.getPClass().getInfo() == PClassInfo.List) {
|
||||||
|
if (key instanceof Long) {
|
||||||
|
normalizeTypes(clazz.getTypeArguments().get(0), clazz.getPClass().getModuleClass(), result);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (clazz.getPClass().getInfo() == PClassInfo.Mapping
|
||||||
|
|| clazz.getPClass().getInfo() == PClassInfo.Map) {
|
||||||
|
var typeArgs = clazz.getTypeArguments();
|
||||||
|
var keyTypes = normalizeTypes(typeArgs.get(0), clazz.getPClass().getModuleClass());
|
||||||
|
for (var kt : iterateTypes(keyTypes)) {
|
||||||
|
if (kt == PType.UNKNOWN
|
||||||
|
|| (kt instanceof PType.Class klazz
|
||||||
|
&& klazz.getPClass().getInfo() == PClassInfo.forValue(VmValue.export(key)))
|
||||||
|
|| (kt instanceof PType.StringLiteral stringLiteral
|
||||||
|
&& stringLiteral.getLiteral().equals(key))) {
|
||||||
|
normalizeTypes(typeArgs.get(1), clazz.getPClass().getModuleClass(), result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells if this reference's referent type is a subtype of {@code type}. Does not check domain.
|
||||||
|
*/
|
||||||
|
public boolean referentTypeIsSubtypeOf(PType type, PClass moduleClass) {
|
||||||
|
// fast path: if referent is unknown it can match any type check
|
||||||
|
if (referentType == PType.UNKNOWN) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var checkType = normalizeTypes(type, moduleClass);
|
||||||
|
// fast path: short circuit if any referent is accepted
|
||||||
|
if (checkType == PType.UNKNOWN || isClass(checkType, BaseModule.getAnyClass().export())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// fast path: short circuit if nothing is accepted
|
||||||
|
if (checkType == PType.NOTHING) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isSubtype(referentType, checkType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean containsClass(Set<PType> types, PClass pClass) {
|
||||||
|
for (var t : types) {
|
||||||
|
if (isClass(t, pClass)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isClass(PType t, PClass pClass) {
|
||||||
|
return t instanceof PType.Class clazz && clazz.getPClass() == pClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isSubtype(PType a, PType b) {
|
||||||
|
// checks if A is a subtype of B
|
||||||
|
// cases (A -> B)
|
||||||
|
// * A == B
|
||||||
|
// * StringLiteral -> StringLiteral: if literals are the same
|
||||||
|
// * StringLiteral -> Class: B is String
|
||||||
|
// * Char Alias -> Char Alias, StringLiteral (known single character)
|
||||||
|
// * Int Alias -> Class: B is a subtype of Number (Int|Float|Number)
|
||||||
|
// * Int Alias -> Alias
|
||||||
|
// * same alias
|
||||||
|
// * Int8 is Int16|Int32
|
||||||
|
// * Int16 is Int32
|
||||||
|
// * UInt8 is Int16|Int32|Uint16|UInt32|UInt
|
||||||
|
// * UInt16 is Int32|UInt32|UInt
|
||||||
|
// * UInt32 is UInt
|
||||||
|
// * Class -> Class: if same class or A is a subclass of B
|
||||||
|
// * if type args are present, must have equal number of them
|
||||||
|
// * for each pair of type args, check variance
|
||||||
|
// * invariant: A_i must be identical to B_i
|
||||||
|
// * covariant: A_i must be a subtype of B_i
|
||||||
|
// * contravariant: B_i must be a subtype of A_i
|
||||||
|
// * Union -> Union: Each elem of A must be a subtype of at least one elem of B
|
||||||
|
// * Non-union -> Union: A must be a subtype of at least one elem of B
|
||||||
|
if (a == b) return true;
|
||||||
|
|
||||||
|
if (a instanceof PType.StringLiteral aStr) {
|
||||||
|
if (b instanceof PType.StringLiteral bStr) {
|
||||||
|
return aStr.getLiteral().equals(bStr.getLiteral());
|
||||||
|
} else if (b instanceof PType.Class bClass) {
|
||||||
|
return bClass.getPClass() == BaseModule.getStringClass().export();
|
||||||
|
}
|
||||||
|
} else if (a instanceof PType.Alias aAlias) {
|
||||||
|
var aa = aAlias.getTypeAlias();
|
||||||
|
if (isIntTypeAlias(aa)) {
|
||||||
|
// special casing for stdlib Int typealiases
|
||||||
|
if (b instanceof PType.Class bClass) {
|
||||||
|
// A is an int alias, B is a Number (sub)class
|
||||||
|
return bClass.getPClass().isSubclassOf(BaseModule.getNumberClass().export());
|
||||||
|
} else if (b instanceof PType.Alias bAlias) {
|
||||||
|
var bb = bAlias.getTypeAlias();
|
||||||
|
if (aa == bb) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (aa == BaseModule.getInt8TypeAlias().export()) {
|
||||||
|
return bb == BaseModule.getInt16TypeAlias().export()
|
||||||
|
|| bb == BaseModule.getInt32TypeAlias().export();
|
||||||
|
} else if (aa == BaseModule.getInt16TypeAlias().export()) {
|
||||||
|
return bb == BaseModule.getInt32TypeAlias().export();
|
||||||
|
} else if (aa == BaseModule.getUInt8TypeAlias().export()) {
|
||||||
|
return bb == BaseModule.getInt16TypeAlias().export()
|
||||||
|
|| bb == BaseModule.getInt32TypeAlias().export()
|
||||||
|
|| bb == BaseModule.getUInt16TypeAlias().export()
|
||||||
|
|| bb == BaseModule.getUInt32TypeAlias().export()
|
||||||
|
|| bb == BaseModule.getUIntTypeAlias().export();
|
||||||
|
} else if (aa == BaseModule.getUInt16TypeAlias().export()) {
|
||||||
|
return bb == BaseModule.getInt32TypeAlias().export()
|
||||||
|
|| bb == BaseModule.getUInt32TypeAlias().export()
|
||||||
|
|| bb == BaseModule.getUIntTypeAlias().export();
|
||||||
|
} else if (aa == BaseModule.getUInt32TypeAlias().export()) {
|
||||||
|
return bb == BaseModule.getUIntTypeAlias().export();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (a instanceof PType.Class aClass && b instanceof PType.Class bClass) {
|
||||||
|
if (!aClass.getPClass().isSubclassOf(bClass.getPClass())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var aArgs = aClass.getTypeArguments();
|
||||||
|
var bArgs = bClass.getTypeArguments();
|
||||||
|
var bParams = bClass.getPClass().getTypeParameters();
|
||||||
|
if (aArgs.size() != bArgs.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// check variance of type args pairwise
|
||||||
|
for (var i = 0; i < aArgs.size(); i++) {
|
||||||
|
if (!switch (bParams.get(i).getVariance()) {
|
||||||
|
case INVARIANT -> aArgs.get(i) == bArgs.get(i);
|
||||||
|
case COVARIANT -> isSubtype(aArgs.get(i), bArgs.get(i));
|
||||||
|
case CONTRAVARIANT -> isSubtype(bArgs.get(i), aArgs.get(i));
|
||||||
|
}) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else if (b instanceof PType.Union bUnion) {
|
||||||
|
if (a instanceof PType.Union aUnion) {
|
||||||
|
a:
|
||||||
|
for (var aElem : aUnion.getElementTypes()) {
|
||||||
|
for (var bElem : bUnion.getElementTypes()) {
|
||||||
|
if (isSubtype(aElem, bElem)) continue a;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
for (var bElem : bUnion.getElementTypes()) {
|
||||||
|
if (isSubtype(a, bElem)) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isIntTypeAlias(TypeAlias t) {
|
||||||
|
return t == BaseModule.getInt8TypeAlias().export()
|
||||||
|
|| t == BaseModule.getInt16TypeAlias().export()
|
||||||
|
|| t == BaseModule.getInt32TypeAlias().export()
|
||||||
|
|| t == BaseModule.getUInt8TypeAlias().export()
|
||||||
|
|| t == BaseModule.getUInt16TypeAlias().export()
|
||||||
|
|| t == BaseModule.getUInt32TypeAlias().export()
|
||||||
|
|| t == BaseModule.getUIntTypeAlias().export();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isPreservedTypeAlias(TypeAlias t) {
|
||||||
|
return isIntTypeAlias(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VmClass getVmClass() {
|
||||||
|
return RefModule.getReferenceClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void force(boolean allowUndefinedValues) {
|
||||||
|
if (forced) return;
|
||||||
|
|
||||||
|
forced = true;
|
||||||
|
|
||||||
|
domain.force(allowUndefinedValues);
|
||||||
|
VmValue.force(data, allowUndefinedValues);
|
||||||
|
for (var elem : path) {
|
||||||
|
elem.force(allowUndefinedValues);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Reference export() {
|
||||||
|
var pathList = new ArrayList<Composite>(path.size());
|
||||||
|
for (var elem : path) {
|
||||||
|
pathList.add(elem.export());
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Reference(domain.export(), VmValue.export(data), pathList, getReferentType());
|
||||||
|
}
|
||||||
|
|
||||||
|
public PType exportType() {
|
||||||
|
return new PType.Class(
|
||||||
|
RefModule.getReferenceClass().export(),
|
||||||
|
new PType.Class(domain.getVmClass().export()),
|
||||||
|
getReferentType());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void accept(VmValueVisitor visitor) {
|
||||||
|
visitor.visitReference(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T accept(VmValueConverter<T> converter, Iterable<Object> path) {
|
||||||
|
return converter.convertReference(this, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(@Nullable Object o) {
|
||||||
|
if (o == this) return true;
|
||||||
|
if (!(o instanceof VmReference that)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return domain.equals(that.domain)
|
||||||
|
&& data.equals(that.data)
|
||||||
|
&& path.equals(that.path)
|
||||||
|
&& referentType.equals(that.referentType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = domain.hashCode();
|
||||||
|
result = 31 * result + data.hashCode();
|
||||||
|
result = 31 * result + path.hashCode();
|
||||||
|
result = 31 * result + referentType.hashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// in-language calls _should_ all go through `ToStringNode`.
|
||||||
|
// however, some calls escape through to here currently (e.g. `Listing.join`).
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
var toStringMethod = getVmClass().getDeclaredMethod(Identifier.TO_STRING);
|
||||||
|
assert toStringMethod != null;
|
||||||
|
var callNode = DirectCallNode.create(toStringMethod.getCallTarget());
|
||||||
|
return (String) callNode.call(this, getVmClass().getPrototype());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -32,6 +32,7 @@ import org.pkl.core.TypeParameter;
|
|||||||
import org.pkl.core.ast.VmModifier;
|
import org.pkl.core.ast.VmModifier;
|
||||||
import org.pkl.core.ast.type.TypeNode;
|
import org.pkl.core.ast.type.TypeNode;
|
||||||
import org.pkl.core.ast.type.TypeNode.ConstrainedTypeNode;
|
import org.pkl.core.ast.type.TypeNode.ConstrainedTypeNode;
|
||||||
|
import org.pkl.core.ast.type.TypeNode.ReferenceTypeNode;
|
||||||
import org.pkl.core.ast.type.TypeNode.TypeVariableNode;
|
import org.pkl.core.ast.type.TypeNode.TypeVariableNode;
|
||||||
import org.pkl.core.ast.type.TypeNode.UnknownTypeNode;
|
import org.pkl.core.ast.type.TypeNode.UnknownTypeNode;
|
||||||
import org.pkl.core.util.LateInit;
|
import org.pkl.core.util.LateInit;
|
||||||
@@ -177,7 +178,8 @@ public final class VmTypeAlias extends VmValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@TruffleBoundary
|
@TruffleBoundary
|
||||||
public TypeNode instantiate(TypeNode[] typeArgumentNodes) {
|
public TypeNode instantiate(
|
||||||
|
TypeNode[] typeArgumentNodes, SourceSection typeAliasTypeNodeSourceSection) {
|
||||||
// Cloning the type node means that the entire type check remains within a single root node,
|
// Cloning the type node means that the entire type check remains within a single root node,
|
||||||
// which should be good for interpreted and compiled performance alike:
|
// which should be good for interpreted and compiled performance alike:
|
||||||
// * Fewer root nodes to call
|
// * Fewer root nodes to call
|
||||||
@@ -199,6 +201,13 @@ public final class VmTypeAlias extends VmValue {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
clone.accept(
|
||||||
|
node -> {
|
||||||
|
if (node instanceof ReferenceTypeNode referenceTypeNode) {
|
||||||
|
referenceTypeNode.validateTypeArguments(typeAliasTypeNodeSourceSection);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
@@ -228,7 +237,8 @@ public final class VmTypeAlias extends VmValue {
|
|||||||
simpleName,
|
simpleName,
|
||||||
getModuleName(),
|
getModuleName(),
|
||||||
qualifiedName,
|
qualifiedName,
|
||||||
typeParameters);
|
typeParameters,
|
||||||
|
module.getVmClass().export());
|
||||||
|
|
||||||
for (var parameter : typeParameters) {
|
for (var parameter : typeParameters) {
|
||||||
parameter.initOwner(__pTypeAlias);
|
parameter.initOwner(__pTypeAlias);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -40,6 +40,7 @@ import com.oracle.truffle.api.dsl.TypeSystem;
|
|||||||
VmRegex.class,
|
VmRegex.class,
|
||||||
VmTypeAlias.class,
|
VmTypeAlias.class,
|
||||||
VmObjectLike.class,
|
VmObjectLike.class,
|
||||||
VmValue.class
|
VmReference.class,
|
||||||
|
VmValue.class,
|
||||||
})
|
})
|
||||||
public class VmTypes {}
|
public class VmTypes {}
|
||||||
|
|||||||
@@ -85,6 +85,8 @@ public interface VmValueConverter<T> {
|
|||||||
|
|
||||||
T convertFunction(VmFunction value, Iterable<Object> path);
|
T convertFunction(VmFunction value, Iterable<Object> path);
|
||||||
|
|
||||||
|
T convertReference(VmReference value, Iterable<Object> path);
|
||||||
|
|
||||||
/** Returns with an empty identifier if the second value is a RenderDirective */
|
/** Returns with an empty identifier if the second value is a RenderDirective */
|
||||||
Pair<Identifier, T> convertProperty(ClassProperty property, Object value, Iterable<Object> path);
|
Pair<Identifier, T> convertProperty(ClassProperty property, Object value, Iterable<Object> path);
|
||||||
|
|
||||||
|
|||||||
@@ -271,6 +271,30 @@ public final class VmValueRenderer {
|
|||||||
append("null");
|
append("null");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitReference(VmReference value) {
|
||||||
|
contexts.push(Context.EXPLICIT);
|
||||||
|
append("Reference(");
|
||||||
|
visit(value.getDomain());
|
||||||
|
append(", ");
|
||||||
|
append(value.getReferentType());
|
||||||
|
append(", ");
|
||||||
|
visit(value.getData());
|
||||||
|
append(")");
|
||||||
|
for (var elem : value.getPath()) {
|
||||||
|
var property = VmUtils.readMember(elem, Identifier.PROPERTY);
|
||||||
|
if (property instanceof String propName) {
|
||||||
|
append(".");
|
||||||
|
writeIdentifier(propName);
|
||||||
|
} else {
|
||||||
|
append("[");
|
||||||
|
visit(VmUtils.readMember(elem, Identifier.KEY));
|
||||||
|
append("]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contexts.pop();
|
||||||
|
}
|
||||||
|
|
||||||
private void append(Object value) {
|
private void append(Object value) {
|
||||||
builder.append(value);
|
builder.append(value);
|
||||||
checkLengthLimit();
|
checkLengthLimit();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -60,6 +60,8 @@ public interface VmValueVisitor {
|
|||||||
|
|
||||||
void visitFunction(VmFunction value);
|
void visitFunction(VmFunction value);
|
||||||
|
|
||||||
|
void visitReference(VmReference value);
|
||||||
|
|
||||||
default void visit(Object value) {
|
default void visit(Object value) {
|
||||||
Objects.requireNonNull(value, "Value to be visited must be non-null.");
|
Objects.requireNonNull(value, "Value to be visited must be non-null.");
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import org.pkl.core.runtime.VmListing;
|
|||||||
import org.pkl.core.runtime.VmMap;
|
import org.pkl.core.runtime.VmMap;
|
||||||
import org.pkl.core.runtime.VmMapping;
|
import org.pkl.core.runtime.VmMapping;
|
||||||
import org.pkl.core.runtime.VmNull;
|
import org.pkl.core.runtime.VmNull;
|
||||||
|
import org.pkl.core.runtime.VmReference;
|
||||||
import org.pkl.core.runtime.VmSet;
|
import org.pkl.core.runtime.VmSet;
|
||||||
import org.pkl.core.runtime.VmTypeAlias;
|
import org.pkl.core.runtime.VmTypeAlias;
|
||||||
import org.pkl.core.runtime.VmTyped;
|
import org.pkl.core.runtime.VmTyped;
|
||||||
@@ -397,6 +398,11 @@ public abstract class AbstractRenderer implements VmValueVisitor {
|
|||||||
currSourceSection = prevSourceSection;
|
currSourceSection = prevSourceSection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitReference(VmReference value) {
|
||||||
|
cannotRenderTypeAddConverter(value);
|
||||||
|
}
|
||||||
|
|
||||||
protected void cannotRenderTypeAddConverter(VmValue value) {
|
protected void cannotRenderTypeAddConverter(VmValue value) {
|
||||||
var builder =
|
var builder =
|
||||||
new VmExceptionBuilder()
|
new VmExceptionBuilder()
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ public final class PklConverter implements VmValueConverter<Object> {
|
|||||||
private final @Nullable VmFunction nullConverter;
|
private final @Nullable VmFunction nullConverter;
|
||||||
private final @Nullable VmFunction classConverter;
|
private final @Nullable VmFunction classConverter;
|
||||||
private final @Nullable VmFunction typeAliasConverter;
|
private final @Nullable VmFunction typeAliasConverter;
|
||||||
|
private final @Nullable VmFunction referenceConverter;
|
||||||
|
|
||||||
private PklConverter(
|
private PklConverter(
|
||||||
VmMapping converters, VmMapping convertPropertyTransformers, Object rendererOrParser) {
|
VmMapping converters, VmMapping convertPropertyTransformers, Object rendererOrParser) {
|
||||||
@@ -76,6 +77,7 @@ public final class PklConverter implements VmValueConverter<Object> {
|
|||||||
nullConverter = typeConverters.get(BaseModule.getNullClass());
|
nullConverter = typeConverters.get(BaseModule.getNullClass());
|
||||||
classConverter = typeConverters.get(BaseModule.getClassClass());
|
classConverter = typeConverters.get(BaseModule.getClassClass());
|
||||||
typeAliasConverter = typeConverters.get(BaseModule.getTypeAliasClass());
|
typeAliasConverter = typeConverters.get(BaseModule.getTypeAliasClass());
|
||||||
|
referenceConverter = typeConverters.get(RefModule.getReferenceClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final PklConverter NOOP =
|
public static final PklConverter NOOP =
|
||||||
@@ -199,6 +201,11 @@ public final class PklConverter implements VmValueConverter<Object> {
|
|||||||
return doConvert(value, path, nullConverter);
|
return doConvert(value, path, nullConverter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object convertReference(VmReference value, Iterable<Object> path) {
|
||||||
|
return doConvert(value, path, referenceConverter);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Pair<Identifier, Object> convertProperty(
|
public Pair<Identifier, Object> convertProperty(
|
||||||
ClassProperty property, Object value, Iterable<Object> path) {
|
ClassProperty property, Object value, Iterable<Object> path) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.pkl.core.stdlib.base;
|
package org.pkl.core.stdlib.base;
|
||||||
|
|
||||||
|
import com.oracle.truffle.api.CompilerDirectives;
|
||||||
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
|
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
|
||||||
import com.oracle.truffle.api.dsl.Specialization;
|
import com.oracle.truffle.api.dsl.Specialization;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
@@ -30,15 +31,16 @@ public final class ModuleClassNodes {
|
|||||||
@Specialization
|
@Specialization
|
||||||
@TruffleBoundary
|
@TruffleBoundary
|
||||||
protected VmList eval(VmObjectLike self, VmObjectLike other) {
|
protected VmList eval(VmObjectLike self, VmObjectLike other) {
|
||||||
|
if (!self.isModuleObject()) {
|
||||||
|
CompilerDirectives.transferToInterpreter();
|
||||||
|
throw exceptionBuilder().evalError("expectedModuleAsReceiver").build();
|
||||||
|
}
|
||||||
|
if (!other.isModuleObject()) {
|
||||||
|
CompilerDirectives.transferToInterpreter();
|
||||||
|
throw exceptionBuilder().evalError("expectedModuleAsArgument").build();
|
||||||
|
}
|
||||||
var selfKey = VmUtils.getModuleInfo(self).getModuleKey();
|
var selfKey = VmUtils.getModuleInfo(self).getModuleKey();
|
||||||
var selfUri = selfKey.getUri();
|
var selfUri = selfKey.getUri();
|
||||||
|
|
||||||
if (!other.isModuleObject()) {
|
|
||||||
throw exceptionBuilder()
|
|
||||||
.evalError("expectedModule")
|
|
||||||
// No meaningful SourceSection available, in this case.
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
var otherKey = VmUtils.getModuleInfo(other).getModuleKey();
|
var otherKey = VmUtils.getModuleInfo(other).getModuleKey();
|
||||||
var otherUri = otherKey.getUri();
|
var otherUri = otherKey.getUri();
|
||||||
|
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ import org.pkl.core.runtime.VmMap;
|
|||||||
import org.pkl.core.runtime.VmMapping;
|
import org.pkl.core.runtime.VmMapping;
|
||||||
import org.pkl.core.runtime.VmNull;
|
import org.pkl.core.runtime.VmNull;
|
||||||
import org.pkl.core.runtime.VmPair;
|
import org.pkl.core.runtime.VmPair;
|
||||||
|
import org.pkl.core.runtime.VmReference;
|
||||||
import org.pkl.core.runtime.VmRegex;
|
import org.pkl.core.runtime.VmRegex;
|
||||||
import org.pkl.core.runtime.VmSet;
|
import org.pkl.core.runtime.VmSet;
|
||||||
import org.pkl.core.runtime.VmTyped;
|
import org.pkl.core.runtime.VmTyped;
|
||||||
@@ -554,6 +555,12 @@ public final class RendererNodes {
|
|||||||
builder.append(value);
|
builder.append(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitReference(VmReference value) {
|
||||||
|
writePropertyName();
|
||||||
|
builder.append(value);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves types for the purpose of protobuf rendering. "Sees through" nullable types and type
|
* Resolves types for the purpose of protobuf rendering. "Sees through" nullable types and type
|
||||||
* aliases, simplifies variations of {@code Int} and {@code String} types (literate string
|
* aliases, simplifies variations of {@code Int} and {@code String} types (literate string
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2026 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.pkl.core.stdlib.ref;
|
||||||
|
|
||||||
|
import com.oracle.truffle.api.dsl.Specialization;
|
||||||
|
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||||
|
import org.pkl.core.runtime.VmClass;
|
||||||
|
import org.pkl.core.runtime.VmReference;
|
||||||
|
import org.pkl.core.runtime.VmTyped;
|
||||||
|
import org.pkl.core.stdlib.ExternalMethod3Node;
|
||||||
|
|
||||||
|
public class RefNodes {
|
||||||
|
public abstract static class Reference extends ExternalMethod3Node {
|
||||||
|
@Specialization
|
||||||
|
protected VmReference eval(
|
||||||
|
VirtualFrame frame, VmTyped self, VmTyped domain, VmClass clazz, Object data) {
|
||||||
|
return new VmReference(domain, clazz, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2026 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.pkl.core.stdlib.ref;
|
||||||
|
|
||||||
|
import com.oracle.truffle.api.dsl.Specialization;
|
||||||
|
import org.pkl.core.runtime.VmList;
|
||||||
|
import org.pkl.core.runtime.VmReference;
|
||||||
|
import org.pkl.core.stdlib.ExternalMethod0Node;
|
||||||
|
|
||||||
|
public class ReferenceNodes {
|
||||||
|
private ReferenceNodes() {}
|
||||||
|
|
||||||
|
public abstract static class getDomain extends ExternalMethod0Node {
|
||||||
|
@Specialization
|
||||||
|
protected Object eval(VmReference self) {
|
||||||
|
return self.getDomain();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract static class getData extends ExternalMethod0Node {
|
||||||
|
@Specialization
|
||||||
|
protected Object eval(VmReference self) {
|
||||||
|
return self.getData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract static class getPath extends ExternalMethod0Node {
|
||||||
|
@Specialization
|
||||||
|
protected VmList eval(VmReference self) {
|
||||||
|
return VmList.create(self.getPath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
@NullMarked
|
||||||
|
package org.pkl.core.stdlib.ref;
|
||||||
|
|
||||||
|
import org.jspecify.annotations.NullMarked;
|
||||||
@@ -33,6 +33,7 @@ public enum PklBinaryCode {
|
|||||||
TYPEALIAS((byte) 0x0D),
|
TYPEALIAS((byte) 0x0D),
|
||||||
FUNCTION((byte) 0x0E),
|
FUNCTION((byte) 0x0E),
|
||||||
BYTES((byte) 0x0F),
|
BYTES((byte) 0x0F),
|
||||||
|
REFERENCE((byte) 0x20),
|
||||||
|
|
||||||
PROPERTY((byte) 0x10),
|
PROPERTY((byte) 0x10),
|
||||||
ENTRY((byte) 0x11),
|
ENTRY((byte) 0x11),
|
||||||
@@ -65,6 +66,7 @@ public enum PklBinaryCode {
|
|||||||
case 0x0D -> PklBinaryCode.TYPEALIAS;
|
case 0x0D -> PklBinaryCode.TYPEALIAS;
|
||||||
case 0x0E -> PklBinaryCode.FUNCTION;
|
case 0x0E -> PklBinaryCode.FUNCTION;
|
||||||
case 0x0F -> PklBinaryCode.BYTES;
|
case 0x0F -> PklBinaryCode.BYTES;
|
||||||
|
case 0x20 -> PklBinaryCode.REFERENCE;
|
||||||
|
|
||||||
case 0x10 -> PklBinaryCode.PROPERTY;
|
case 0x10 -> PklBinaryCode.PROPERTY;
|
||||||
case 0x11 -> PklBinaryCode.ENTRY;
|
case 0x11 -> PklBinaryCode.ENTRY;
|
||||||
|
|||||||
@@ -203,7 +203,10 @@ Class `{0}` does not have type parameters.
|
|||||||
notASubclassOfTyped=\
|
notASubclassOfTyped=\
|
||||||
Class `{0}` is not a subtype of `Typed`.
|
Class `{0}` is not a subtype of `Typed`.
|
||||||
|
|
||||||
expectedModule=\
|
expectedModuleAsReceiver=\
|
||||||
|
Expected a module as the receiver, but got an object that amends a module.
|
||||||
|
|
||||||
|
expectedModuleAsArgument=\
|
||||||
Expected a module as argument, but got an object that amends a module.
|
Expected a module as argument, but got an object that amends a module.
|
||||||
|
|
||||||
wrongTypeArgumentCount=\
|
wrongTypeArgumentCount=\
|
||||||
@@ -286,11 +289,6 @@ External members cannot have a body.
|
|||||||
abstractMemberCannotHaveBody=\
|
abstractMemberCannotHaveBody=\
|
||||||
Abstract members cannot have a body.
|
Abstract members cannot have a body.
|
||||||
|
|
||||||
abstractMemberInNonAbstractClass=\
|
|
||||||
Cannot define an abstract member in a non-abstract class.\n\
|
|
||||||
\n\
|
|
||||||
A member can only be `abstract` if its enclosing class is also `abstract`.
|
|
||||||
|
|
||||||
methodNotDefined1=\
|
methodNotDefined1=\
|
||||||
Method `{0}` is not defined for argument type `{1}`.
|
Method `{0}` is not defined for argument type `{1}`.
|
||||||
|
|
||||||
@@ -390,6 +388,9 @@ Cannot find property `{0}` in object of type `{1}`.\n\
|
|||||||
Did you mean any of the following?\n\
|
Did you mean any of the following?\n\
|
||||||
{2}
|
{2}
|
||||||
|
|
||||||
|
cannotFindPropertyInReference=\
|
||||||
|
Cannot find property `{0}` in object of type `{1}`.
|
||||||
|
|
||||||
cannotFindMethodInScope=\
|
cannotFindMethodInScope=\
|
||||||
Cannot find method `{0}`.
|
Cannot find method `{0}`.
|
||||||
|
|
||||||
@@ -861,6 +862,9 @@ Package URIs must have an authority component.\n\
|
|||||||
\n\
|
\n\
|
||||||
For example, `example.com` in URI `project://example.com/my/package@1.0.0`.
|
For example, `example.com` in URI `project://example.com/my/package@1.0.0`.
|
||||||
|
|
||||||
|
invalidRelativePathInPackageUri=\
|
||||||
|
Package URIs cannot contain `..` segments in the URI's "path" component.
|
||||||
|
|
||||||
unexpectedChecksumInPackageUri=\
|
unexpectedChecksumInPackageUri=\
|
||||||
Did not expect to find a checksum component in this package URI.
|
Did not expect to find a checksum component in this package URI.
|
||||||
|
|
||||||
@@ -1176,3 +1180,6 @@ Cannot follow redirect from ''https:'' URL to ''http:'' URL.\
|
|||||||
\n\
|
\n\
|
||||||
HTTP Request: `GET {0}`\n\
|
HTTP Request: `GET {0}`\n\
|
||||||
Redirected to: `{1}`
|
Redirected to: `{1}`
|
||||||
|
|
||||||
|
invalidReferenceTypeAnnotationWithConstraint=\
|
||||||
|
`Reference` referent type argument may not include type constraints.
|
||||||
|
|||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
foo: String
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
open module ReferencedModuleWithOutputOverride
|
||||||
|
|
||||||
|
foo: String
|
||||||
|
|
||||||
|
hidden output: ModuleOutput = new {
|
||||||
|
text = foo
|
||||||
|
}
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
import "pkl:math"
|
||||||
|
import "pkl:ref"
|
||||||
|
|
||||||
|
class D extends ref.Domain {
|
||||||
|
function renderReference(reference: ref.Reference<D, Any>): String =
|
||||||
|
let (data = reference.getData())
|
||||||
|
let (root = if (data is Resource) data.name else data.toString())
|
||||||
|
let (
|
||||||
|
path =
|
||||||
|
reference
|
||||||
|
.getPath()
|
||||||
|
.map((elem) -> if (elem.isProperty) ".\(elem.property)" else "[\(elem.key)]")
|
||||||
|
)
|
||||||
|
"${\(root)\(path.join(""))}"
|
||||||
|
}
|
||||||
|
|
||||||
|
local const d: D = new {}
|
||||||
|
typealias Ref<T> = ref.Reference<D, T>
|
||||||
|
|
||||||
|
abstract class Resource {
|
||||||
|
name: String
|
||||||
|
hidden fixed $: Ref<Resource>
|
||||||
|
}
|
||||||
|
|
||||||
|
class A extends Resource {
|
||||||
|
id: String
|
||||||
|
hidden outputs: AProperties
|
||||||
|
hidden fixed $: Ref<A> = ref.Reference(d, A, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Test doc comment
|
||||||
|
class AProperties {
|
||||||
|
foo: Int
|
||||||
|
someMapping: Mapping<String, Int?>
|
||||||
|
someMap: Map<MapKey, Int>
|
||||||
|
someListing: Listing<Int>
|
||||||
|
someList: List<Int>
|
||||||
|
nonInt: String
|
||||||
|
}
|
||||||
|
|
||||||
|
class B extends Resource {
|
||||||
|
id: String
|
||||||
|
hidden outputs: BProperties
|
||||||
|
hidden fixed $: Ref<B> = ref.Reference(d, B, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
class BProperties {
|
||||||
|
foo: String
|
||||||
|
someMapping: Mapping<String, String?>
|
||||||
|
someMap: Map<MapKey, String>
|
||||||
|
someListing: Listing<String>
|
||||||
|
someList: List<String>
|
||||||
|
nonString: Int
|
||||||
|
}
|
||||||
|
|
||||||
|
class MapKey {
|
||||||
|
k: Int
|
||||||
|
|
||||||
|
function toString(): String = "key:\(k)"
|
||||||
|
}
|
||||||
|
|
||||||
|
class K {
|
||||||
|
aId: String | *Ref<String>?
|
||||||
|
bId: String | *Ref<String>?
|
||||||
|
aProperties: AProperties | *Ref<AProperties>?
|
||||||
|
bProperties: BProperties | *Ref<BProperties>?
|
||||||
|
aValues: Listing<Int | Ref<Int?>>?
|
||||||
|
bValues: Listing<String | Ref<String?>>?
|
||||||
|
splitUnion: Ref<Listing<String> | Listing<Int>>?
|
||||||
|
}
|
||||||
|
|
||||||
|
a: A = new {
|
||||||
|
name = "a"
|
||||||
|
id = "some-a-value"
|
||||||
|
}
|
||||||
|
|
||||||
|
b: B = new {
|
||||||
|
name = "b"
|
||||||
|
id = "some-b-value"
|
||||||
|
}
|
||||||
|
|
||||||
|
aOrB: A | B = a
|
||||||
|
aRef: Ref<A> = a.$
|
||||||
|
bRef: Ref<B> = b.$
|
||||||
|
unknownRef: Ref<A | B> = aRef
|
||||||
|
unknownRef2: Ref<A> | Ref<B> = aRef
|
||||||
|
unknownRef3: Ref<B | A> = aOrB.$
|
||||||
|
|
||||||
|
k: K = new {
|
||||||
|
aId = aRef.id
|
||||||
|
bId = bRef.id
|
||||||
|
aProperties = aRef.outputs
|
||||||
|
bProperties = bRef.outputs
|
||||||
|
aValues {
|
||||||
|
aRef.outputs.foo
|
||||||
|
aRef.outputs.someMapping["key"]
|
||||||
|
aRef.outputs.someMap[new MapKey { k = 123 }]
|
||||||
|
aRef.outputs.someListing[0]
|
||||||
|
aRef.outputs.someList[math.maxInt]
|
||||||
|
bRef.outputs.nonString
|
||||||
|
}
|
||||||
|
bValues {
|
||||||
|
bRef.outputs.foo
|
||||||
|
bRef.outputs.someMapping["key"]
|
||||||
|
bRef.outputs.someMap[new MapKey { k = 123 }]
|
||||||
|
bRef.outputs.someListing[0]
|
||||||
|
bRef.outputs.someList[math.maxInt]
|
||||||
|
aRef.outputs.nonInt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
j: K = new {
|
||||||
|
local aRef2 = unknownRef as Ref<A>
|
||||||
|
aProperties = aRef2.outputs
|
||||||
|
splitUnion = unknownRef.outputs.someListing
|
||||||
|
}
|
||||||
|
|
||||||
|
refInterpolation = "\(aRef.outputs.someListing[1])"
|
||||||
|
kInterpolation = "\(k)"
|
||||||
|
aValuesJoined = k.aValues.join("\n")
|
||||||
|
|
||||||
|
// ensure that type arguments that are unions are handled correctly
|
||||||
|
typeArgs = ref.Reference(d, TypeHolder, null).prop as Ref<Listing<Number | Boolean | String>>
|
||||||
|
class TypeHolder {
|
||||||
|
prop: Listing<String | Boolean | Number>
|
||||||
|
}
|
||||||
|
|
||||||
|
output {
|
||||||
|
renderer {
|
||||||
|
converters {
|
||||||
|
[ref.Reference] = (it) -> it.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
amends "../snippetTest.pkl"
|
||||||
|
|
||||||
|
import "pkl:ref"
|
||||||
|
|
||||||
|
local class D extends ref.Domain {
|
||||||
|
function renderReference(reference: ref.Reference<D, Any>): String = reference.getData().toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
local const d: D = new {}
|
||||||
|
local typealias Ref<T> = ref.Reference<D, T>
|
||||||
|
|
||||||
|
local class Holder {
|
||||||
|
num: Int
|
||||||
|
text: String
|
||||||
|
lit: "literal"
|
||||||
|
small: Int8
|
||||||
|
optional: Mapping<String, Int?>
|
||||||
|
listing: Listing<Int>
|
||||||
|
union: Listing<String> | Listing<Int>
|
||||||
|
}
|
||||||
|
|
||||||
|
local const h: Holder = new {
|
||||||
|
num = 1
|
||||||
|
text = "t"
|
||||||
|
lit = "literal"
|
||||||
|
small = 8
|
||||||
|
optional { ["k"] = 5 }
|
||||||
|
listing { 1; 2 }
|
||||||
|
union = new Listing<Int> { 1 }
|
||||||
|
}
|
||||||
|
|
||||||
|
local hRef1: Ref<Holder> = ref.Reference(d, Holder, h)
|
||||||
|
local hRef2: Ref<Holder> = 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
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
-5
@@ -1,5 +0,0 @@
|
|||||||
class Foo {
|
|
||||||
abstract bar: Int
|
|
||||||
}
|
|
||||||
|
|
||||||
res = new Foo { bar = 5 }
|
|
||||||
Vendored
-1
@@ -1 +0,0 @@
|
|||||||
abstract foo: Int
|
|
||||||
Vendored
-5
@@ -1,5 +0,0 @@
|
|||||||
class Foo {
|
|
||||||
abstract function bar(): Int
|
|
||||||
}
|
|
||||||
|
|
||||||
res = new Foo {}
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import "pkl:ref"
|
||||||
|
|
||||||
|
class D extends ref.Domain {
|
||||||
|
function renderReference(reference: ref.Reference<D, Any>): String = throw("not supported")
|
||||||
|
}
|
||||||
|
local d: D = new {}
|
||||||
|
typealias Ref<T> = ref.Reference<D, T>
|
||||||
|
|
||||||
|
test = ref.Reference(d, String, "") as Ref<Int>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import "pkl:ref"
|
||||||
|
|
||||||
|
class D extends ref.Domain {
|
||||||
|
function renderReference(reference: ref.Reference<D, Any>): String = throw("not supported")
|
||||||
|
}
|
||||||
|
typealias Ref<T> = ref.Reference<D, T>
|
||||||
|
local d: D = new {}
|
||||||
|
|
||||||
|
test = ref.Reference(d, String, "") as Ref<Listing<String(true)>>
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import "pkl:ref"
|
||||||
|
|
||||||
|
class D extends ref.Domain {
|
||||||
|
function renderReference(reference: ref.Reference<D, Any>): String = throw("not supported")
|
||||||
|
}
|
||||||
|
typealias Ref<T> = ref.Reference<D, T>
|
||||||
|
local d: D = new {}
|
||||||
|
|
||||||
|
test = ref.Reference(d, String, "") as Ref<Alias1?>
|
||||||
|
|
||||||
|
typealias Alias1 = Int | Alias2?
|
||||||
|
typealias Alias2 = String(length < 5)
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import "pkl:ref"
|
||||||
|
|
||||||
|
class D extends ref.Domain {
|
||||||
|
function renderReference(reference: ref.Reference<D, Any>): String = throw("not supported")
|
||||||
|
}
|
||||||
|
typealias RefAlias1 = ref.Reference<D, Alias1?>
|
||||||
|
local d: D = new {}
|
||||||
|
|
||||||
|
test = ref.Reference(d, String, "") as RefAlias1
|
||||||
|
|
||||||
|
typealias Alias1 = Int | Alias2?
|
||||||
|
typealias Alias2 = String(length < 5)
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import "pkl:ref"
|
||||||
|
|
||||||
|
class D extends ref.Domain {
|
||||||
|
function renderReference(reference: ref.Reference<D, Any>): String = throw("not supported")
|
||||||
|
}
|
||||||
|
local d: D = new {}
|
||||||
|
|
||||||
|
test = ref.Reference(d, Mapping, "").default
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import "pkl:ref"
|
||||||
|
|
||||||
|
class D extends ref.Domain {
|
||||||
|
function renderReference(reference: ref.Reference<D, Any>): String = throw("not supported")
|
||||||
|
}
|
||||||
|
local d: D = new {}
|
||||||
|
|
||||||
|
test = ref.Reference(d, Listing, "").default
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import "pkl:ref"
|
||||||
|
|
||||||
|
class D extends ref.Domain {
|
||||||
|
function renderReference(reference: ref.Reference<D, Any>): String = throw("not supported")
|
||||||
|
}
|
||||||
|
local d: D = new {}
|
||||||
|
|
||||||
|
test = ref.Reference(d, Dynamic, "").default
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import "pkl:ref"
|
||||||
|
|
||||||
|
import ".../input-helper/errors/ReferencedModule.pkl"
|
||||||
|
|
||||||
|
class D extends ref.Domain {
|
||||||
|
function renderReference(reference: ref.Reference<D, Any>): String = throw("not supported")
|
||||||
|
}
|
||||||
|
local d: D = new {}
|
||||||
|
|
||||||
|
test = ref.Reference(d, ReferencedModule.getClass(), "").output
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import "pkl:ref"
|
||||||
|
|
||||||
|
import ".../input-helper/errors/ReferencedModuleWithOutputOverride.pkl"
|
||||||
|
|
||||||
|
class D extends ref.Domain {
|
||||||
|
function renderReference(reference: ref.Reference<D, Any>): String = throw("not supported")
|
||||||
|
}
|
||||||
|
local d: D = new {}
|
||||||
|
|
||||||
|
test = ref.Reference(d, ReferencedModuleWithOutputOverride.getClass(), "").output
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import "pkl:ref"
|
||||||
|
|
||||||
|
import ".../input-helper/errors/ReferencedModuleWithOutputOverride.pkl"
|
||||||
|
|
||||||
|
class ModuleSubclass extends ReferencedModuleWithOutputOverride
|
||||||
|
|
||||||
|
class D extends ref.Domain {
|
||||||
|
function renderReference(reference: ref.Reference<D, Any>): String = throw("not supported")
|
||||||
|
}
|
||||||
|
local d: D = new {}
|
||||||
|
|
||||||
|
test = ref.Reference(d, ModuleSubclass, "").output
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import "pkl:ref"
|
||||||
|
|
||||||
|
class A {
|
||||||
|
foo: String | Int | Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
class D extends ref.Domain {
|
||||||
|
function renderReference(reference: ref.Reference<D, Any>): String = throw("not supported")
|
||||||
|
}
|
||||||
|
local d: D = new {}
|
||||||
|
|
||||||
|
test = ref.Reference(d, A, "").foo as ref.Reference<D, Int | Boolean>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import "pkl:ref"
|
||||||
|
|
||||||
|
class D extends ref.Domain {
|
||||||
|
function renderReference(reference: ref.Reference<D, Any>): String = throw("not supported")
|
||||||
|
}
|
||||||
|
local d: D = new {}
|
||||||
|
typealias Ref<T> = ref.Reference<D, T>
|
||||||
|
|
||||||
|
test = ref.Reference(d, String, "") as Ref<Boolean | Int>
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import "pkl:ref"
|
||||||
|
|
||||||
|
class A {
|
||||||
|
foo: String | Int | Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
class D extends ref.Domain {
|
||||||
|
function renderReference(reference: ref.Reference<D, Any>): String = throw("not supported")
|
||||||
|
}
|
||||||
|
local d: D = new {}
|
||||||
|
|
||||||
|
local test = ref.Reference(d, A, "").foo
|
||||||
|
testInterpolation = "test:\(test)"
|
||||||
|
|
||||||
|
// this tests that the interpolation appears in the output when referenceToString throws
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import "pkl:ref"
|
||||||
|
|
||||||
|
class D extends ref.Domain {
|
||||||
|
function renderReference(reference: ref.Reference<D, Any>): String = throw("not supported")
|
||||||
|
}
|
||||||
|
local d: D = new {}
|
||||||
|
typealias Ref<T> = ref.Reference<D, T>
|
||||||
|
|
||||||
|
test = ref.Reference(d, String, "") as Ref<Listing<String>>
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import "pkl:ref"
|
||||||
|
|
||||||
|
class D extends ref.Domain {
|
||||||
|
function renderReference(reference: ref.Reference<D, Any>): String = throw("not supported")
|
||||||
|
}
|
||||||
|
local d: D = new {}
|
||||||
|
typealias Ref<T> = ref.Reference<D, T>
|
||||||
|
|
||||||
|
test = ref.Reference(d, String, "") as Ref<Alias1?>
|
||||||
|
|
||||||
|
typealias Alias1 = Int | Alias2?
|
||||||
|
typealias Alias2 = Boolean
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import "pkl:ref"
|
||||||
|
|
||||||
|
class D extends ref.Domain {
|
||||||
|
function renderReference(reference: ref.Reference<D, Any>): String = throw("not supported")
|
||||||
|
}
|
||||||
|
local d: D = new {}
|
||||||
|
typealias Ref<T> = ref.Reference<D, T>
|
||||||
|
|
||||||
|
class D2 extends ref.Domain {
|
||||||
|
function renderReference(reference: ref.Reference<D, Any>): String = throw("not supported")
|
||||||
|
}
|
||||||
|
local d2: D2 = new {}
|
||||||
|
|
||||||
|
test = ref.Reference(d2, String, "") as Ref<String>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import "pkl:ref"
|
||||||
|
|
||||||
|
class D extends ref.Domain {
|
||||||
|
function renderReference(reference: ref.Reference<D, Any>): String = throw("not supported")
|
||||||
|
}
|
||||||
|
local d: D = new {}
|
||||||
|
typealias Ref<T> = ref.Reference<D, T>
|
||||||
|
|
||||||
|
class A {
|
||||||
|
b: String
|
||||||
|
}
|
||||||
|
|
||||||
|
test = ref.Reference(d, String, new A {}).c
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import "pkl:ref"
|
||||||
|
|
||||||
|
class D extends ref.Domain {
|
||||||
|
function renderReference(reference: ref.Reference<D, Any>): String = throw("not supported")
|
||||||
|
}
|
||||||
|
local d: D = new {}
|
||||||
|
typealias Ref<T> = ref.Reference<D, T>
|
||||||
|
|
||||||
|
test = ref.Reference(d, List, List())["hi"]
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import "pkl:ref"
|
||||||
|
|
||||||
|
class D extends ref.Domain {
|
||||||
|
function renderReference(reference: ref.Reference<D, Any>): String = throw("not supported")
|
||||||
|
}
|
||||||
|
typealias Ref<T> = ref.Reference<D, T>
|
||||||
|
local d: D = new {}
|
||||||
|
|
||||||
|
test = ref.Reference(d, String, "") as Ref<String(true)>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import "pkl:ref"
|
||||||
|
|
||||||
|
class D extends ref.Domain {
|
||||||
|
function renderReference(reference: ref.Reference<D, Any>): String = throw("not supported")
|
||||||
|
}
|
||||||
|
typealias Ref<T> = ref.Reference<D, T>
|
||||||
|
local d: D = new {}
|
||||||
|
|
||||||
|
test = ref.Reference(d, String, "") as Ref<String(true) | Int>
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
local objectThatAmendsModule = (module) {
|
||||||
|
// add a local property to force this into a new object amends;
|
||||||
|
// empty object amends are optimized away.
|
||||||
|
local qux = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
res = objectThatAmendsModule.relativePathTo(module)
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
local objectThatAmendsModule = (module) {
|
||||||
|
// add a local property to force this into a new object amends;
|
||||||
|
// empty object amends are optimized away.
|
||||||
|
local qux = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
res = module.relativePathTo(objectThatAmendsModule)
|
||||||
|
|
||||||
+2
@@ -0,0 +1,2 @@
|
|||||||
|
// relative path in package URI
|
||||||
|
res = import("package://localhost:0/%2e%2e/birds@0.5.0#/catalog/Bird.pkl")
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
a {
|
||||||
|
name = "a"
|
||||||
|
id = "some-a-value"
|
||||||
|
}
|
||||||
|
b {
|
||||||
|
name = "b"
|
||||||
|
id = "some-b-value"
|
||||||
|
}
|
||||||
|
aOrB {
|
||||||
|
name = "a"
|
||||||
|
id = "some-a-value"
|
||||||
|
}
|
||||||
|
aRef = "${a}"
|
||||||
|
bRef = "${b}"
|
||||||
|
unknownRef = "${a}"
|
||||||
|
unknownRef2 = "${a}"
|
||||||
|
unknownRef3 = "${a}"
|
||||||
|
k {
|
||||||
|
aId = "${a.id}"
|
||||||
|
bId = "${b.id}"
|
||||||
|
aProperties = "${a.outputs}"
|
||||||
|
bProperties = "${b.outputs}"
|
||||||
|
aValues {
|
||||||
|
"${a.outputs.foo}"
|
||||||
|
"${a.outputs.someMapping[key]}"
|
||||||
|
"${a.outputs.someMap[key:123]}"
|
||||||
|
"${a.outputs.someListing[0]}"
|
||||||
|
"${a.outputs.someList[9223372036854775807]}"
|
||||||
|
"${b.outputs.nonString}"
|
||||||
|
}
|
||||||
|
bValues {
|
||||||
|
"${b.outputs.foo}"
|
||||||
|
"${b.outputs.someMapping[key]}"
|
||||||
|
"${b.outputs.someMap[key:123]}"
|
||||||
|
"${b.outputs.someListing[0]}"
|
||||||
|
"${b.outputs.someList[9223372036854775807]}"
|
||||||
|
"${a.outputs.nonInt}"
|
||||||
|
}
|
||||||
|
splitUnion = null
|
||||||
|
}
|
||||||
|
j {
|
||||||
|
aId = null
|
||||||
|
bId = null
|
||||||
|
aProperties = "${a.outputs}"
|
||||||
|
bProperties = null
|
||||||
|
aValues = null
|
||||||
|
bValues = null
|
||||||
|
splitUnion = "${a.outputs.someListing}"
|
||||||
|
}
|
||||||
|
refInterpolation = "${a.outputs.someListing[1]}"
|
||||||
|
kInterpolation = "new K { aId = Reference(new D {}, String, new A { name = \"a\"; id = \"some-a-value\" }).id; bId = Reference(new D {}, String, new B { name = \"b\"; id = \"some-b-value\" }).id; aProperties = Reference(new D {}, reference#AProperties, new A { name = \"a\"; id = \"some-a-value\" }).outputs; bProperties = Reference(new D {}, reference#BProperties, new B { name = \"b\"; id = \"some-b-value\" }).outputs; aValues { Reference(new D {}, Int, new A { name = \"a\"; id = \"some-a-value\" }).outputs.foo; Reference(new D {}, Int | Null, new A { name = \"a\"; id = \"some-a-value\" }).outputs.someMapping[\"key\"]; Reference(new D {}, Int, new A { name = \"a\"; id = \"some-a-value\" }).outputs.someMap[new MapKey { k = 123 }]; Reference(new D {}, Int, new A { name = \"a\"; id = \"some-a-value\" }).outputs.someListing[0]; Reference(new D {}, Int, new A { name = \"a\"; id = \"some-a-value\" }).outputs.someList[9223372036854775807]; Reference(new D {}, Int, new B { name = \"b\"; id = \"some-b-value\" }).outputs.nonString }; bValues { Reference(new D {}, String, new B { name = \"b\"; id = \"some-b-value\" }).outputs.foo; Reference(new D {}, Null | String, new B { name = \"b\"; id = \"some-b-value\" }).outputs.someMapping[\"key\"]; Reference(new D {}, String, new B { name = \"b\"; id = \"some-b-value\" }).outputs.someMap[new MapKey { k = 123 }]; Reference(new D {}, String, new B { name = \"b\"; id = \"some-b-value\" }).outputs.someListing[0]; Reference(new D {}, String, new B { name = \"b\"; id = \"some-b-value\" }).outputs.someList[9223372036854775807]; Reference(new D {}, String, new A { name = \"a\"; id = \"some-a-value\" }).outputs.nonInt }; splitUnion = null }"
|
||||||
|
aValuesJoined = """
|
||||||
|
${a.outputs.foo}
|
||||||
|
${a.outputs.someMapping[key]}
|
||||||
|
${a.outputs.someMap[key:123]}
|
||||||
|
${a.outputs.someListing[0]}
|
||||||
|
${a.outputs.someList[9223372036854775807]}
|
||||||
|
${b.outputs.nonString}
|
||||||
|
"""
|
||||||
|
typeArgs = "${null.prop}"
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
facts {
|
||||||
|
["equality"] {
|
||||||
|
true
|
||||||
|
true
|
||||||
|
true
|
||||||
|
true
|
||||||
|
true
|
||||||
|
true
|
||||||
|
true
|
||||||
|
}
|
||||||
|
["inequality"] {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
["set deduplication"] {
|
||||||
|
true
|
||||||
|
true
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
-8
@@ -1,8 +0,0 @@
|
|||||||
–– Pkl Error ––
|
|
||||||
Cannot define an abstract member in a non-abstract class.
|
|
||||||
|
|
||||||
x | abstract bar: Int
|
|
||||||
^^^^^^^^
|
|
||||||
at abstractMemberInNonAbstractClass#Foo (file:///$snippetsDir/input/errors/abstractMemberInNonAbstractClass.pkl)
|
|
||||||
|
|
||||||
A member can only be `abstract` if its enclosing class is also `abstract`.
|
|
||||||
Vendored
-8
@@ -1,8 +0,0 @@
|
|||||||
–– Pkl Error ––
|
|
||||||
Cannot define an abstract member in a non-abstract class.
|
|
||||||
|
|
||||||
x | abstract foo: Int
|
|
||||||
^^^^^^^^
|
|
||||||
at abstractMemberInNonAbstractModule (file:///$snippetsDir/input/errors/abstractMemberInNonAbstractModule.pkl)
|
|
||||||
|
|
||||||
A member can only be `abstract` if its enclosing class is also `abstract`.
|
|
||||||
Vendored
-8
@@ -1,8 +0,0 @@
|
|||||||
–– Pkl Error ––
|
|
||||||
Cannot define an abstract member in a non-abstract class.
|
|
||||||
|
|
||||||
x | abstract function bar(): Int
|
|
||||||
^^^^^^^^
|
|
||||||
at abstractMethodInNonAbstractClass#Foo (file:///$snippetsDir/input/errors/abstractMethodInNonAbstractClass.pkl)
|
|
||||||
|
|
||||||
A member can only be `abstract` if its enclosing class is also `abstract`.
|
|
||||||
+1
@@ -20,6 +20,7 @@ pkl:pklbinary
|
|||||||
pkl:platform
|
pkl:platform
|
||||||
pkl:Project
|
pkl:Project
|
||||||
pkl:protobuf
|
pkl:protobuf
|
||||||
|
pkl:ref
|
||||||
pkl:reflect
|
pkl:reflect
|
||||||
pkl:release
|
pkl:release
|
||||||
pkl:semver
|
pkl:semver
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
–– Pkl Error ––
|
||||||
|
Expected value of type `pkl.ref#Reference<reference1#D, Int>`, but got type `pkl.ref#Reference<reference1#D, String>`.
|
||||||
|
Value: Reference(new D {}, String, "")
|
||||||
|
|
||||||
|
x | typealias Ref<T> = ref.Reference<D, T>
|
||||||
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
at reference1#test (file:///$snippetsDir/input/errors/reference1.pkl)
|
||||||
|
|
||||||
|
xxx | renderer.renderDocument(value)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at pkl.base#Module.output.text (pkl:base)
|
||||||
|
|
||||||
|
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||||
|
^^^^
|
||||||
|
at pkl.base#Module.output.bytes (pkl:base)
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
–– Pkl Error ––
|
||||||
|
`Reference` referent type argument may not include type constraints.
|
||||||
|
|
||||||
|
x | test = ref.Reference(d, String, "") as Ref<Listing<String(true)>>
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at reference10#test (file:///$snippetsDir/input/errors/reference10.pkl)
|
||||||
|
|
||||||
|
xxx | renderer.renderDocument(value)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at pkl.base#Module.output.text (pkl:base)
|
||||||
|
|
||||||
|
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||||
|
^^^^
|
||||||
|
at pkl.base#Module.output.bytes (pkl:base)
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
–– Pkl Error ––
|
||||||
|
`Reference` referent type argument may not include type constraints.
|
||||||
|
|
||||||
|
x | test = ref.Reference(d, String, "") as Ref<Alias1?>
|
||||||
|
^^^^^^^^^^^^
|
||||||
|
at reference11#test (file:///$snippetsDir/input/errors/reference11.pkl)
|
||||||
|
|
||||||
|
xxx | renderer.renderDocument(value)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at pkl.base#Module.output.text (pkl:base)
|
||||||
|
|
||||||
|
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||||
|
^^^^
|
||||||
|
at pkl.base#Module.output.bytes (pkl:base)
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
–– Pkl Error ––
|
||||||
|
`Reference` referent type argument may not include type constraints.
|
||||||
|
|
||||||
|
x | typealias RefAlias1 = ref.Reference<D, Alias1?>
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at reference12#RefAlias1 (file:///$snippetsDir/input/errors/reference12.pkl)
|
||||||
|
|
||||||
|
xxx | renderer.renderDocument(value)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at pkl.base#Module.output.text (pkl:base)
|
||||||
|
|
||||||
|
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||||
|
^^^^
|
||||||
|
at pkl.base#Module.output.bytes (pkl:base)
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
–– Pkl Error ––
|
||||||
|
Cannot find property `default` in object of type `pkl.ref#Reference<reference13#D, Mapping<unknown, unknown>>`.
|
||||||
|
|
||||||
|
x | test = ref.Reference(d, Mapping, "").default
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at reference13#test (file:///$snippetsDir/input/errors/reference13.pkl)
|
||||||
|
|
||||||
|
xxx | renderer.renderDocument(value)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at pkl.base#Module.output.text (pkl:base)
|
||||||
|
|
||||||
|
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||||
|
^^^^
|
||||||
|
at pkl.base#Module.output.bytes (pkl:base)
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
–– Pkl Error ––
|
||||||
|
Cannot find property `default` in object of type `pkl.ref#Reference<reference14#D, Listing<unknown>>`.
|
||||||
|
|
||||||
|
x | test = ref.Reference(d, Listing, "").default
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at reference14#test (file:///$snippetsDir/input/errors/reference14.pkl)
|
||||||
|
|
||||||
|
xxx | renderer.renderDocument(value)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at pkl.base#Module.output.text (pkl:base)
|
||||||
|
|
||||||
|
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||||
|
^^^^
|
||||||
|
at pkl.base#Module.output.bytes (pkl:base)
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
–– Pkl Error ––
|
||||||
|
Cannot find property `default` in object of type `pkl.ref#Reference<reference15#D, Dynamic>`.
|
||||||
|
|
||||||
|
x | test = ref.Reference(d, Dynamic, "").default
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at reference15#test (file:///$snippetsDir/input/errors/reference15.pkl)
|
||||||
|
|
||||||
|
xxx | renderer.renderDocument(value)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at pkl.base#Module.output.text (pkl:base)
|
||||||
|
|
||||||
|
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||||
|
^^^^
|
||||||
|
at pkl.base#Module.output.bytes (pkl:base)
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
–– Pkl Error ––
|
||||||
|
Cannot find property `output` in object of type `pkl.ref#Reference<reference16#D, ReferencedModule>`.
|
||||||
|
|
||||||
|
xx | test = ref.Reference(d, ReferencedModule.getClass(), "").output
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at reference16#test (file:///$snippetsDir/input/errors/reference16.pkl)
|
||||||
|
|
||||||
|
xxx | renderer.renderDocument(value)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at pkl.base#Module.output.text (pkl:base)
|
||||||
|
|
||||||
|
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||||
|
^^^^
|
||||||
|
at pkl.base#Module.output.bytes (pkl:base)
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
–– Pkl Error ––
|
||||||
|
Cannot find property `output` in object of type `pkl.ref#Reference<reference17#D, ReferencedModuleWithOutputOverride>`.
|
||||||
|
|
||||||
|
xx | test = ref.Reference(d, ReferencedModuleWithOutputOverride.getClass(), "").output
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at reference17#test (file:///$snippetsDir/input/errors/reference17.pkl)
|
||||||
|
|
||||||
|
xxx | renderer.renderDocument(value)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at pkl.base#Module.output.text (pkl:base)
|
||||||
|
|
||||||
|
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||||
|
^^^^
|
||||||
|
at pkl.base#Module.output.bytes (pkl:base)
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
–– Pkl Error ––
|
||||||
|
Cannot find property `output` in object of type `pkl.ref#Reference<reference18#D, reference18#ModuleSubclass>`.
|
||||||
|
|
||||||
|
xx | test = ref.Reference(d, ModuleSubclass, "").output
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at reference18#test (file:///$snippetsDir/input/errors/reference18.pkl)
|
||||||
|
|
||||||
|
xxx | renderer.renderDocument(value)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at pkl.base#Module.output.text (pkl:base)
|
||||||
|
|
||||||
|
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||||
|
^^^^
|
||||||
|
at pkl.base#Module.output.bytes (pkl:base)
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
–– Pkl Error ––
|
||||||
|
Expected value of type `pkl.ref#Reference<reference19#D, Int | Boolean>`, but got type `pkl.ref#Reference<reference19#D, Boolean | Int | String>`.
|
||||||
|
Value: Reference(new D {}, Boolean | Int | String, "").foo
|
||||||
|
|
||||||
|
xx | test = ref.Reference(d, A, "").foo as ref.Reference<D, Int | Boolean>
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at reference19#test (file:///$snippetsDir/input/errors/reference19.pkl)
|
||||||
|
|
||||||
|
xxx | renderer.renderDocument(value)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at pkl.base#Module.output.text (pkl:base)
|
||||||
|
|
||||||
|
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||||
|
^^^^
|
||||||
|
at pkl.base#Module.output.bytes (pkl:base)
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
–– Pkl Error ––
|
||||||
|
Expected value of type `pkl.ref#Reference<reference2#D, Boolean | Int>`, but got type `pkl.ref#Reference<reference2#D, String>`.
|
||||||
|
Value: Reference(new D {}, String, "")
|
||||||
|
|
||||||
|
x | typealias Ref<T> = ref.Reference<D, T>
|
||||||
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
at reference2#test (file:///$snippetsDir/input/errors/reference2.pkl)
|
||||||
|
|
||||||
|
xxx | renderer.renderDocument(value)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at pkl.base#Module.output.text (pkl:base)
|
||||||
|
|
||||||
|
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||||
|
^^^^
|
||||||
|
at pkl.base#Module.output.bytes (pkl:base)
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
–– Pkl Error ––
|
||||||
|
not supported
|
||||||
|
|
||||||
|
x | function renderReference(reference: ref.Reference<D, Any>): String = throw("not supported")
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at reference20#D.renderReference (file:///$snippetsDir/input/errors/reference20.pkl)
|
||||||
|
|
||||||
|
xxx | function toString(): String = getDomain().renderReference(this)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at pkl.ref#Reference.toString (pkl:ref)
|
||||||
|
|
||||||
|
xx | testInterpolation = "test:\(test)"
|
||||||
|
^^^^^^^
|
||||||
|
at reference20#testInterpolation (file:///$snippetsDir/input/errors/reference20.pkl)
|
||||||
|
|
||||||
|
xxx | renderer.renderDocument(value)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at pkl.base#Module.output.text (pkl:base)
|
||||||
|
|
||||||
|
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||||
|
^^^^
|
||||||
|
at pkl.base#Module.output.bytes (pkl:base)
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
–– Pkl Error ––
|
||||||
|
Expected value of type `pkl.ref#Reference<reference3#D, Listing<String>>`, but got type `pkl.ref#Reference<reference3#D, String>`.
|
||||||
|
Value: Reference(new D {}, String, "")
|
||||||
|
|
||||||
|
x | typealias Ref<T> = ref.Reference<D, T>
|
||||||
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
at reference3#test (file:///$snippetsDir/input/errors/reference3.pkl)
|
||||||
|
|
||||||
|
xxx | renderer.renderDocument(value)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at pkl.base#Module.output.text (pkl:base)
|
||||||
|
|
||||||
|
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||||
|
^^^^
|
||||||
|
at pkl.base#Module.output.bytes (pkl:base)
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
–– Pkl Error ––
|
||||||
|
Expected value of type `pkl.ref#Reference<reference4#D, reference4#Alias1?>`, but got type `pkl.ref#Reference<reference4#D, String>`.
|
||||||
|
Value: Reference(new D {}, String, "")
|
||||||
|
|
||||||
|
x | typealias Ref<T> = ref.Reference<D, T>
|
||||||
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
at reference4#test (file:///$snippetsDir/input/errors/reference4.pkl)
|
||||||
|
|
||||||
|
xxx | renderer.renderDocument(value)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at pkl.base#Module.output.text (pkl:base)
|
||||||
|
|
||||||
|
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||||
|
^^^^
|
||||||
|
at pkl.base#Module.output.bytes (pkl:base)
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
–– Pkl Error ––
|
||||||
|
Expected value of type `pkl.ref#Reference<reference5#D, String>`, but got type `pkl.ref#Reference<reference5#D2, String>`.
|
||||||
|
Value: Reference(new D2 {}, String, "")
|
||||||
|
|
||||||
|
x | typealias Ref<T> = ref.Reference<D, T>
|
||||||
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
at reference5#test (file:///$snippetsDir/input/errors/reference5.pkl)
|
||||||
|
|
||||||
|
xxx | renderer.renderDocument(value)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at pkl.base#Module.output.text (pkl:base)
|
||||||
|
|
||||||
|
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||||
|
^^^^
|
||||||
|
at pkl.base#Module.output.bytes (pkl:base)
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
–– Pkl Error ––
|
||||||
|
Cannot find property `c` in object of type `pkl.ref#Reference<reference6#D, String>`.
|
||||||
|
|
||||||
|
xx | test = ref.Reference(d, String, new A {}).c
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at reference6#test (file:///$snippetsDir/input/errors/reference6.pkl)
|
||||||
|
|
||||||
|
xxx | renderer.renderDocument(value)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at pkl.base#Module.output.text (pkl:base)
|
||||||
|
|
||||||
|
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||||
|
^^^^
|
||||||
|
at pkl.base#Module.output.bytes (pkl:base)
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
–– Pkl Error ––
|
||||||
|
Operator `[]` is not defined for operand types `pkl.ref#Reference<reference7#D, List<unknown>>` and `String`.
|
||||||
|
Left operand : Reference(new D {}, List<unknown>, List())
|
||||||
|
Right operand: "hi"
|
||||||
|
|
||||||
|
x | test = ref.Reference(d, List, List())["hi"]
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at reference7#test (file:///$snippetsDir/input/errors/reference7.pkl)
|
||||||
|
|
||||||
|
xxx | renderer.renderDocument(value)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at pkl.base#Module.output.text (pkl:base)
|
||||||
|
|
||||||
|
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||||
|
^^^^
|
||||||
|
at pkl.base#Module.output.bytes (pkl:base)
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
–– Pkl Error ––
|
||||||
|
`Reference` referent type argument may not include type constraints.
|
||||||
|
|
||||||
|
x | test = ref.Reference(d, String, "") as Ref<String(true)>
|
||||||
|
^^^^^^^^^^^^^^^^^
|
||||||
|
at reference8#test (file:///$snippetsDir/input/errors/reference8.pkl)
|
||||||
|
|
||||||
|
xxx | renderer.renderDocument(value)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at pkl.base#Module.output.text (pkl:base)
|
||||||
|
|
||||||
|
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||||
|
^^^^
|
||||||
|
at pkl.base#Module.output.bytes (pkl:base)
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
–– Pkl Error ––
|
||||||
|
`Reference` referent type argument may not include type constraints.
|
||||||
|
|
||||||
|
x | test = ref.Reference(d, String, "") as Ref<String(true) | Int>
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at reference9#test (file:///$snippetsDir/input/errors/reference9.pkl)
|
||||||
|
|
||||||
|
xxx | renderer.renderDocument(value)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at pkl.base#Module.output.text (pkl:base)
|
||||||
|
|
||||||
|
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||||
|
^^^^
|
||||||
|
at pkl.base#Module.output.bytes (pkl:base)
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
–– Pkl Error ––
|
||||||
|
Expected a module as the receiver, but got an object that amends a module.
|
||||||
|
|
||||||
|
x | res = objectThatAmendsModule.relativePathTo(module)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at relativePathToNotAModule1#res (file:///$snippetsDir/input/errors/relativePathToNotAModule1.pkl)
|
||||||
|
|
||||||
|
xxx | renderer.renderDocument(value)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
at pkl.base#Module.output.text (pkl:base)
|
||||||
|
|
||||||
|
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||||
|
^^^^
|
||||||
|
at pkl.base#Module.output.bytes (pkl:base)
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user