Fix many editor diagnostics (#1707)

This addresses many IDE warnings resulting from the switch to JSpecify.

Also, this changes the behavior of exporting VmObject; there's no place
in our code that does not force a VmObject prior to export, so
the existing logic around handling nullable values has been removed.
This commit is contained in:
Daniel Chao
2026-06-29 09:22:19 -07:00
committed by GitHub
parent 742a8e88da
commit 139d1ae8ec
63 changed files with 208 additions and 130 deletions
@@ -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");
* you may not use this file except in compliance with the License.
@@ -69,11 +69,11 @@ public record ImportGraph(Map<URI, Set<Import>> imports, Map<URI, URI> resolvedI
var value = entry.getValue();
var set = new TreeSet<Import>();
if (!(value instanceof JsArray array)) {
throw new FormatException("array", value.getClass());
throw new FormatException("array", value == null ? Void.class : value.getClass());
}
for (var elem : array) {
if (!(elem instanceof JsObject importObj)) {
throw new FormatException("object", elem.getClass());
throw new FormatException("object", elem == null ? Void.class : elem.getClass());
}
set.add(parseImport(importObj));
}
@@ -98,7 +98,7 @@ public record ImportGraph(Map<URI, Set<Import>> imports, Map<URI, URI> resolvedI
var key = new URI(entry.getKey());
var value = entry.getValue();
if (!(value instanceof String str)) {
throw new FormatException("string", value.getClass());
throw new FormatException("string", value == null ? Void.class : value.getClass());
}
var valueUri = new URI(str);
ret.put(key, valueUri);
@@ -109,6 +109,8 @@ final class JsonRenderer implements ValueRenderer {
"Values of type `Bytes` cannot be rendered as JSON. Value: %s", (Object) value));
}
// Pair coming from the runtime can never admit null (in-language null is represented as PNull)
@SuppressWarnings("DataFlowIssue")
@Override
public void visitPair(Pair<?, ?> value) {
try {
@@ -18,7 +18,6 @@ package org.pkl.core;
import java.net.URI;
import java.util.*;
import org.jspecify.annotations.Nullable;
import org.pkl.core.util.LateInit;
/** Describes the property, method and class members of a module. */
public final class ModuleSchema {
@@ -33,8 +32,8 @@ public final class ModuleSchema {
private final Map<String, TypeAlias> typeAliases;
private final Map<String, URI> imports;
@LateInit private Map<String, PClass> __allClasses;
@LateInit private Map<String, TypeAlias> __allTypeAliases;
private @Nullable Map<String, PClass> __allClasses;
private @Nullable Map<String, TypeAlias> __allTypeAliases;
/** Constructs a {@code ModuleSchema} instance. */
public ModuleSchema(
@@ -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");
* you may not use this file except in compliance with the License.
@@ -227,9 +227,7 @@ final class PcfRenderer implements ValueRenderer {
write(currIndent);
writeIdentifier(name);
if (value == null) { // unevaluated property
write(" = ?");
} else if (value instanceof Composite) {
if (value instanceof Composite) {
write(' ');
visit(value);
} else {
@@ -1,5 +1,5 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
* 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.
@@ -21,7 +21,9 @@ import java.io.UncheckedIOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import org.jspecify.annotations.Nullable;
import org.msgpack.core.MessagePack;
import org.msgpack.core.MessageUnpacker;
import org.pkl.core.runtime.BaseModule;
@@ -111,7 +113,7 @@ public class PklBinaryDecoder extends AbstractPklBinaryDecoder {
@Override
protected Object doDecodeMap(MapDecodeIterator iter) {
var map = CollectionUtils.newLinkedHashMap(iter.getSize());
Map<@Nullable Object, @Nullable Object> map = CollectionUtils.newLinkedHashMap(iter.getSize());
while (iter.hasNext()) {
var entry = iter.next();
map.put(entry.getFirst(), entry.getSecond());
@@ -54,6 +54,9 @@ final class PropertiesRenderer implements ValueRenderer {
} else if (value instanceof Map<?, ?> map) {
doVisitMap(null, map);
} else if (value instanceof Pair<?, ?> pair) {
// Pair coming from the runtime can never admit null (in-language null is represented as
// PNull)
//noinspection DataFlowIssue
doVisitKeyAndValue(null, pair.getFirst(), pair.getSecond());
} else {
throw new RendererException(
@@ -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");
* you may not use this file except in compliance with the License.
@@ -17,7 +17,7 @@ package org.pkl.core;
import java.io.Serial;
import java.io.Serializable;
import org.pkl.core.util.LateInit;
import org.jspecify.annotations.Nullable;
/** A type parameter of a generic class, type alias, or method. */
public final class TypeParameter implements Serializable {
@@ -27,7 +27,7 @@ public final class TypeParameter implements Serializable {
private final String name;
private final int index;
@LateInit private volatile Member owner;
private volatile @Nullable Member owner;
public TypeParameter(Variance variance, String name, int index) {
this.variance = variance;
@@ -48,6 +48,7 @@ public final class TypeParameter implements Serializable {
/** Returns the generic class, type alias, or method that this type parameter belongs to. */
public Member getOwner() {
assert owner != null;
//noinspection DataFlowIssue
return owner;
}
@@ -18,7 +18,6 @@ package org.pkl.core;
import java.util.*;
import java.util.regex.*;
import org.jspecify.annotations.Nullable;
import org.pkl.core.util.LateInit;
/**
* A <a href="https://semver.org/spec/v2.0.0.html">semantic version</a>.
@@ -59,7 +58,7 @@ public final class Version implements Comparable<Version> {
private final @Nullable String preRelease;
private final @Nullable String build;
@LateInit private volatile Identifier[] __preReleaseIdentifiers;
private volatile Identifier @Nullable [] __preReleaseIdentifiers;
/** Constructs a semantic version. */
public Version(
@@ -230,6 +229,7 @@ public final class Version implements Comparable<Version> {
: new Identifier(-1, str))
.toArray(Identifier[]::new);
}
//noinspection DataFlowIssue
return __preReleaseIdentifiers;
}
@@ -1,5 +1,5 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
* 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.
@@ -20,19 +20,19 @@ import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.ExplodeLoop;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.source.SourceSection;
import org.jspecify.annotations.Nullable;
import org.pkl.core.ast.ExpressionNode;
import org.pkl.core.ast.type.TypeNode;
import org.pkl.core.ast.type.TypeNode.UInt8TypeAliasTypeNode;
import org.pkl.core.ast.type.VmTypeMismatchException;
import org.pkl.core.runtime.VmBytes;
import org.pkl.core.runtime.VmUtils;
import org.pkl.core.util.LateInit;
@NodeInfo(shortName = "Bytes()")
public final class BytesLiteralNode extends ExpressionNode {
@Children private final ExpressionNode[] elements;
@Child @LateInit private TypeNode typeNode;
@Child private @Nullable TypeNode typeNode;
public BytesLiteralNode(SourceSection sourceSection, ExpressionNode[] elements) {
super(sourceSection);
@@ -22,6 +22,7 @@ import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.DirectCallNode;
import com.oracle.truffle.api.nodes.ExplodeLoop;
import com.oracle.truffle.api.source.SourceSection;
import org.jspecify.annotations.Nullable;
import org.pkl.core.ast.ExpressionNode;
import org.pkl.core.runtime.Identifier;
import org.pkl.core.runtime.VmObjectLike;
@@ -34,7 +35,7 @@ public abstract sealed class AbstractInvokeMethodLexicalNode extends ExpressionN
protected final int levelsUp;
private final boolean needsConst;
@Children private ExpressionNode[] argumentNodes;
@Child private DirectCallNode callNode;
@Child private @Nullable DirectCallNode callNode;
@CompilationFinal protected boolean isConstChecked;
protected AbstractInvokeMethodLexicalNode(
@@ -90,6 +91,7 @@ public abstract sealed class AbstractInvokeMethodLexicalNode extends ExpressionN
callNode = DirectCallNode.create(getCallTarget(owner));
insert(callNode);
}
assert callNode != null;
return callNode;
}
}
@@ -19,17 +19,17 @@ import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;
import org.jspecify.annotations.Nullable;
import org.pkl.core.ast.ExpressionNode;
import org.pkl.core.ast.type.TypeNode.UnknownTypeNode;
import org.pkl.core.runtime.*;
import org.pkl.core.util.LateInit;
/** Infers the parent to amend in `function createPerson(): Person = new { ... }`. */
public final class InferParentWithinMethodNode extends ExpressionNode {
private final VmLanguage language;
private final Identifier methodName;
@Child private ExpressionNode ownerNode;
@CompilationFinal @LateInit private Object inferredParent;
@Child private @Nullable ExpressionNode ownerNode;
@CompilationFinal private @Nullable Object inferredParent;
public InferParentWithinMethodNode(
SourceSection sourceSection,
@@ -52,6 +52,7 @@ public final class InferParentWithinMethodNode extends ExpressionNode {
CompilerDirectives.transferToInterpreter();
assert ownerNode != null;
var owner = (VmObjectLike) ownerNode.executeGeneric(frame);
assert owner.isPrototype();
@@ -19,6 +19,7 @@ import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;
import org.jspecify.annotations.Nullable;
import org.pkl.core.ast.ExpressionNode;
import org.pkl.core.ast.member.ObjectMethodNode;
import org.pkl.core.ast.type.TypeNode.UnknownTypeNode;
@@ -26,14 +27,13 @@ import org.pkl.core.runtime.Identifier;
import org.pkl.core.runtime.VmDynamic;
import org.pkl.core.runtime.VmLanguage;
import org.pkl.core.runtime.VmObjectLike;
import org.pkl.core.util.LateInit;
/** Infers the parent to amend in `obj { local function createPerson(): Person = new { ... } }`. */
public final class InferParentWithinObjectMethodNode extends ExpressionNode {
private final VmLanguage language;
private final Identifier localMethodName;
@Child private ExpressionNode ownerNode;
@CompilationFinal @LateInit private Object inferredParent;
@Child private @Nullable ExpressionNode ownerNode;
@CompilationFinal private @Nullable Object inferredParent;
public InferParentWithinObjectMethodNode(
SourceSection sourceSection,
@@ -58,6 +58,7 @@ public final class InferParentWithinObjectMethodNode extends ExpressionNode {
CompilerDirectives.transferToInterpreter();
assert ownerNode != null;
var owner = (VmObjectLike) ownerNode.executeGeneric(frame);
var member = owner.getMember(localMethodName);
@@ -18,6 +18,7 @@ package org.pkl.core.ast.expression.member;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;
import org.jspecify.annotations.Nullable;
import org.pkl.core.ast.ExpressionNode;
import org.pkl.core.ast.MemberLookupMode;
import org.pkl.core.ast.expression.primary.GetEnclosingReceiverNode;
@@ -49,8 +50,8 @@ public final class ReadAmbiguousLocalityPropertyNode extends ExpressionNode {
private final Identifier name;
private final int levelsUp;
private final boolean needsConst;
private @Child ExpressionNode readLocalPropertyNode;
private @Child ExpressionNode readPropertyNode;
@Child private @Nullable ExpressionNode readLocalPropertyNode;
@Child private @Nullable ExpressionNode readPropertyNode;
public ReadAmbiguousLocalityPropertyNode(
SourceSection sourceSection, Identifier name, int levelsUp, boolean needsConst) {
@@ -22,6 +22,7 @@ import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.DirectCallNode;
import com.oracle.truffle.api.nodes.ExplodeLoop;
import com.oracle.truffle.api.source.SourceSection;
import org.jspecify.annotations.Nullable;
import org.pkl.core.PklBugException;
import org.pkl.core.ast.ExpressionNode;
import org.pkl.core.ast.member.ObjectMember;
@@ -34,8 +35,8 @@ public final class ReadLocalPropertyNode extends ExpressionNode {
private final Identifier name;
private final int levelsUp;
private final boolean needsConst;
@Child private DirectCallNode callNode;
@CompilationFinal private ObjectMember property;
@Child private @Nullable DirectCallNode callNode;
@CompilationFinal @Nullable private ObjectMember property;
public ReadLocalPropertyNode(
SourceSection sourceSection, Identifier name, int levelsUp, boolean needsConst) {
@@ -91,6 +92,7 @@ public final class ReadLocalPropertyNode extends ExpressionNode {
callNode = DirectCallNode.create(property.getCallTarget());
insert(callNode);
}
assert callNode != null;
return callNode;
}
}
@@ -23,6 +23,7 @@ import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.source.SourceSection;
import java.io.IOException;
import java.net.URI;
import org.jspecify.annotations.Nullable;
import org.pkl.core.SecurityManagerException;
import org.pkl.core.ast.member.SharedMemberNode;
import org.pkl.core.externalreader.ExternalReaderProcessException;
@@ -35,13 +36,12 @@ import org.pkl.core.runtime.VmMapping;
import org.pkl.core.runtime.VmObjectBuilder;
import org.pkl.core.util.GlobResolver;
import org.pkl.core.util.GlobResolver.InvalidGlobPatternException;
import org.pkl.core.util.LateInit;
@NodeInfo(shortName = "import*")
public class ImportGlobNode extends AbstractImportNode {
private final String globPattern;
@Child @LateInit private SharedMemberNode memberNode;
@CompilationFinal @LateInit private VmMapping cachedResult;
@Child private @Nullable SharedMemberNode memberNode;
@CompilationFinal private @Nullable VmMapping cachedResult;
public ImportGlobNode(
SourceSection sourceSection,
@@ -21,6 +21,7 @@ import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.source.SourceSection;
import java.net.URI;
import org.jspecify.annotations.Nullable;
import org.pkl.core.SecurityManagerException;
import org.pkl.core.http.HttpClientException;
import org.pkl.core.module.ResolvedModuleKey;
@@ -28,13 +29,12 @@ import org.pkl.core.packages.PackageLoadError;
import org.pkl.core.runtime.VmContext;
import org.pkl.core.runtime.VmLanguage;
import org.pkl.core.runtime.VmTyped;
import org.pkl.core.util.LateInit;
@NodeInfo(shortName = "import")
public final class ImportNode extends AbstractImportNode {
private final VmLanguage language;
@CompilationFinal @LateInit private VmTyped importedModule;
@CompilationFinal private @Nullable VmTyped importedModule;
public ImportNode(
VmLanguage language,
@@ -24,6 +24,7 @@ import com.oracle.truffle.api.source.SourceSection;
import java.io.IOException;
import java.net.URISyntaxException;
import org.graalvm.collections.EconomicMap;
import org.jspecify.annotations.Nullable;
import org.pkl.core.SecurityManagerException;
import org.pkl.core.ast.member.SharedMemberNode;
import org.pkl.core.externalreader.ExternalReaderProcessException;
@@ -36,12 +37,11 @@ import org.pkl.core.runtime.VmObjectBuilder;
import org.pkl.core.util.GlobResolver;
import org.pkl.core.util.GlobResolver.InvalidGlobPatternException;
import org.pkl.core.util.IoUtils;
import org.pkl.core.util.LateInit;
@NodeInfo(shortName = "read*")
public abstract class ReadGlobNode extends AbstractReadNode {
private final EconomicMap<String, VmMapping> cachedResults = EconomicMap.create();
@Child @LateInit private SharedMemberNode memberNode;
@Child private @Nullable SharedMemberNode memberNode;
protected ReadGlobNode(SourceSection sourceSection, ModuleKey currentModule) {
super(sourceSection, currentModule);
@@ -67,6 +67,7 @@ public abstract class ReadGlobNode extends AbstractReadNode {
@TruffleBoundary
public Object read(String globPattern) {
var cachedResult = cachedResults.get(globPattern);
//noinspection ConstantValue
if (cachedResult != null) return cachedResult;
// use same check as for globbed imports (see AstBuilder)
@@ -26,6 +26,7 @@ import org.pkl.core.TypeParameter;
import org.pkl.core.ast.VmModifier;
import org.pkl.core.ast.type.TypeNode;
import org.pkl.core.runtime.*;
import org.pkl.core.util.LateInit;
public final class ClassMethod extends ClassMember {
private final List<TypeParameter> typeParameters;
@@ -33,7 +34,7 @@ public final class ClassMethod extends ClassMember {
// null = not deprecated, "" = no/empty message in the @Deprecated body
private final @Nullable String deprecation;
@CompilationFinal private FunctionNode functionNode;
@CompilationFinal @LateInit private FunctionNode functionNode;
public ClassMethod(
SourceSection sourceSection,
@@ -61,6 +62,7 @@ public final class ClassMethod extends ClassMember {
}
public void initFunctionNode(FunctionNode functionNode) {
//noinspection ConstantValue
assert this.functionNode == null;
this.functionNode = functionNode;
}
@@ -84,6 +84,7 @@ public final class ClassNode extends ExpressionNode {
// Caching of classes also guarantees that classes are singletons and can be compared by
// identity,
// which improves efficiency and performance (for example in shape checks).
//noinspection ConstantValue
if (cachedClass != null) return cachedClass;
CompilerDirectives.transferToInterpreter();
@@ -18,7 +18,6 @@ package org.pkl.core.ast.member;
import com.oracle.truffle.api.frame.FrameDescriptor;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;
import org.jspecify.annotations.Nullable;
import org.pkl.core.ast.PklRootNode;
import org.pkl.core.ast.type.TypeNode;
import org.pkl.core.runtime.VmLanguage;
@@ -46,7 +45,7 @@ public final class ListingOrMappingTypeCastNode extends PklRootNode {
}
@Override
public @Nullable String getName() {
public String getName() {
return qualifiedName;
}
@@ -23,12 +23,11 @@ import org.pkl.core.ast.ExpressionNode;
import org.pkl.core.ast.type.TypeNode;
import org.pkl.core.ast.type.UnresolvedTypeNode;
import org.pkl.core.runtime.VmLanguage;
import org.pkl.core.util.LateInit;
public final class LocalTypedPropertyNode extends RegularMemberNode {
private final VmLanguage language;
@Child private UnresolvedTypeNode unresolvedTypeNode;
@Child @LateInit private TypeNode typeNode;
@Child private @Nullable UnresolvedTypeNode unresolvedTypeNode;
@Child private @Nullable TypeNode typeNode;
private @Nullable Object defaultValue;
private boolean defaultValueInitialized;
@@ -47,6 +46,7 @@ public final class LocalTypedPropertyNode extends RegularMemberNode {
public @Nullable Object getDefaultValue(VirtualFrame frame) {
if (!defaultValueInitialized) {
assert typeNode != null;
defaultValue =
typeNode.createDefaultValue(
frame, language, member.getHeaderSection(), member.getQualifiedName());
@@ -59,6 +59,7 @@ public final class LocalTypedPropertyNode extends RegularMemberNode {
protected Object executeImpl(VirtualFrame frame) {
if (typeNode == null) {
CompilerDirectives.transferToInterpreter();
assert unresolvedTypeNode != null;
typeNode = insert(unresolvedTypeNode.execute(frame));
unresolvedTypeNode = null;
}
@@ -25,7 +25,6 @@ import org.pkl.core.ast.ExpressionNode;
import org.pkl.core.ast.type.TypeNode;
import org.pkl.core.ast.type.UnresolvedTypeNode;
import org.pkl.core.runtime.*;
import org.pkl.core.util.LateInit;
public final class ObjectMethodNode extends RegularMemberNode {
private final VmLanguage language;
@@ -33,7 +32,7 @@ public final class ObjectMethodNode extends RegularMemberNode {
@Children private final @Nullable UnresolvedTypeNode[] unresolvedParameterTypeNodes;
@Child private @Nullable UnresolvedTypeNode unresolvedReturnTypeNode;
@CompilationFinal @LateInit private FunctionNode functionNode;
@CompilationFinal private @Nullable FunctionNode functionNode;
public ObjectMethodNode(
VmLanguage language,
@@ -19,6 +19,7 @@ import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;
import org.jspecify.annotations.Nullable;
import org.pkl.core.ast.ExpressionNode;
import org.pkl.core.runtime.*;
import org.pkl.core.util.LateInit;
@@ -26,7 +27,7 @@ import org.pkl.core.util.LateInit;
/** Resolves `<type>` to the type's default value in `new <type> { ... }`. */
public final class GetParentForTypeNode extends ExpressionNode {
@Child private UnresolvedTypeNode unresolvedTypeNode;
@Child private TypeNode typeNode;
@Child private @Nullable TypeNode typeNode;
private final String qualifiedName;
@CompilationFinal @LateInit Object defaultValue;
@@ -49,6 +50,7 @@ public final class GetParentForTypeNode extends ExpressionNode {
@Override
public Object executeGeneric(VirtualFrame frame) {
//noinspection ConstantValue
if (defaultValue != null) return defaultValue;
CompilerDirectives.transferToInterpreterAndInvalidate();
@@ -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");
* you may not use this file except in compliance with the License.
@@ -19,14 +19,14 @@ import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.source.SourceSection;
import org.jspecify.annotations.Nullable;
import org.pkl.core.ast.ExpressionNode;
import org.pkl.core.util.LateInit;
@NodeInfo(shortName = "as")
public final class TypeCastNode extends ExpressionNode {
@Child private ExpressionNode valueNode;
@Child private UnresolvedTypeNode unresolvedTypeNode;
@Child @LateInit private TypeNode typeNode;
@Child private @Nullable UnresolvedTypeNode unresolvedTypeNode;
@Child private @Nullable TypeNode typeNode;
public TypeCastNode(
SourceSection sourceSection,
@@ -43,6 +43,7 @@ public final class TypeCastNode extends ExpressionNode {
// don't compile unresolvedTypeNode.execute()
// invalidation is done by insert()
CompilerDirectives.transferToInterpreter();
assert unresolvedTypeNode != null;
typeNode = insert(unresolvedTypeNode.execute(frame));
unresolvedTypeNode = null;
}
@@ -239,7 +239,7 @@ public abstract class TypeNode extends PklNode {
public abstract static class FrameSlotTypeNode extends TypeNode {
@CompilationFinal protected int slot = -1;
@CompilationFinal @Child protected WriteFrameSlotNode writeFrameSlotNode;
@CompilationFinal @Child protected @Nullable WriteFrameSlotNode writeFrameSlotNode;
protected FrameSlotTypeNode(SourceSection sourceSection) {
super(sourceSection);
@@ -26,7 +26,7 @@ import org.pkl.core.runtime.VmLanguage;
@NodeInfo(shortName = "is")
public final class TypeTestNode extends ExpressionNode {
@Child private ExpressionNode valueNode;
@Child private UnresolvedTypeNode unresolvedTypeNode;
@Child private @Nullable UnresolvedTypeNode unresolvedTypeNode;
@Child private @Nullable TypeNode typeNode;
public TypeTestNode(
@@ -49,6 +49,7 @@ public final class TypeTestNode extends ExpressionNode {
// don't compile unresolvedTypeNode.execute()
// invalidation is done by insert()
CompilerDirectives.transferToInterpreter();
assert unresolvedTypeNode != null;
typeNode = insert(unresolvedTypeNode.execute(frame));
unresolvedTypeNode = null;
}
@@ -103,7 +103,7 @@ final class ExternalResourceResolverImpl implements ExternalResourceResolver {
readResponses.computeIfAbsent(
baseUri,
(uri) -> {
var future = new CompletableFuture<byte[]>();
var future = new CompletableFuture<byte @Nullable []>();
var request =
new ReadResourceRequest(requestIdGenerator.nextLong(), evaluatorId, uri);
try {
@@ -46,7 +46,6 @@ import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.TrustManagerFactory;
import org.pkl.core.SecurityManagerException;
import org.pkl.core.util.ErrorMessages;
import org.pkl.core.util.Exceptions;
@@ -93,7 +92,7 @@ final class JdkHttpClient implements HttpClient {
HttpRequest request,
BodyHandler<T> responseBodyHandler,
HttpRequestChecker httpRequestChecker)
throws IOException, SecurityManagerException {
throws IOException {
try {
return underlying.send(request, responseBodyHandler);
} catch (ConnectException e) {
@@ -84,7 +84,7 @@ public final class Messages {
}
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}
@@ -93,12 +93,14 @@ public class PathElement {
}
/** Returns the element at path {@code basePath}, given a {@link Path}. */
@SuppressWarnings("DataFlowIssue") // incorrect analysis; this can return null.
public @Nullable TreePathElement getElement(Path basePath) {
var path = basePath.normalize();
var element = this;
for (var i = 0; i < path.getNameCount(); i++) {
var part = path.getName(i).toString();
element = element.getChildren().get(part);
//noinspection ConstantValue
if (element == null) {
return null;
}
@@ -183,6 +183,7 @@ public final class ProjectDependenciesManager {
public Map<String, Dependency> getLocalPackageDependencies(PackageUri packageUri) {
ensureDependenciesInitialized();
var dep = localPackageDependencies.get(packageUri);
//noinspection ConstantValue
assert dep != null;
return dep;
}
@@ -67,7 +67,7 @@ public abstract class Dependency {
}
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}
@@ -107,7 +107,7 @@ public abstract class Dependency {
}
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}
@@ -217,6 +217,7 @@ public final class DependencyMetadata {
var map = new HashMap<>();
for (var kv : value) {
var kvObj = (JsObject) kv;
assert kvObj != null;
map.put(parsePObject(kvObj.get("key")), parsePObject(kvObj.get("value")));
}
return map;
@@ -294,7 +295,7 @@ public final class DependencyMetadata {
var ret = new ArrayList<String>(arr.size());
for (var elem : arr) {
if (!(elem instanceof String string)) {
throw new FormatException("string", elem.getClass());
throw new FormatException("string", elem != null ? elem.getClass() : Void.class);
}
ret.add(string);
}
@@ -414,7 +415,7 @@ public final class DependencyMetadata {
}
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}
@@ -624,8 +625,8 @@ public final class DependencyMetadata {
jsonWriter.endObject();
}
private void writeGenericObject(Object value) throws IOException {
if (value instanceof PNull) {
private void writeGenericObject(@Nullable Object value) throws IOException {
if (value == null || value instanceof PNull) {
jsonWriter.nullValue();
} else if (value instanceof PObject pObject) {
writePObject(pObject);
@@ -18,6 +18,7 @@ package org.pkl.core.packages;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Path;
import org.jspecify.annotations.Nullable;
import org.pkl.core.PklBugException;
import org.pkl.core.Version;
import org.pkl.core.util.ErrorMessages;
@@ -98,7 +99,7 @@ public final class PackageAssetUri {
}
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}
@@ -118,7 +118,7 @@ public final class PackageUri {
}
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}
@@ -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");
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@ package org.pkl.core.project;
import java.net.URI;
import java.net.URISyntaxException;
import org.jspecify.annotations.Nullable;
import org.pkl.core.PklBugException;
import org.pkl.core.packages.PackageUri;
import org.pkl.core.util.ErrorMessages;
@@ -84,7 +85,7 @@ public record CanonicalPackageUri(URI baseUri, int majorVersion) {
}
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}
@@ -199,7 +199,7 @@ public final class Project {
sb.append("\n│");
}
sb.append("\n│ ");
sb.append(uri.toString());
sb.append(uri);
}
sb.append("\n└─");
}
@@ -477,7 +477,7 @@ public final class Project {
}
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}
@@ -611,7 +611,7 @@ public final class Project {
}
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}
@@ -141,6 +141,7 @@ public final class ProjectDependenciesResolver {
private void updateDependency(Dependency dependency) {
var canonicalPackageUri = CanonicalPackageUri.fromPackageUri(dependency.getPackageUri());
var currentDependency = resolvedDependencies.get(canonicalPackageUri);
//noinspection ConstantValue
if (currentDependency == null
|| currentDependency.getVersion().compareTo(dependency.getVersion()) < 0) {
EconomicMaps.put(resolvedDependencies, canonicalPackageUri, dependency);
@@ -135,6 +135,7 @@ public final class ProjectDeps {
}
/** Given a declared dependency, return the resolved dependency. */
@SuppressWarnings("DataFlowIssue") // incorrect analysis
public @Nullable Dependency get(CanonicalPackageUri canonicalPackageUri) {
return resolvedDependencies.get(canonicalPackageUri);
}
@@ -150,7 +151,7 @@ public final class ProjectDeps {
}
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}
@@ -51,6 +51,8 @@ public final class FileSystemManager {
public static synchronized FileSystem getFileSystem(URI uri) throws IOException {
var fs = fileSystems.get(uri);
// incorrect nullability for `org.graalvm.collections.UnmodifiableEconomicMap`
//noinspection ConstantValue
if (fs != null) {
var count = counts.get(fs);
assert count != null;
@@ -40,10 +40,10 @@ public final class ModuleInfo {
@LateInit private List<VmTyped> annotations;
@LateInit private VmTyped __mirror;
private @Nullable VmTyped __mirror;
private final Object mirrorLock = new Object();
@LateInit private ModuleSchema __moduleSchema;
private @Nullable ModuleSchema __moduleSchema;
private final Object moduleSchemaLock = new Object();
public ModuleInfo(
@@ -65,12 +65,12 @@ public final class ModuleInfo {
}
public void initAnnotations(List<VmTyped> annotations) {
//noinspection ConstantValue
assert this.annotations == null;
this.annotations = annotations;
}
public List<VmTyped> getAnnotations() {
assert annotations != null;
return annotations;
}
@@ -101,8 +101,14 @@ public final class StackTraceRenderer {
if (hint != null) {
out.append(AnsiTheme.ERROR_MESSAGE_HINT, hint);
} else {
assert hintBuilder != null;
out.append(AnsiTheme.ERROR_MESSAGE_HINT, () -> hintBuilder.accept(out, true));
out.append(
AnsiTheme.ERROR_MESSAGE_HINT,
() -> {
// nullaway needs this assertion
//noinspection ConstantValue
assert hintBuilder != null;
hintBuilder.accept(out, true);
});
}
out.append('\n');
}
@@ -491,11 +491,11 @@ public final class TestRunner {
sb.append("\n Expected: ");
appendLocation(sb, expectedLocation);
sb.append("\n ");
sb.append(AnsiTheme.TEST_EXAMPLE_OUTPUT, expectedValue.replaceAll("\n", "\n "));
sb.append(AnsiTheme.TEST_EXAMPLE_OUTPUT, expectedValue.replace("\n", "\n "));
sb.append("\n Actual: ");
appendLocation(sb, actualLocation);
sb.append("\n ");
sb.append(AnsiTheme.TEST_EXAMPLE_OUTPUT, actualValue.replaceAll("\n", "\n "));
sb.append(AnsiTheme.TEST_EXAMPLE_OUTPUT, actualValue.replace("\n", "\n "));
});
return new Failure("Example Failure", sb.toString());
}
@@ -107,6 +107,7 @@ public final class VmContext {
}
public void initialize(Holder holder) {
//noinspection ConstantValue
assert this.holder == null;
this.holder = holder;
}
@@ -19,6 +19,7 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.frame.MaterializedFrame;
import java.util.Objects;
import org.graalvm.collections.UnmodifiableEconomicMap;
import org.jspecify.annotations.Nullable;
import org.pkl.core.PClassInfo;
import org.pkl.core.PObject;
import org.pkl.core.ast.member.ObjectMember;
@@ -75,12 +76,14 @@ public final class VmDynamic extends VmObject {
@Override
@TruffleBoundary
public PObject export() {
assert forced : "Value was not forced prior to export";
var properties =
CollectionUtils.<String, Object>newLinkedHashMap(EconomicMaps.size(cachedValues));
iterateMemberValues(
iterateAlreadyForcedMemberValues(
(key, member, value) -> {
properties.put(key.toString(), VmValue.exportNullable(value));
properties.put(key.toString(), VmValue.export(value));
return true;
});
@@ -99,9 +102,8 @@ public final class VmDynamic extends VmObject {
@Override
@TruffleBoundary
public boolean equals(Object obj) {
if (this == obj) // noinspection Contract
return true;
public boolean equals(@Nullable Object obj) {
if (this == obj) return true;
if (!(obj instanceof VmDynamic other)) return false;
// could use shallow force, but deep force is cached
@@ -115,6 +117,7 @@ public final class VmDynamic extends VmObject {
if (isHiddenOrLocalProperty(key)) continue;
var value = cursor.getValue();
//noinspection ConstantValue
assert value != null;
var otherValue = other.getCachedValue(key);
if (!value.equals(otherValue)) return false;
@@ -137,6 +140,7 @@ public final class VmDynamic extends VmObject {
if (isHiddenOrLocalProperty(key)) continue;
var value = cursor.getValue();
//noinspection ConstantValue
assert value != null;
result += key.hashCode() ^ value.hashCode();
}
@@ -87,13 +87,15 @@ public final class VmListing extends VmListingOrMapping {
@Override
@TruffleBoundary
public List<Object> export() {
assert forced : "Value was not forced prior to export";
var properties = new ArrayList<>(EconomicMaps.size(cachedValues));
iterateMemberValues(
iterateAlreadyForcedMemberValues(
(key, prop, value) -> {
if (isDefaultProperty(key)) return true;
properties.add(VmValue.exportNullable(value));
properties.add(VmValue.export(value));
return true;
});
@@ -127,6 +129,7 @@ public final class VmListing extends VmListingOrMapping {
if (key instanceof Identifier) continue;
var value = cursor.getValue();
//noinspection ConstantValue
assert value != null;
var otherValue = other.getCachedValue(key);
if (!value.equals(otherValue)) return false;
@@ -149,6 +152,7 @@ public final class VmListing extends VmListingOrMapping {
if (key instanceof Identifier) continue;
var value = cursor.getValue();
//noinspection ConstantValue
assert value != null;
result = 31 * result + value.hashCode();
}
@@ -147,6 +147,7 @@ public final class VmMap extends VmValue implements Iterable<Map.Entry<Object, O
for (var key : other.keyOrder) {
var value = other.map.get(key);
assert value != null;
if (!map.containsKey(key)) {
keyOrderBuilder.append(key);
@@ -21,19 +21,18 @@ import com.oracle.truffle.api.frame.MaterializedFrame;
import java.util.HashSet;
import java.util.Map;
import org.graalvm.collections.UnmodifiableEconomicMap;
import org.jspecify.annotations.Nullable;
import org.pkl.core.ast.member.ListingOrMappingTypeCastNode;
import org.pkl.core.ast.member.ObjectMember;
import org.pkl.core.util.CollectionUtils;
import org.pkl.core.util.EconomicMaps;
import org.pkl.core.util.LateInit;
import org.pkl.core.util.MutableLong;
public final class VmMapping extends VmListingOrMapping {
private long cachedLength = -1;
@GuardedBy("this")
@LateInit
private VmSet __allKeys;
private @Nullable VmSet __allKeys;
private static final class EmptyHolder {
private static final VmMapping EMPTY =
@@ -94,13 +93,15 @@ public final class VmMapping extends VmListingOrMapping {
@Override
@TruffleBoundary
public Map<Object, Object> export() {
assert forced : "Value was not forced prior to export";
var properties = CollectionUtils.newLinkedHashMap(EconomicMaps.size(cachedValues));
iterateMemberValues(
iterateAlreadyForcedMemberValues(
(key, prop, value) -> {
if (isDefaultProperty(key)) return true;
properties.put(VmValue.export(key), VmValue.exportNullable(value));
properties.put(VmValue.export(key), VmValue.export(value));
return true;
});
@@ -119,9 +120,8 @@ public final class VmMapping extends VmListingOrMapping {
@Override
@TruffleBoundary
public boolean equals(Object obj) {
if (this == obj) // noinspection Contract
return true;
public boolean equals(@Nullable Object obj) {
if (this == obj) return true;
if (!(obj instanceof VmMapping other)) return false;
// could use shallow force, but deep force is cached
@@ -135,6 +135,7 @@ public final class VmMapping extends VmListingOrMapping {
if (key instanceof Identifier) continue;
var value = cursor.getValue();
//noinspection ConstantValue
assert value != null;
var otherValue = other.getCachedValue(key);
if (!value.equals(otherValue)) return false;
@@ -157,6 +158,7 @@ public final class VmMapping extends VmListingOrMapping {
if (key instanceof Identifier) continue;
var value = cursor.getValue();
//noinspection ConstantValue
assert value != null;
result += key.hashCode() ^ value.hashCode();
}
@@ -34,7 +34,7 @@ public abstract class VmObject extends VmObjectLike {
protected final EconomicMap<Object, Object> cachedValues;
protected int cachedHash;
private boolean forced;
protected boolean forced;
public VmObject(
MaterializedFrame enclosingFrame,
@@ -204,17 +204,20 @@ public abstract class VmObject extends VmObjectLike {
/**
* Exports this object's members. Skips local members, hidden members, class definitions, and type
* aliases. Members that haven't been forced have a `null` value.
* aliases.
*
* <p>Assumes that this object has already been forced.
*/
@TruffleBoundary
protected final Map<String, Object> exportMembers() {
var result = CollectionUtils.<String, Object>newLinkedHashMap(EconomicMaps.size(cachedValues));
Map<String, Object> result = CollectionUtils.newLinkedHashMap(EconomicMaps.size(cachedValues));
assert forced : "Value was not forced prior to export";
iterateMemberValues(
iterateAlreadyForcedMemberValues(
(key, member, value) -> {
if (member.isClass() || member.isTypeAlias()) return true;
result.put(key.toString(), VmValue.exportNullable(value));
result.put(key.toString(), VmValue.export(value));
return true;
});
@@ -30,6 +30,7 @@ import org.pkl.core.Composite;
import org.pkl.core.PClass;
import org.pkl.core.PClassInfo;
import org.pkl.core.PType;
import org.pkl.core.PklBugException;
import org.pkl.core.Reference;
import org.pkl.core.TypeAlias;
import org.pkl.core.util.paguro.RrbTree;
@@ -218,6 +219,15 @@ public final class VmReference extends VmValue {
normalizeTypes(prop.getType(), clazz.getPClass().getModuleClass(), result);
}
private static PClassInfo<?> getClassInfo(Object value) {
if (value instanceof VmValue vmValue) return vmValue.getVmClass().getPClassInfo();
if (value instanceof String) return PClassInfo.String;
if (value instanceof Boolean) return PClassInfo.Boolean;
if (value instanceof Long) return PClassInfo.Int;
if (value instanceof Double) return PClassInfo.Float;
throw new PklBugException("Not a Pkl value: " + value.getClass());
}
@SuppressWarnings("DuplicatedCode")
private static void getCandidateSubscriptType(PType type, Object key, Set<PType> result) {
if (type == PType.UNKNOWN) {
@@ -244,8 +254,7 @@ public final class VmReference extends VmValue {
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.Class klazz && klazz.getPClass().getInfo() == getClassInfo(key))
|| (kt instanceof PType.StringLiteral stringLiteral
&& stringLiteral.getLiteral().equals(key))) {
normalizeTypes(typeArgs.get(1), clazz.getPClass().getModuleClass(), result);
@@ -34,7 +34,6 @@ import org.pkl.core.ast.type.TypeNode;
import org.pkl.core.ast.type.TypeNode.ConstrainedTypeNode;
import org.pkl.core.ast.type.TypeNode.TypeVariableNode;
import org.pkl.core.ast.type.TypeNode.UnknownTypeNode;
import org.pkl.core.util.LateInit;
public final class VmTypeAlias extends VmValue {
private final SourceSection sourceSection;
@@ -48,17 +47,15 @@ public final class VmTypeAlias extends VmValue {
private final List<TypeParameter> typeParameters;
private final MaterializedFrame enclosingFrame;
@LateInit private TypeNode typeNode;
private @Nullable TypeNode typeNode;
@LateInit
@GuardedBy("pTypeAliasLock")
private TypeAlias __pTypeAlias;
private @Nullable TypeAlias __pTypeAlias;
private final Object pTypeAliasLock = new Object();
@LateInit
@GuardedBy("mirrorLock")
private VmTyped __mirror;
private @Nullable VmTyped __mirror;
private final Object mirrorLock = new Object();
@@ -86,7 +83,6 @@ public final class VmTypeAlias extends VmValue {
}
public void initTypeCheckNode(TypeNode typeNode) {
assert this.typeNode == null;
this.typeNode = typeNode;
}
@@ -100,6 +96,7 @@ public final class VmTypeAlias extends VmValue {
*/
@TruffleBoundary
public SourceSection getBaseTypeSection() {
assert typeNode != null;
if (typeNode instanceof ConstrainedTypeNode constrainedTypeNode) {
return constrainedTypeNode.getBaseTypeSection();
}
@@ -116,6 +113,7 @@ public final class VmTypeAlias extends VmValue {
*/
@TruffleBoundary
public SourceSection getConstraintSection() {
assert typeNode != null;
if (typeNode instanceof ConstrainedTypeNode) {
return ((ConstrainedTypeNode) typeNode).getFirstConstraintSection();
}
@@ -169,6 +167,7 @@ public final class VmTypeAlias extends VmValue {
}
public TypeNode getTypeNode() {
assert typeNode != null;
return typeNode;
}
@@ -178,6 +177,7 @@ public final class VmTypeAlias extends VmValue {
@TruffleBoundary
public TypeNode instantiate(TypeNode[] typeArgumentNodes) {
assert typeNode != null;
// 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:
// * Fewer root nodes to call
@@ -265,6 +265,7 @@ public final class VmTypeAlias extends VmValue {
}
public VmTyped getTypeMirror() {
assert typeNode != null;
return typeNode.getMirror();
}
@@ -29,10 +29,9 @@ import org.pkl.core.ast.ExpressionNode;
import org.pkl.core.ast.expression.unary.ImportNode;
import org.pkl.core.ast.member.ObjectMember;
import org.pkl.core.util.EconomicMaps;
import org.pkl.core.util.LateInit;
public final class VmTyped extends VmObject {
@CompilationFinal @LateInit private VmClass clazz;
@CompilationFinal private @Nullable VmClass clazz;
public VmTyped(
MaterializedFrame enclosingFrame,
@@ -162,6 +161,8 @@ public final class VmTyped extends VmObject {
@Override
@TruffleBoundary
public Composite export() {
assert forced : "Value was not forced prior to export";
assert clazz != null;
if (!isModuleObject()) {
return new PObject(clazz.getPClassInfo(), exportMembers());
}
@@ -190,6 +191,7 @@ public final class VmTyped extends VmObject {
if (this == obj) return true;
if (!(obj instanceof VmTyped other)) return false;
assert clazz != null;
if (clazz != other.clazz) return false;
// could use shallow force, but deep force is cached
force(false);
@@ -210,6 +212,7 @@ public final class VmTyped extends VmObject {
public int hashCode() {
if (cachedHash != 0) return cachedHash;
assert clazz != null;
force(false);
var result = 0;
@@ -94,6 +94,7 @@ public final class VmObjectFactory<E> {
? TypeCheckedPropertyNodeGen.create(null, new FrameDescriptor(), member, bodyNode)
: new UntypedObjectMemberNode(null, new FrameDescriptor(), member, bodyNode);
member.initMemberNode(node);
//noinspection ConstantValue
if (members.put(identifier, member) != null) {
throw new VmExceptionBuilder()
.bug(
@@ -110,7 +111,6 @@ public final class VmObjectFactory<E> {
@TruffleBoundary
public VmTyped create(@Nullable E extraStorage) {
var clazz = classSupplier.get();
assert clazz != null;
var result =
new VmTyped(VmUtils.createEmptyMaterializedFrame(), clazz.getPrototype(), clazz, members);
@@ -46,7 +46,7 @@ import org.pkl.core.stdlib.ExternalPropertyNode;
* CLI args) would lead to incorrect behavior, as a single base module instance is shared across all
* language contexts, and properties (whether external or not) are evaluated just once.
*/
@SuppressWarnings("UnusedParameters")
@SuppressWarnings("unused")
public final class BaseNodes {
private BaseNodes() {}
@@ -64,6 +64,7 @@ public final class BaseNodes {
}
}
@SuppressWarnings("unused")
public abstract static class Regex extends ExternalMethod1Node {
// cache Regex object to avoid repeated java.util.Pattern.compile()
@Specialization(guards = "pattern.equals(cachedPattern)")
@@ -20,6 +20,7 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.LoopNode;
import org.jspecify.annotations.Nullable;
import org.pkl.core.ast.expression.binary.*;
import org.pkl.core.ast.internal.IsInstanceOfNode;
import org.pkl.core.ast.internal.IsInstanceOfNodeGen;
@@ -33,7 +34,6 @@ import org.pkl.core.stdlib.base.CollectionNodes.CompareByNode;
import org.pkl.core.stdlib.base.CollectionNodes.CompareNode;
import org.pkl.core.stdlib.base.CollectionNodes.CompareWithNode;
import org.pkl.core.util.EconomicSets;
import org.pkl.core.util.LateInit;
// duplication between ListNodes and SetNodes is "intentional"
// (sharing nodes between VmCollection subtypes results in
@@ -1336,7 +1336,7 @@ public final class ListNodes {
public abstract static class toBytes extends ExternalMethod0Node {
@Child @LateInit private TypeNode typeNode;
@Child private @Nullable TypeNode typeNode;
private TypeNode getTypeNode() {
if (typeNode == null) {
@@ -28,6 +28,7 @@ import org.pkl.core.runtime.*;
import org.pkl.core.stdlib.ExternalMethod1Node;
import org.pkl.core.stdlib.PklConverter;
import org.pkl.core.util.EconomicMaps;
import org.pkl.core.util.LateInit;
import org.pkl.core.util.json.JsonHandler;
import org.pkl.core.util.json.JsonParser;
import org.pkl.core.util.json.ParseException;
@@ -71,6 +72,8 @@ public final class ParserNodes {
private final Deque<Object> currPath = new ArrayDeque<>();
@LateInit private Object value;
public Handler(PklConverter converter, boolean useMapping) {
this.converter = converter;
this.useMapping = useMapping;
@@ -78,8 +81,6 @@ public final class ParserNodes {
currPath.push(VmValueConverter.TOP_LEVEL_VALUE);
}
private Object value;
@Override
public void endNull() {
value = VmNull.withoutDefault();
@@ -617,7 +617,7 @@ public final class RendererNodes {
// - All element types are resolved also.
// - All string literal types are combined into a single String case.
var hasString = false;
var elements = new ArrayList<TypeNode>();
var elements = new ArrayList<@Nullable TypeNode>();
for (var t : ((UnionTypeNode) type).getElementTypeNodes()) {
var resolved = resolveType(t);
if (resolved instanceof StringLiteralTypeNode || resolved instanceof StringTypeNode) {
@@ -21,6 +21,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import org.graalvm.collections.EconomicMap;
import org.jspecify.annotations.Nullable;
import org.pkl.core.TestResults;
import org.pkl.core.TestResults.Error;
import org.pkl.core.TestResults.TestResult;
@@ -59,8 +60,6 @@ public final class JUnitReporter implements TestReporter {
var totalTests = allTestResults.stream().mapToLong(TestResults::totalTests).sum();
var totalFailures = allTestResults.stream().mapToLong(TestResults::totalFailures).sum();
assert aggregateSuiteName != null;
var attrs =
buildAttributes(
"name", aggregateSuiteName,
@@ -206,12 +205,15 @@ public final class JUnitReporter implements TestReporter {
members.size() - 4);
}
private VmMapping buildAttributes(Object... attributes) {
private VmMapping buildAttributes(@Nullable Object... attributes) {
EconomicMap<Object, ObjectMember> attrs = EconomicMaps.create(attributes.length);
for (int i = 0; i < attributes.length; i += 2) {
attrs.put(
attributes[i],
VmUtils.createSyntheticObjectEntry(attributes[i].toString(), attributes[i + 1]));
for (var i = 0; i < attributes.length; i += 2) {
var key = attributes[i];
var value = attributes[i + 1];
if (key == null || value == null) {
continue;
}
attrs.put(key, VmUtils.createSyntheticObjectEntry(key.toString(), value));
}
return new VmMapping(
VmUtils.createEmptyMaterializedFrame(), BaseModule.getMappingClass().getPrototype(), attrs);
@@ -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");
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@ package org.pkl.core.util;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import org.jspecify.annotations.Nullable;
public final class CollectionUtils {
private static final float LOAD_FACTOR = 0.75f;
@@ -45,7 +46,8 @@ public final class CollectionUtils {
}
@TruffleBoundary
public static <K, V> LinkedHashMap<K, V> newLinkedHashMap(int expectedSize) {
public static <K extends @Nullable Object, V extends @Nullable Object>
LinkedHashMap<K, V> newLinkedHashMap(int expectedSize) {
return new LinkedHashMap<>((int) (expectedSize / LOAD_FACTOR) + 1, LOAD_FACTOR);
}
@@ -81,11 +81,13 @@ public final class EconomicMaps {
return result;
}
@SuppressWarnings("DataFlowIssue")
@TruffleBoundary
public static <K, V> @Nullable V get(UnmodifiableEconomicMap<K, V> self, K key) {
return self.get(key);
}
@SuppressWarnings("DataFlowIssue")
@TruffleBoundary
public static <K, V> @Nullable V get(UnmodifiableEconomicMap<K, V> self, K key, V defaultValue) {
return self.get(key, defaultValue);
@@ -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");
* you may not use this file except in compliance with the License.
@@ -381,6 +381,7 @@ public final class JsonParser {
}
private void startCapture() {
//noinspection ConstantValue
if (captureBuffer == null) {
captureBuffer = new StringBuilder();
}
@@ -25,7 +25,7 @@ import org.jspecify.annotations.Nullable;
/**
* Writes a JSON (<a href="http://www.ietf.org/rfc/rfc7159.txt">RFC 7159</a>) encoded value to a
* stream, one token at a time. The stream includes both literal values (strings, numbers, booleans
* and nulls) as well as the begin and end delimiters of objects and arrays.
* and nulls) as well as the beginning and ending delimiters of objects and arrays.
*
* <h3>Encoding JSON</h3>
*
@@ -195,7 +195,7 @@ public final class JsonWriter implements Closeable, Flushable {
/**
* Sets the indentation string to be repeated for each level of indentation in the encoded
* document. If {@code indent.isEmpty()} the encoded document will be compact. Otherwise the
* document. If {@code indent.isEmpty()} the encoded document will be compact. Otherwise, the
* encoded document will be more human-readable.
*
* @param indent a string containing only whitespace.
@@ -418,6 +418,8 @@ public final class JsonWriter implements Closeable, Flushable {
public JsonWriter value(boolean value) throws IOException {
writeDeferredName();
beforeValue();
// avoid method dispatch
//noinspection SimplifiableConditionalExpression
out.write(value ? "true" : "false");
return this;
}
@@ -433,6 +435,8 @@ public final class JsonWriter implements Closeable, Flushable {
}
writeDeferredName();
beforeValue();
// avoid method dispatch
//noinspection SimplifiableConditionalExpression
out.write(value ? "true" : "false");
return this;
}
@@ -922,7 +922,10 @@ public abstract class RrbTree<E> implements BaseList<E>, Indented {
/** {@inheritDoc} */
@SuppressWarnings("unchecked")
@Override
public boolean equals(Object other) {
public boolean equals(@Nullable Object other) {
if (other == null) {
return false;
}
if (this == other) {
return true;
}