From 139d1ae8eca26ceaad4d28ec2b10833833cf2b66 Mon Sep 17 00:00:00 2001 From: Daniel Chao Date: Mon, 29 Jun 2026 09:22:19 -0700 Subject: [PATCH] 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. --- .../main/java/org/pkl/core/ImportGraph.java | 8 ++++---- .../main/java/org/pkl/core/JsonRenderer.java | 2 ++ .../main/java/org/pkl/core/ModuleSchema.java | 5 ++--- .../main/java/org/pkl/core/PcfRenderer.java | 6 ++---- .../java/org/pkl/core/PklBinaryDecoder.java | 6 ++++-- .../java/org/pkl/core/PropertiesRenderer.java | 3 +++ .../main/java/org/pkl/core/TypeParameter.java | 7 ++++--- .../src/main/java/org/pkl/core/Version.java | 4 ++-- .../expression/literal/BytesLiteralNode.java | 6 +++--- .../AbstractInvokeMethodLexicalNode.java | 4 +++- .../member/InferParentWithinMethodNode.java | 7 ++++--- .../InferParentWithinObjectMethodNode.java | 7 ++++--- .../ReadAmbiguousLocalityPropertyNode.java | 5 +++-- .../member/ReadLocalPropertyNode.java | 6 ++++-- .../ast/expression/unary/ImportGlobNode.java | 6 +++--- .../core/ast/expression/unary/ImportNode.java | 4 ++-- .../ast/expression/unary/ReadGlobNode.java | 5 +++-- .../org/pkl/core/ast/member/ClassMethod.java | 4 +++- .../org/pkl/core/ast/member/ClassNode.java | 1 + .../member/ListingOrMappingTypeCastNode.java | 3 +-- .../ast/member/LocalTypedPropertyNode.java | 7 ++++--- .../pkl/core/ast/member/ObjectMethodNode.java | 3 +-- .../core/ast/type/GetParentForTypeNode.java | 4 +++- .../org/pkl/core/ast/type/TypeCastNode.java | 9 +++++---- .../java/org/pkl/core/ast/type/TypeNode.java | 2 +- .../org/pkl/core/ast/type/TypeTestNode.java | 3 ++- .../ExternalResourceResolverImpl.java | 2 +- .../java/org/pkl/core/http/JdkHttpClient.java | 3 +-- .../java/org/pkl/core/messaging/Messages.java | 2 +- .../java/org/pkl/core/module/PathElement.java | 2 ++ .../module/ProjectDependenciesManager.java | 1 + .../java/org/pkl/core/packages/Dependency.java | 4 ++-- .../pkl/core/packages/DependencyMetadata.java | 9 +++++---- .../org/pkl/core/packages/PackageAssetUri.java | 3 ++- .../java/org/pkl/core/packages/PackageUri.java | 2 +- .../pkl/core/project/CanonicalPackageUri.java | 5 +++-- .../java/org/pkl/core/project/Project.java | 6 +++--- .../project/ProjectDependenciesResolver.java | 1 + .../java/org/pkl/core/project/ProjectDeps.java | 3 ++- .../pkl/core/runtime/FileSystemManager.java | 2 ++ .../java/org/pkl/core/runtime/ModuleInfo.java | 6 +++--- .../pkl/core/runtime/StackTraceRenderer.java | 10 ++++++++-- .../java/org/pkl/core/runtime/TestRunner.java | 4 ++-- .../java/org/pkl/core/runtime/VmContext.java | 1 + .../java/org/pkl/core/runtime/VmDynamic.java | 14 +++++++++----- .../java/org/pkl/core/runtime/VmListing.java | 8 ++++++-- .../main/java/org/pkl/core/runtime/VmMap.java | 1 + .../java/org/pkl/core/runtime/VmMapping.java | 18 ++++++++++-------- .../java/org/pkl/core/runtime/VmObject.java | 13 ++++++++----- .../java/org/pkl/core/runtime/VmReference.java | 13 +++++++++++-- .../java/org/pkl/core/runtime/VmTypeAlias.java | 15 ++++++++------- .../java/org/pkl/core/runtime/VmTyped.java | 7 +++++-- .../org/pkl/core/stdlib/VmObjectFactory.java | 2 +- .../org/pkl/core/stdlib/base/BaseNodes.java | 3 ++- .../org/pkl/core/stdlib/base/ListNodes.java | 4 ++-- .../org/pkl/core/stdlib/json/ParserNodes.java | 5 +++-- .../core/stdlib/protobuf/RendererNodes.java | 2 +- .../core/stdlib/test/report/JUnitReporter.java | 16 +++++++++------- .../org/pkl/core/util/CollectionUtils.java | 6 ++++-- .../java/org/pkl/core/util/EconomicMaps.java | 2 ++ .../org/pkl/core/util/json/JsonParser.java | 3 ++- .../org/pkl/core/util/json/JsonWriter.java | 8 ++++++-- .../java/org/pkl/core/util/paguro/RrbTree.java | 5 ++++- 63 files changed, 208 insertions(+), 130 deletions(-) diff --git a/pkl-core/src/main/java/org/pkl/core/ImportGraph.java b/pkl-core/src/main/java/org/pkl/core/ImportGraph.java index 94ba0facc..5b87316eb 100644 --- a/pkl-core/src/main/java/org/pkl/core/ImportGraph.java +++ b/pkl-core/src/main/java/org/pkl/core/ImportGraph.java @@ -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> imports, Map resolvedI var value = entry.getValue(); var set = new TreeSet(); 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> imports, Map 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); diff --git a/pkl-core/src/main/java/org/pkl/core/JsonRenderer.java b/pkl-core/src/main/java/org/pkl/core/JsonRenderer.java index 3805fed0c..24002af65 100644 --- a/pkl-core/src/main/java/org/pkl/core/JsonRenderer.java +++ b/pkl-core/src/main/java/org/pkl/core/JsonRenderer.java @@ -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 { diff --git a/pkl-core/src/main/java/org/pkl/core/ModuleSchema.java b/pkl-core/src/main/java/org/pkl/core/ModuleSchema.java index 7c9215248..b7f67b407 100644 --- a/pkl-core/src/main/java/org/pkl/core/ModuleSchema.java +++ b/pkl-core/src/main/java/org/pkl/core/ModuleSchema.java @@ -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 typeAliases; private final Map imports; - @LateInit private Map __allClasses; - @LateInit private Map __allTypeAliases; + private @Nullable Map __allClasses; + private @Nullable Map __allTypeAliases; /** Constructs a {@code ModuleSchema} instance. */ public ModuleSchema( diff --git a/pkl-core/src/main/java/org/pkl/core/PcfRenderer.java b/pkl-core/src/main/java/org/pkl/core/PcfRenderer.java index 0f1aa9937..9f80e926c 100644 --- a/pkl-core/src/main/java/org/pkl/core/PcfRenderer.java +++ b/pkl-core/src/main/java/org/pkl/core/PcfRenderer.java @@ -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 { diff --git a/pkl-core/src/main/java/org/pkl/core/PklBinaryDecoder.java b/pkl-core/src/main/java/org/pkl/core/PklBinaryDecoder.java index bd798d554..9a0e095b2 100644 --- a/pkl-core/src/main/java/org/pkl/core/PklBinaryDecoder.java +++ b/pkl-core/src/main/java/org/pkl/core/PklBinaryDecoder.java @@ -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()); diff --git a/pkl-core/src/main/java/org/pkl/core/PropertiesRenderer.java b/pkl-core/src/main/java/org/pkl/core/PropertiesRenderer.java index 52e29d0fd..163c0ce34 100644 --- a/pkl-core/src/main/java/org/pkl/core/PropertiesRenderer.java +++ b/pkl-core/src/main/java/org/pkl/core/PropertiesRenderer.java @@ -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( diff --git a/pkl-core/src/main/java/org/pkl/core/TypeParameter.java b/pkl-core/src/main/java/org/pkl/core/TypeParameter.java index 7fac7c118..019141069 100644 --- a/pkl-core/src/main/java/org/pkl/core/TypeParameter.java +++ b/pkl-core/src/main/java/org/pkl/core/TypeParameter.java @@ -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; } diff --git a/pkl-core/src/main/java/org/pkl/core/Version.java b/pkl-core/src/main/java/org/pkl/core/Version.java index d5b067704..c2b61bfb2 100644 --- a/pkl-core/src/main/java/org/pkl/core/Version.java +++ b/pkl-core/src/main/java/org/pkl/core/Version.java @@ -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 semantic version. @@ -59,7 +58,7 @@ public final class Version implements Comparable { 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 { : new Identifier(-1, str)) .toArray(Identifier[]::new); } + //noinspection DataFlowIssue return __preReleaseIdentifiers; } diff --git a/pkl-core/src/main/java/org/pkl/core/ast/expression/literal/BytesLiteralNode.java b/pkl-core/src/main/java/org/pkl/core/ast/expression/literal/BytesLiteralNode.java index 698cd04f3..8aa78ff08 100644 --- a/pkl-core/src/main/java/org/pkl/core/ast/expression/literal/BytesLiteralNode.java +++ b/pkl-core/src/main/java/org/pkl/core/ast/expression/literal/BytesLiteralNode.java @@ -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); diff --git a/pkl-core/src/main/java/org/pkl/core/ast/expression/member/AbstractInvokeMethodLexicalNode.java b/pkl-core/src/main/java/org/pkl/core/ast/expression/member/AbstractInvokeMethodLexicalNode.java index def29a31e..5eaabbae4 100644 --- a/pkl-core/src/main/java/org/pkl/core/ast/expression/member/AbstractInvokeMethodLexicalNode.java +++ b/pkl-core/src/main/java/org/pkl/core/ast/expression/member/AbstractInvokeMethodLexicalNode.java @@ -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; } } diff --git a/pkl-core/src/main/java/org/pkl/core/ast/expression/member/InferParentWithinMethodNode.java b/pkl-core/src/main/java/org/pkl/core/ast/expression/member/InferParentWithinMethodNode.java index af9f55058..c886236e5 100644 --- a/pkl-core/src/main/java/org/pkl/core/ast/expression/member/InferParentWithinMethodNode.java +++ b/pkl-core/src/main/java/org/pkl/core/ast/expression/member/InferParentWithinMethodNode.java @@ -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(); diff --git a/pkl-core/src/main/java/org/pkl/core/ast/expression/member/InferParentWithinObjectMethodNode.java b/pkl-core/src/main/java/org/pkl/core/ast/expression/member/InferParentWithinObjectMethodNode.java index fe18aa5ea..f9a241a8c 100644 --- a/pkl-core/src/main/java/org/pkl/core/ast/expression/member/InferParentWithinObjectMethodNode.java +++ b/pkl-core/src/main/java/org/pkl/core/ast/expression/member/InferParentWithinObjectMethodNode.java @@ -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); diff --git a/pkl-core/src/main/java/org/pkl/core/ast/expression/member/ReadAmbiguousLocalityPropertyNode.java b/pkl-core/src/main/java/org/pkl/core/ast/expression/member/ReadAmbiguousLocalityPropertyNode.java index 4fae4b0ae..e51d82cdc 100644 --- a/pkl-core/src/main/java/org/pkl/core/ast/expression/member/ReadAmbiguousLocalityPropertyNode.java +++ b/pkl-core/src/main/java/org/pkl/core/ast/expression/member/ReadAmbiguousLocalityPropertyNode.java @@ -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) { diff --git a/pkl-core/src/main/java/org/pkl/core/ast/expression/member/ReadLocalPropertyNode.java b/pkl-core/src/main/java/org/pkl/core/ast/expression/member/ReadLocalPropertyNode.java index a7d2fe658..9cfa4e1cd 100644 --- a/pkl-core/src/main/java/org/pkl/core/ast/expression/member/ReadLocalPropertyNode.java +++ b/pkl-core/src/main/java/org/pkl/core/ast/expression/member/ReadLocalPropertyNode.java @@ -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; } } diff --git a/pkl-core/src/main/java/org/pkl/core/ast/expression/unary/ImportGlobNode.java b/pkl-core/src/main/java/org/pkl/core/ast/expression/unary/ImportGlobNode.java index 7fe41bc5c..fc76b16a2 100644 --- a/pkl-core/src/main/java/org/pkl/core/ast/expression/unary/ImportGlobNode.java +++ b/pkl-core/src/main/java/org/pkl/core/ast/expression/unary/ImportGlobNode.java @@ -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, diff --git a/pkl-core/src/main/java/org/pkl/core/ast/expression/unary/ImportNode.java b/pkl-core/src/main/java/org/pkl/core/ast/expression/unary/ImportNode.java index 0622f7e1c..3f6786be1 100644 --- a/pkl-core/src/main/java/org/pkl/core/ast/expression/unary/ImportNode.java +++ b/pkl-core/src/main/java/org/pkl/core/ast/expression/unary/ImportNode.java @@ -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, diff --git a/pkl-core/src/main/java/org/pkl/core/ast/expression/unary/ReadGlobNode.java b/pkl-core/src/main/java/org/pkl/core/ast/expression/unary/ReadGlobNode.java index 6c9f15223..645f73fec 100644 --- a/pkl-core/src/main/java/org/pkl/core/ast/expression/unary/ReadGlobNode.java +++ b/pkl-core/src/main/java/org/pkl/core/ast/expression/unary/ReadGlobNode.java @@ -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 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) diff --git a/pkl-core/src/main/java/org/pkl/core/ast/member/ClassMethod.java b/pkl-core/src/main/java/org/pkl/core/ast/member/ClassMethod.java index 9cfa622db..fb236f4e6 100644 --- a/pkl-core/src/main/java/org/pkl/core/ast/member/ClassMethod.java +++ b/pkl-core/src/main/java/org/pkl/core/ast/member/ClassMethod.java @@ -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 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; } diff --git a/pkl-core/src/main/java/org/pkl/core/ast/member/ClassNode.java b/pkl-core/src/main/java/org/pkl/core/ast/member/ClassNode.java index 9302105fa..79a6f4cb3 100644 --- a/pkl-core/src/main/java/org/pkl/core/ast/member/ClassNode.java +++ b/pkl-core/src/main/java/org/pkl/core/ast/member/ClassNode.java @@ -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(); diff --git a/pkl-core/src/main/java/org/pkl/core/ast/member/ListingOrMappingTypeCastNode.java b/pkl-core/src/main/java/org/pkl/core/ast/member/ListingOrMappingTypeCastNode.java index 61df46b35..21de62431 100644 --- a/pkl-core/src/main/java/org/pkl/core/ast/member/ListingOrMappingTypeCastNode.java +++ b/pkl-core/src/main/java/org/pkl/core/ast/member/ListingOrMappingTypeCastNode.java @@ -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; } diff --git a/pkl-core/src/main/java/org/pkl/core/ast/member/LocalTypedPropertyNode.java b/pkl-core/src/main/java/org/pkl/core/ast/member/LocalTypedPropertyNode.java index f6bde413b..381ba61ba 100644 --- a/pkl-core/src/main/java/org/pkl/core/ast/member/LocalTypedPropertyNode.java +++ b/pkl-core/src/main/java/org/pkl/core/ast/member/LocalTypedPropertyNode.java @@ -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; } diff --git a/pkl-core/src/main/java/org/pkl/core/ast/member/ObjectMethodNode.java b/pkl-core/src/main/java/org/pkl/core/ast/member/ObjectMethodNode.java index a2b9808a4..e45bb4b99 100644 --- a/pkl-core/src/main/java/org/pkl/core/ast/member/ObjectMethodNode.java +++ b/pkl-core/src/main/java/org/pkl/core/ast/member/ObjectMethodNode.java @@ -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, diff --git a/pkl-core/src/main/java/org/pkl/core/ast/type/GetParentForTypeNode.java b/pkl-core/src/main/java/org/pkl/core/ast/type/GetParentForTypeNode.java index cb3bd9b13..20021a4ab 100644 --- a/pkl-core/src/main/java/org/pkl/core/ast/type/GetParentForTypeNode.java +++ b/pkl-core/src/main/java/org/pkl/core/ast/type/GetParentForTypeNode.java @@ -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 `` to the type's default value in `new { ... }`. */ 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(); diff --git a/pkl-core/src/main/java/org/pkl/core/ast/type/TypeCastNode.java b/pkl-core/src/main/java/org/pkl/core/ast/type/TypeCastNode.java index 968d2826b..faaffa483 100644 --- a/pkl-core/src/main/java/org/pkl/core/ast/type/TypeCastNode.java +++ b/pkl-core/src/main/java/org/pkl/core/ast/type/TypeCastNode.java @@ -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; } diff --git a/pkl-core/src/main/java/org/pkl/core/ast/type/TypeNode.java b/pkl-core/src/main/java/org/pkl/core/ast/type/TypeNode.java index 455f5bf68..4b614d3d8 100644 --- a/pkl-core/src/main/java/org/pkl/core/ast/type/TypeNode.java +++ b/pkl-core/src/main/java/org/pkl/core/ast/type/TypeNode.java @@ -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); diff --git a/pkl-core/src/main/java/org/pkl/core/ast/type/TypeTestNode.java b/pkl-core/src/main/java/org/pkl/core/ast/type/TypeTestNode.java index a7c95836b..fdc993a6e 100644 --- a/pkl-core/src/main/java/org/pkl/core/ast/type/TypeTestNode.java +++ b/pkl-core/src/main/java/org/pkl/core/ast/type/TypeTestNode.java @@ -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; } diff --git a/pkl-core/src/main/java/org/pkl/core/externalreader/ExternalResourceResolverImpl.java b/pkl-core/src/main/java/org/pkl/core/externalreader/ExternalResourceResolverImpl.java index 96fd27d22..c0d969b2c 100644 --- a/pkl-core/src/main/java/org/pkl/core/externalreader/ExternalResourceResolverImpl.java +++ b/pkl-core/src/main/java/org/pkl/core/externalreader/ExternalResourceResolverImpl.java @@ -103,7 +103,7 @@ final class ExternalResourceResolverImpl implements ExternalResourceResolver { readResponses.computeIfAbsent( baseUri, (uri) -> { - var future = new CompletableFuture(); + var future = new CompletableFuture(); var request = new ReadResourceRequest(requestIdGenerator.nextLong(), evaluatorId, uri); try { diff --git a/pkl-core/src/main/java/org/pkl/core/http/JdkHttpClient.java b/pkl-core/src/main/java/org/pkl/core/http/JdkHttpClient.java index 9dc4d2af5..28b49e401 100644 --- a/pkl-core/src/main/java/org/pkl/core/http/JdkHttpClient.java +++ b/pkl-core/src/main/java/org/pkl/core/http/JdkHttpClient.java @@ -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 responseBodyHandler, HttpRequestChecker httpRequestChecker) - throws IOException, SecurityManagerException { + throws IOException { try { return underlying.send(request, responseBodyHandler); } catch (ConnectException e) { diff --git a/pkl-core/src/main/java/org/pkl/core/messaging/Messages.java b/pkl-core/src/main/java/org/pkl/core/messaging/Messages.java index dc78a05da..9607d548f 100644 --- a/pkl-core/src/main/java/org/pkl/core/messaging/Messages.java +++ b/pkl-core/src/main/java/org/pkl/core/messaging/Messages.java @@ -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; } diff --git a/pkl-core/src/main/java/org/pkl/core/module/PathElement.java b/pkl-core/src/main/java/org/pkl/core/module/PathElement.java index 41b181efd..31dd8d471 100644 --- a/pkl-core/src/main/java/org/pkl/core/module/PathElement.java +++ b/pkl-core/src/main/java/org/pkl/core/module/PathElement.java @@ -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; } diff --git a/pkl-core/src/main/java/org/pkl/core/module/ProjectDependenciesManager.java b/pkl-core/src/main/java/org/pkl/core/module/ProjectDependenciesManager.java index 913524f73..3b9e3c2bf 100644 --- a/pkl-core/src/main/java/org/pkl/core/module/ProjectDependenciesManager.java +++ b/pkl-core/src/main/java/org/pkl/core/module/ProjectDependenciesManager.java @@ -183,6 +183,7 @@ public final class ProjectDependenciesManager { public Map getLocalPackageDependencies(PackageUri packageUri) { ensureDependenciesInitialized(); var dep = localPackageDependencies.get(packageUri); + //noinspection ConstantValue assert dep != null; return dep; } diff --git a/pkl-core/src/main/java/org/pkl/core/packages/Dependency.java b/pkl-core/src/main/java/org/pkl/core/packages/Dependency.java index e55a57b9c..d4ac8f0b4 100644 --- a/pkl-core/src/main/java/org/pkl/core/packages/Dependency.java +++ b/pkl-core/src/main/java/org/pkl/core/packages/Dependency.java @@ -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; } diff --git a/pkl-core/src/main/java/org/pkl/core/packages/DependencyMetadata.java b/pkl-core/src/main/java/org/pkl/core/packages/DependencyMetadata.java index 2847d8e11..681103ca5 100644 --- a/pkl-core/src/main/java/org/pkl/core/packages/DependencyMetadata.java +++ b/pkl-core/src/main/java/org/pkl/core/packages/DependencyMetadata.java @@ -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(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); diff --git a/pkl-core/src/main/java/org/pkl/core/packages/PackageAssetUri.java b/pkl-core/src/main/java/org/pkl/core/packages/PackageAssetUri.java index 3df58cbba..d58963489 100644 --- a/pkl-core/src/main/java/org/pkl/core/packages/PackageAssetUri.java +++ b/pkl-core/src/main/java/org/pkl/core/packages/PackageAssetUri.java @@ -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; } diff --git a/pkl-core/src/main/java/org/pkl/core/packages/PackageUri.java b/pkl-core/src/main/java/org/pkl/core/packages/PackageUri.java index c860c6dc0..6f9fa0df1 100644 --- a/pkl-core/src/main/java/org/pkl/core/packages/PackageUri.java +++ b/pkl-core/src/main/java/org/pkl/core/packages/PackageUri.java @@ -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; } diff --git a/pkl-core/src/main/java/org/pkl/core/project/CanonicalPackageUri.java b/pkl-core/src/main/java/org/pkl/core/project/CanonicalPackageUri.java index adc96f21c..0f088c6d9 100644 --- a/pkl-core/src/main/java/org/pkl/core/project/CanonicalPackageUri.java +++ b/pkl-core/src/main/java/org/pkl/core/project/CanonicalPackageUri.java @@ -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; } diff --git a/pkl-core/src/main/java/org/pkl/core/project/Project.java b/pkl-core/src/main/java/org/pkl/core/project/Project.java index 992143468..0c66dd39f 100644 --- a/pkl-core/src/main/java/org/pkl/core/project/Project.java +++ b/pkl-core/src/main/java/org/pkl/core/project/Project.java @@ -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; } diff --git a/pkl-core/src/main/java/org/pkl/core/project/ProjectDependenciesResolver.java b/pkl-core/src/main/java/org/pkl/core/project/ProjectDependenciesResolver.java index a2c9922c9..7cd409cd9 100644 --- a/pkl-core/src/main/java/org/pkl/core/project/ProjectDependenciesResolver.java +++ b/pkl-core/src/main/java/org/pkl/core/project/ProjectDependenciesResolver.java @@ -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); diff --git a/pkl-core/src/main/java/org/pkl/core/project/ProjectDeps.java b/pkl-core/src/main/java/org/pkl/core/project/ProjectDeps.java index 1db8b7605..35259a7c8 100644 --- a/pkl-core/src/main/java/org/pkl/core/project/ProjectDeps.java +++ b/pkl-core/src/main/java/org/pkl/core/project/ProjectDeps.java @@ -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; } diff --git a/pkl-core/src/main/java/org/pkl/core/runtime/FileSystemManager.java b/pkl-core/src/main/java/org/pkl/core/runtime/FileSystemManager.java index d272fdf8a..b40516f2b 100644 --- a/pkl-core/src/main/java/org/pkl/core/runtime/FileSystemManager.java +++ b/pkl-core/src/main/java/org/pkl/core/runtime/FileSystemManager.java @@ -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; diff --git a/pkl-core/src/main/java/org/pkl/core/runtime/ModuleInfo.java b/pkl-core/src/main/java/org/pkl/core/runtime/ModuleInfo.java index 988fb5284..92004272b 100644 --- a/pkl-core/src/main/java/org/pkl/core/runtime/ModuleInfo.java +++ b/pkl-core/src/main/java/org/pkl/core/runtime/ModuleInfo.java @@ -40,10 +40,10 @@ public final class ModuleInfo { @LateInit private List 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 annotations) { + //noinspection ConstantValue assert this.annotations == null; this.annotations = annotations; } public List getAnnotations() { - assert annotations != null; return annotations; } diff --git a/pkl-core/src/main/java/org/pkl/core/runtime/StackTraceRenderer.java b/pkl-core/src/main/java/org/pkl/core/runtime/StackTraceRenderer.java index 189575050..b13c8dea4 100644 --- a/pkl-core/src/main/java/org/pkl/core/runtime/StackTraceRenderer.java +++ b/pkl-core/src/main/java/org/pkl/core/runtime/StackTraceRenderer.java @@ -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'); } diff --git a/pkl-core/src/main/java/org/pkl/core/runtime/TestRunner.java b/pkl-core/src/main/java/org/pkl/core/runtime/TestRunner.java index e874d8044..bee4b5532 100644 --- a/pkl-core/src/main/java/org/pkl/core/runtime/TestRunner.java +++ b/pkl-core/src/main/java/org/pkl/core/runtime/TestRunner.java @@ -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()); } diff --git a/pkl-core/src/main/java/org/pkl/core/runtime/VmContext.java b/pkl-core/src/main/java/org/pkl/core/runtime/VmContext.java index 0a90d026f..e267e5aeb 100644 --- a/pkl-core/src/main/java/org/pkl/core/runtime/VmContext.java +++ b/pkl-core/src/main/java/org/pkl/core/runtime/VmContext.java @@ -107,6 +107,7 @@ public final class VmContext { } public void initialize(Holder holder) { + //noinspection ConstantValue assert this.holder == null; this.holder = holder; } diff --git a/pkl-core/src/main/java/org/pkl/core/runtime/VmDynamic.java b/pkl-core/src/main/java/org/pkl/core/runtime/VmDynamic.java index a3dbb6be4..9d352dd26 100644 --- a/pkl-core/src/main/java/org/pkl/core/runtime/VmDynamic.java +++ b/pkl-core/src/main/java/org/pkl/core/runtime/VmDynamic.java @@ -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.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(); } diff --git a/pkl-core/src/main/java/org/pkl/core/runtime/VmListing.java b/pkl-core/src/main/java/org/pkl/core/runtime/VmListing.java index c0af13c08..500f53388 100644 --- a/pkl-core/src/main/java/org/pkl/core/runtime/VmListing.java +++ b/pkl-core/src/main/java/org/pkl/core/runtime/VmListing.java @@ -87,13 +87,15 @@ public final class VmListing extends VmListingOrMapping { @Override @TruffleBoundary public List 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(); } diff --git a/pkl-core/src/main/java/org/pkl/core/runtime/VmMap.java b/pkl-core/src/main/java/org/pkl/core/runtime/VmMap.java index 7ad2de57f..5721114f4 100644 --- a/pkl-core/src/main/java/org/pkl/core/runtime/VmMap.java +++ b/pkl-core/src/main/java/org/pkl/core/runtime/VmMap.java @@ -147,6 +147,7 @@ public final class VmMap extends VmValue implements Iterable 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(); } diff --git a/pkl-core/src/main/java/org/pkl/core/runtime/VmObject.java b/pkl-core/src/main/java/org/pkl/core/runtime/VmObject.java index 73633bef8..367ef47ff 100644 --- a/pkl-core/src/main/java/org/pkl/core/runtime/VmObject.java +++ b/pkl-core/src/main/java/org/pkl/core/runtime/VmObject.java @@ -34,7 +34,7 @@ public abstract class VmObject extends VmObjectLike { protected final EconomicMap 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. + * + *

Assumes that this object has already been forced. */ @TruffleBoundary protected final Map exportMembers() { - var result = CollectionUtils.newLinkedHashMap(EconomicMaps.size(cachedValues)); + Map 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; }); diff --git a/pkl-core/src/main/java/org/pkl/core/runtime/VmReference.java b/pkl-core/src/main/java/org/pkl/core/runtime/VmReference.java index 6dfd78c7b..853a8f248 100644 --- a/pkl-core/src/main/java/org/pkl/core/runtime/VmReference.java +++ b/pkl-core/src/main/java/org/pkl/core/runtime/VmReference.java @@ -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 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); diff --git a/pkl-core/src/main/java/org/pkl/core/runtime/VmTypeAlias.java b/pkl-core/src/main/java/org/pkl/core/runtime/VmTypeAlias.java index 03480827a..208b042bd 100644 --- a/pkl-core/src/main/java/org/pkl/core/runtime/VmTypeAlias.java +++ b/pkl-core/src/main/java/org/pkl/core/runtime/VmTypeAlias.java @@ -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 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(); } diff --git a/pkl-core/src/main/java/org/pkl/core/runtime/VmTyped.java b/pkl-core/src/main/java/org/pkl/core/runtime/VmTyped.java index e01741c37..e83c14c72 100644 --- a/pkl-core/src/main/java/org/pkl/core/runtime/VmTyped.java +++ b/pkl-core/src/main/java/org/pkl/core/runtime/VmTyped.java @@ -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; diff --git a/pkl-core/src/main/java/org/pkl/core/stdlib/VmObjectFactory.java b/pkl-core/src/main/java/org/pkl/core/stdlib/VmObjectFactory.java index e5d4c1d64..377a86709 100644 --- a/pkl-core/src/main/java/org/pkl/core/stdlib/VmObjectFactory.java +++ b/pkl-core/src/main/java/org/pkl/core/stdlib/VmObjectFactory.java @@ -94,6 +94,7 @@ public final class VmObjectFactory { ? 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 { @TruffleBoundary public VmTyped create(@Nullable E extraStorage) { var clazz = classSupplier.get(); - assert clazz != null; var result = new VmTyped(VmUtils.createEmptyMaterializedFrame(), clazz.getPrototype(), clazz, members); diff --git a/pkl-core/src/main/java/org/pkl/core/stdlib/base/BaseNodes.java b/pkl-core/src/main/java/org/pkl/core/stdlib/base/BaseNodes.java index 84cb28af7..55baa45fb 100644 --- a/pkl-core/src/main/java/org/pkl/core/stdlib/base/BaseNodes.java +++ b/pkl-core/src/main/java/org/pkl/core/stdlib/base/BaseNodes.java @@ -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)") diff --git a/pkl-core/src/main/java/org/pkl/core/stdlib/base/ListNodes.java b/pkl-core/src/main/java/org/pkl/core/stdlib/base/ListNodes.java index af33801b4..c4093fc13 100644 --- a/pkl-core/src/main/java/org/pkl/core/stdlib/base/ListNodes.java +++ b/pkl-core/src/main/java/org/pkl/core/stdlib/base/ListNodes.java @@ -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) { diff --git a/pkl-core/src/main/java/org/pkl/core/stdlib/json/ParserNodes.java b/pkl-core/src/main/java/org/pkl/core/stdlib/json/ParserNodes.java index 2ef74b24a..d7fbfb6a0 100644 --- a/pkl-core/src/main/java/org/pkl/core/stdlib/json/ParserNodes.java +++ b/pkl-core/src/main/java/org/pkl/core/stdlib/json/ParserNodes.java @@ -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 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(); diff --git a/pkl-core/src/main/java/org/pkl/core/stdlib/protobuf/RendererNodes.java b/pkl-core/src/main/java/org/pkl/core/stdlib/protobuf/RendererNodes.java index ad1868270..82c6274a6 100644 --- a/pkl-core/src/main/java/org/pkl/core/stdlib/protobuf/RendererNodes.java +++ b/pkl-core/src/main/java/org/pkl/core/stdlib/protobuf/RendererNodes.java @@ -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(); + var elements = new ArrayList<@Nullable TypeNode>(); for (var t : ((UnionTypeNode) type).getElementTypeNodes()) { var resolved = resolveType(t); if (resolved instanceof StringLiteralTypeNode || resolved instanceof StringTypeNode) { diff --git a/pkl-core/src/main/java/org/pkl/core/stdlib/test/report/JUnitReporter.java b/pkl-core/src/main/java/org/pkl/core/stdlib/test/report/JUnitReporter.java index 3a1169ae6..777726ba9 100644 --- a/pkl-core/src/main/java/org/pkl/core/stdlib/test/report/JUnitReporter.java +++ b/pkl-core/src/main/java/org/pkl/core/stdlib/test/report/JUnitReporter.java @@ -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 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); diff --git a/pkl-core/src/main/java/org/pkl/core/util/CollectionUtils.java b/pkl-core/src/main/java/org/pkl/core/util/CollectionUtils.java index 1d69e6be5..879072dd8 100644 --- a/pkl-core/src/main/java/org/pkl/core/util/CollectionUtils.java +++ b/pkl-core/src/main/java/org/pkl/core/util/CollectionUtils.java @@ -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 LinkedHashMap newLinkedHashMap(int expectedSize) { + public static + LinkedHashMap newLinkedHashMap(int expectedSize) { return new LinkedHashMap<>((int) (expectedSize / LOAD_FACTOR) + 1, LOAD_FACTOR); } diff --git a/pkl-core/src/main/java/org/pkl/core/util/EconomicMaps.java b/pkl-core/src/main/java/org/pkl/core/util/EconomicMaps.java index 6e191d139..7410714cd 100644 --- a/pkl-core/src/main/java/org/pkl/core/util/EconomicMaps.java +++ b/pkl-core/src/main/java/org/pkl/core/util/EconomicMaps.java @@ -81,11 +81,13 @@ public final class EconomicMaps { return result; } + @SuppressWarnings("DataFlowIssue") @TruffleBoundary public static @Nullable V get(UnmodifiableEconomicMap self, K key) { return self.get(key); } + @SuppressWarnings("DataFlowIssue") @TruffleBoundary public static @Nullable V get(UnmodifiableEconomicMap self, K key, V defaultValue) { return self.get(key, defaultValue); diff --git a/pkl-core/src/main/java/org/pkl/core/util/json/JsonParser.java b/pkl-core/src/main/java/org/pkl/core/util/json/JsonParser.java index 67f35ca51..b7e186ded 100644 --- a/pkl-core/src/main/java/org/pkl/core/util/json/JsonParser.java +++ b/pkl-core/src/main/java/org/pkl/core/util/json/JsonParser.java @@ -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(); } diff --git a/pkl-core/src/main/java/org/pkl/core/util/json/JsonWriter.java b/pkl-core/src/main/java/org/pkl/core/util/json/JsonWriter.java index d523be448..ed374255f 100644 --- a/pkl-core/src/main/java/org/pkl/core/util/json/JsonWriter.java +++ b/pkl-core/src/main/java/org/pkl/core/util/json/JsonWriter.java @@ -25,7 +25,7 @@ import org.jspecify.annotations.Nullable; /** * Writes a JSON (RFC 7159) 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. * *

Encoding JSON

* @@ -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; } diff --git a/pkl-core/src/main/java/org/pkl/core/util/paguro/RrbTree.java b/pkl-core/src/main/java/org/pkl/core/util/paguro/RrbTree.java index ca81478cf..744a19dad 100644 --- a/pkl-core/src/main/java/org/pkl/core/util/paguro/RrbTree.java +++ b/pkl-core/src/main/java/org/pkl/core/util/paguro/RrbTree.java @@ -922,7 +922,10 @@ public abstract class RrbTree implements BaseList, 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; }