Commit Graph

189 Commits

Author SHA1 Message Date
Islon Scherer bfac0d66ed Reject relative package URIs (#1683) 2026-06-17 15:39:03 +02:00
Aditya Singh a9c98e4396 Fix incorrect Facts in pkl:base doc comments (#1669)
Several `Facts:` examples in the `pkl:base` standard library docs assert
statements that are false when evaluated. Since these examples are not
run by any test, the mistakes went unnoticed and are rendered verbatim
into the generated API docs, where they mislead readers.

The corrected examples:

- `String.isNotBlank`: `"\t\n\r".isNotBlank` was listed as holding, but
a string of only whitespace is blank, so it is false. Negated it to
match the neighboring `!"".isNotBlank` and `!" ".isNotBlank` examples.
- `DataSize.toBinaryUnit` / `toDecimalUnit`: the `mb`/`mib` lines
mirrored the `kb`/`kib` lines, but the identity only holds for adjacent
units. `1024.kb == 1000.kib` (both 1,024,000 b), whereas `1024.mb` is
1,024,000,000 b and `1000.mib` is 1,048,576,000 b, so they are not
equal. There is no clean round-number equivalent at this magnitude, so I
removed the two false lines; the remaining examples still demonstrate
the conversion.
- `Collection.any`: `!List(1, 2, 3).any((n) -> n.isEven)` is false
because 2 is even. Changed the list to `List(1, 3, 5)` so the negation
holds.
- `IntSeq.end`: the example read `IntSeq(2, 5).start == 5`, which
documents the wrong property and is false (`start` is 2). Corrected it
to `IntSeq(2, 5).end == 5`.
- `List.isDistinctBy` / `distinctBy`: `List("a", "b", "abc")` is not
distinct by length, since `"a"` and `"b"` both have length 1. Switched
to `List("a", "bb", "ccc")` so the distinctness examples hold.
- `Map`: `Map(...).values` returns a `List`, not a `Set`. Corrected the
expected type.

I verified that each corrected example evaluates to `true`, and that the
neighboring examples I kept still pass, using the released Pkl 0.31.1
binary. The changes are confined to doc-comment text, so formatting is
unaffected.

---------

Signed-off-by: Aditya Singh <adisin650@gmail.com>
2026-06-11 17:10:14 +00:00
Daniel Chao 84d2c32d10 Improve handling of frame slots (#1634)
This makes various improvements to the handling of frame slot vars, and
includes some bug fixes introduced by
https://github.com/apple/pkl/pull/1622

* Refactor SymbolTable to track for-generator and parameter slots in
each scope
* Execute let expressions in their own root node in some places
* Unify how frame slots are managed; they are all represented as
`FrameSlotVariable`, created in `AstBuilder`, and passed into
`SymbolTable`.
* Fix how let expressions are executed in custom this scopes (introduce
a new root node when needed)
2026-06-11 03:02:42 +00:00
Daniel Chao 27fe06c796 Fix errors around strings with lone high or low surrogates (#1673)
This fixes some errors around treatment of strings with lone high/low
surrogates.
2026-06-10 08:35:22 -07:00
Daniel Chao 1a1e1cfea9 Fix String.padStart/padEnd (#1672)
Fixes the following two bugs:

* Pads to incorrect string length
* Does not append full code point
2026-06-10 08:34:50 -07:00
Vinayak Joshi ce0383837a Reject abstract members in non-abstract classes (#1647)
Fixes #1614.

## Context

A non-abstract `class` (or `module`) was allowed to declare `abstract`
properties and methods.
Because such an enclosing type is instantiable, an `abstract` member
there can never be guaranteed
an implementation — so the contradiction surfaced only as a runtime
error when the member was
accessed (`Cannot invoke abstract method`), or not at all.

This makes it a compile-time error to declare an `abstract` member
unless its enclosing class or
module is also `abstract`. This is consistent with how Pkl already
rejects instantiating an abstract
class, and mirrors how Java and Kotlin treat abstract members.

## Before

```pkl
class Foo {
  abstract bar: Int
}
res = new Foo { bar = 5 }   // evaluated successfully (should fail)
```

```pkl
class Foo {
  abstract function bar(): Int
}
res = new Foo {}            // evaluated successfully; res.bar() failed only at runtime
```

## After

```
–– Pkl Error ––
Cannot define an abstract member in a non-abstract class.

2 | abstract bar: Int
    ^^^^^^^^
at Foo

A member can only be `abstract` if its enclosing class is also `abstract`.
```

## Implementation

- `AstBuilder` now validates, while building the AST, that a
non-abstract class/module declares no
`abstract` members. The check runs in both `visitClass` and
`visitModule`, and the error points at
  the `abstract` keyword.
- Adds the `abstractMemberInNonAbstractClass` error message.

## Scope: classes and modules

The issue describes classes; I applied the same rule to modules as well,
since a module is a class
in Pkl and a non-abstract module is likewise directly evaluatable. Happy
to narrow this to classes
only if you'd prefer — it's a one-line change either way.

The `moduleMethodModifiers` pkl-doc test fixture declared an abstract
method at non-abstract module
level (relying on the old behavior); it's updated to an `abstract
module`, and its expected
documentation output is regenerated.

## Tests

- New `LanguageSnippetTests` error cases: abstract property in a class,
abstract method in a class,
  and abstract member in a module.
- `./gradlew build` passes (`pkl-core` and `pkl-doc` included).

---------

Co-authored-by: Vinayak <vinayak@vama.app>
Co-authored-by: Daniel Chao <daniel.h.chao@gmail.com>
2026-06-10 10:36:40 +02:00
Daniel Chao 391329c1fa Fix test (#1667)
The previous PR (https://github.com/apple/pkl/pull/1637) got auto-merged
by mistake; there's a failing test here
2026-06-08 16:11:49 -05:00
Daniel Chao d012285f7d Improve HTTP redirect following (#1637)
This implements HTTP redirect following ourselves.

The goal is:

1. All I/O is checked against `--allowed-resources` and
`--allowed-modules`, including HTTP redirects
2. HTTP rewrite rules can affect redirect following
3. HTTP headers can affect redirect following

---------

Co-authored-by: Islon Scherer <islonscherer@gmail.com>
2026-06-08 18:13:48 +00:00
Daniel Chao 01f8fcae7b Catch correct exception type in MultiplicationNode (#1652)
Closes #1651
2026-06-05 12:55:27 -07:00
Daniel Chao 41e012a0f0 Fix toRadixString on math.minInt (#1656)
Closes #1655
2026-06-05 18:27:03 +00:00
Daniel Chao aa01241068 Fix eager typecheck of Map (#1654)
Closes #1653
2026-06-05 11:24:00 -07:00
Jen Basch 74eae0388e Fix error rendering @ConvertProperty annotations during error reporting (#1648)
The added snippet test originally produced error "A value of type
`Function2` cannot be exported."

This PR actually fixes the bug twice:
* By marking `ConvertProperty.render` as `hidden` so that it is skipped
when the enclosing object is exported. This broke any attempts to obtain
the module schema because this requires exporting all annotations on all
class properties.
* By changing the way that `VmUndefinedValueException.fillInHint()`
obtains the module URI to avoid obtaining the module schema (and
triggering the more expensive module schema generation process).

It also makes function-typed annotation properties in `pkl:Command` hidden to avoid similar issues there.
2026-06-05 16:50:34 +00:00
Jen Basch 68f7d06eed Improve error message when parsing truncated let expressions (#1639)
This previously yielded
```
Unexpected token `}`. Expected `}`.
```
Pretty confusing, no?

Now it's just
```
Unexpected token `}`.
```

Resolves #1638
2026-06-02 16:00:46 -07:00
Daniel Chao 035ef0a789 Change loading of external readers (#1394)
This introduces breaking changes for external readers are loaded:

1. In PklProject, relative paths are resolved relative to the enclosing
PklProject file (make behavior consistent with how other settings work)
2. Make CLI flags blow away any settings set on a PklProject
3. Introduce a new `workingDir` property, which defaults to the
PklProject dir

The overall goal is to make this behavior consistent with how other
settings work.
For example, relative paths for other evaluator settings are already
relative to the project directory.
Additionally, in every other case, CLI flags will overwrite any setting
set within PklProject.
2026-06-02 18:02:52 +00:00
Daniel Chao c9f3823952 Touch ups around local members (#1633)
* Add assertion if ObjectMember key in cachedValues is not local (should never happen)
* Move test to snippet tests
2026-06-02 03:47:46 +00:00
Jen Basch 18af04c2ec Correctly count regular members of Dynamic (#1632)
Previously, `VmDynamic.isHiddenOrLocalProperty` didn't correctly
identify locals whose cache key is an `ObjectMember` instead of an
`Identifier`, causing `VmDynamic. getRegularMemberCount` to return an
incorrect value. This caused some renderers to produce incorrect output.

Resolves #1631
2026-06-01 20:27:19 -07:00
Daniel Chao 7dd2bc67de Optimize let expressions as frame slot vars (#1622)
This introduces an optimization to write let expressions to frame slots
of the current frame, rather than transforming them into lambdas. As a
result, let expressions are _much_ faster to execute.
2026-06-01 16:53:30 -07:00
Islon Scherer bfda4cc8c8 Fix forcing of VmValue during error rendering (#1629) 2026-06-01 18:25:33 +02:00
Islon Scherer dbf04f6598 Resolve variables at parse time (#1429)
This replaces `ResolveVariableNode` and `ResolveMethodNode` with their resolution.
When we build the truffle node tree, we determine whether names resolve to:

* lexical scope
* base module
* implicit this

Then, we use this information to directly construct the underlying nodes (`ReadPropertyNode`, `ReadLocalPropertyNode`, etc).

Additionally, `AstBuilder` determines whether the property access must be const or not.

This introduces a `BaseModuleMembers` registry, which gets generated as part of Java compilation.
2026-05-26 14:08:20 -07:00
Mirko Alicastro ff319faef3 Use Locale.ROOT when lowercasing rewrite URIs (#1618)
Use Locale.ROOT to apply the lowecase format. For URI scheme and host
locale-neutral casing is the semantically the correct choice. Added a
unit test that sets the default locale to tr-TR and that would fail
without the fix.
2026-05-26 09:37:42 -07:00
Daniel Chao b070d56741 Remove public modifier on LazyHttpClient and RequestRewritingClient (#1609)
This introduces a test helper to expose configured HTTP settings, and
makes the underlying classes package-private again.
2026-05-22 10:17:26 -07:00
Daniel Chao 8e2e5e4ba8 Improve HTTP headers logic (#1584)
* Relax forbidden headers constraints
  - remove restriction on browser-related headers
- allow any glob pattern (no need to end with `/` or `*`, because glob
patterns already require users to explicitly declare prefix matches if
that's the intention)
* Replace `List<Pair<, ...>>`; use `Map<String, ...>` instead
* Use glob pattern strings as an API throughout, instead of `Pattern`
(e.g. in `HttpClientBuilder`)
* Add HTTP headers to message passing API
* Add HTTP headers to executor API (introduces `ExecutorSpiOptions4`)
* Add tests for Gradle, CLI, and pkl-executor invocations
* Improve documentation
* Add `isGlobPattern` API to class `String` for in-language validation
of http headers
* Behavior change: make sure explicitly configured `User-Agent` in
`HttpClientBuilder` can be shadowed by headers (allows users to set
`--http-header "**=User-Agent: My User Agent"` and for this to be the
only user agent).

CC @kyokuping
2026-05-21 20:07:06 -07:00
odenix 3dc93cbd4a pkl-core: Migrate nullness to JSpecify (#1601)
Replace pkl-core's local nullness annotations with JSpecify annotations.
Enable NullAway checking for pkl-core packages except org.pkl.core.ast
and org.pkl.core.stdlib.

Notable code changes:
- Add a dedicated late-init constructor to VmTyped
- Move VmExceptionBuilder's fallback message derivation from withCause()
to build()
- Split VmException rendering between builder-provided messages and
string-backed messages
- Initialize MessageTransport handlers with default throwing handlers
- Update JSON helper collection types to allow nullable values JSON
arrays and objects can contain JSON null,
so the Java Map/List element types need to model nullable elements
explicitly
- Make public command transform APIs accept nullable transformed values 
   Command transforms can produce null for optional/default handling,
so the BiFunction and options-map element types now model that
explicitly
- Make ExecutorSpiException accept nullable message and cause 
Existing call sites can pass nullable causes from Throwable.getCause()
- Remove JSR-305 semantics from `@LateInit`
   JSpecify does not support the same type-qualifier-nickname pattern,
so `@LateInit` is now documentation plus a NullAway
constructor-initialization exemption

Out of scope:
- NullAway checking of org.pkl.core.ast and org.pkl.core.stdlib
- IntelliJ warnings related to `@LateInit` fields
- Removing the JSR-305 dependency, since concurrency annotations are
still in use
2026-05-21 13:57:20 -07:00
Islon Scherer 3fbcd463e0 Introduce "minimal" test reporter (#1563) 2026-05-19 17:20:26 +02:00
Daniel Chao a7a64acbac Improve handling of evaling dependency notation URIs (#1595) 2026-05-15 15:51:09 -07:00
Daniel Chao 3ad1cb3645 Ensure local dependency matches PklProject.dep.json version (#1594)
The version of local project dependencies should _always_ exactly match
up with what's declared in a PklProject.deps.json; any package in the
transitive dependency tree should always be delcaring the same import
too.

Closes #1591
2026-05-15 11:48:57 -07:00
Jeaeun Kim 14085c18bb Add support for customizing HTTP headers (#1196)
This PR adds support for custom HTTP headers, introducing a
`--http-header` CLI flag to accept `key=value` pairs. These headers can
also be specified within the `setting.pkl` file.

Closes #633

SPICE: https://github.com/apple/pkl-evolution/pull/24

---------

Co-authored-by: Jen Basch <jbasch94@gmail.com>
Co-authored-by: Islon Scherer <islonscherer@gmail.com>
2026-05-12 13:53:59 -07:00
Daniel Chao 38733e5781 Fix parsing of dependency notation URIs (#1570)
Fixes a thrown exception when path segments contain characters that
aren't URI safe (e.g. `import "@foo/bar baz.pkl"`).

Closes #1545
2026-05-07 13:00:52 -07:00
Jen Basch b7ba6a8649 Fix pkl:test fact power assertions when member source section is unavailable (#1571)
Power assertions only work when the source section is available. If it
is unavailable, power assertions throw a ParserError (unexpected EOF on
an empty input) when re-parsing the expression for presentation.
2026-05-04 12:25:15 -07:00
Daniel Chao 2b3603b544 Reformat Kotlin code (#1560)
ktfmt has much improved how it formats Kotlin code. Unfortunately, this
means that whenever we touch a single line in a Kotlin file, we get a
_lot_ more changes thanks to ratcheting now picking up this file for
formatting.

This PR just reformats every single Kotlin file so we don't have to deal
with this churn in future PRs that touch Kotlin code.
2026-04-25 06:14:44 -07:00
Jen Basch e07abb7311 SPICE-0028: Add support for multi-line string line continuations (#1507)
SPICE: https://github.com/apple/pkl-evolution/pull/31
2026-04-21 10:29:52 -07:00
Jen Basch eeb0970dc4 Fix bug where reusing a pklbinary#Renderer could result in incorrect output (#1525) 2026-04-15 23:12:36 -07:00
odenix 2d4286ee7b Upgrade JVM toolchain to 25 and Kotlin toolchain to 2.3.20 (#1516)
Motivation
- Enable correct NullAway analysis
- Pick up toolchain fixes and improvements

Toolchains
- Require JDK 25 for JVM toolchain (keep Java 17 runtime compatibility)
- Require Kotlin 2.3.20 for Kotlin toolchain (keep Kotlin 2.2 runtime
compatibility)
- Require JDK 25 for Gradle daemon JVM (via
gradle-daemon-jvm.properties)
- Fix javac and kotlinc warnings from toolchain upgrades

CI
- Bump GitHub workflows to JDK 25

Building Kotlin
- Bump Kotlin language level to 2.2 to match stdlib version
- Consolidate build logic into pklKotlinBase.gradle.kts
- Adopt modern Kotlin plugin syntax
- Fix new kotlinc warnings
- Update ktfmt to 0.62
  - first version compatible with Kotlin 2.3.20
  - changes formatting compared to 0.61
- Replace dependency resolution rule with BOM alignment
  - rule was too broad and interfered with toolchain/runtime separation

Testing
- Expand matrix to JDK 25 (LTS) and 26
- Ensure each matrix task can be run independently
- Fix KotlinCodeGeneratorsTest and EmbeddedExecutorsTest on affected
JDKs
- Disable one test in CliCommandTest on affected JDKs (failure cause
unknown)

Compatibility fixes
- Fix reflective access in DocGenerator on affected JDKs

Build fixes
- Fix misuse of `task.enabled` vs. `report.required`
- Fix `gradlew tasks` on Windows
- Downgrade Spotless to 8.3.0 to (hopefully) work around sporadic
NoClassDefFoundError

Result
- NullAway runs correctly
- Broader JDK test coverage
- More reproducible and potentially faster builds
2026-04-14 11:57:09 -07:00
Jen Basch a9c890e2f9 Do not activate power assertions when a single union member containing a type constraint fails (#1462)
Prior to this change, this code would activate powers assertions /
instrumentation permanently:
```pkl
foo: String(contains("a")) | String(contains("b")) = "boo"
```

This is because the `contains("a")` constraint would fail, triggering
power assertions, but the subsequent check of the union's
`contains("b")` branch would succeed.
As observed in #1419, once instrumentation is enabled, all subsequent
evaluation slows significantly.
As with #1419, the fix here is to disable power assertions via
`VmLocalContext` until we know that all union members failed type
checking; then, each member is re-executed with power assertions allowed
to provide the improved user-facing error.
2026-03-25 11:52:37 -07:00
Jen Basch cdc6fa8aec Prevent I/O when checking UNC paths against --root-dir (#1466)
Test on [windows] please
2026-03-25 11:40:51 -07:00
Jen Basch cce84d7ccc Correct SecurityManager check for HTTP(S) module URIs (#1463) 2026-03-23 07:43:07 -07:00
Jen Basch a6db476c70 Fix module reflection when instrumentation is active (#1464) 2026-03-23 07:42:40 -07:00
Kushal Pisavadia f9b880be85 Fix command typealias unwrapping in resolveType (#1449)
The loop unwraps nullables and constraints but breaks straight away
after a `typealias`. This means the nullable is missed. Removing the
`break` fixes it.

## Exception

```
org.pkl.core.PklException: –– Pkl Error ––
Command option property `foo` has unsupported type `String?`.

11 | foo: OptionalString
     ^^^^^^^^^^^^^^^^^^^
at <unknown> (file:///var/folders/xh/lmp1n6qj4m13t53cfmbqnkwh0000gn/T/junit-1378070630576324311/cmd.pkl)

Use a supported type or define a transformEach and/or transformAll function
```
2026-02-27 13:33:00 -08:00
Kushal Pisavadia 64ea7951db Fix stream double-consumption in CommandSpecParser (#1448)
The `choices` stream was consumed eagerly for metavar construction, then
captured in a lambda for later validation—which promptly fell over with
`IllegalStateException`. Materialise to a `List` straightaway.
2026-02-27 10:04:32 +00:00
Jen Basch 4cf2a1b42c Allow command options to have nullable types and default values (#1444) 2026-02-26 08:34:46 -08:00
Jen Basch 3ef065b6b6 Correct --root-dir check to also work for jar:file: URIs (#1442) 2026-02-25 10:57:01 -08:00
Jen Basch a5dc91f0a5 Command flag behavior improvements (#1432)
* Forbid overlap of built-in and command-defined flag names 
* Allow interleaving built-in and command-defined flags on the command
line
* List abbreviated flag names first, matching the behavior of built-in
flags
2026-02-20 12:00:18 -08:00
Jen Basch 72a57af164 SPICE-0025: pkl run CLI framework (#1367) 2026-02-12 07:53:02 -08:00
Islon Scherer f0449c8330 Add flag to turn power assertions on/off (#1419) 2026-02-03 09:35:16 +01:00
Jen Basch 73264e8fd1 SPICE-0024: Annotation converters (#1333)
This enables defining declarative key and/or value transformations in
cases where neither `Class`- nor path-based converters can be applied
gracefully. It is also the only way to express transforming the
resulting property names in `Typed` objects without applying a converter
to the entire containing type, which is cumbersome at best.

SPICE: https://github.com/apple/pkl-evolution/pull/26
2026-01-23 12:44:41 -08:00
Daniel Chao ed0cad668f Fix Function.toString (#1411)
Fixes an issue where the underlying default Java toString() is leaking
through
2026-01-21 07:29:58 -08:00
Daniel Chao 03a7676e64 Implement power assertions (#1384)
This adds power assertions to Pkl!

This implements the SPICE described in
https://github.com/apple/pkl-evolution/pull/29

This follows the power assertions style of reporting also found in
Groovy, Kotlin, and others.

* Literal values are not emitted in the diagram
* Stdlib constructors of literals like `List(1, 2)` are also considered
  literals

Power assertions are added to:

* Failing type constraints
* Failing test facts

Power assertions are implemented as a truffle instrument to observe
execution.
When an assertion fails, the instrument is created and the assertion is
run again to observe facts.
This incurs runtime overhead to collect facts, but has no impact on code
in the non-error case.

---------

Co-authored-by: Islon Scherer <islonscherer@gmail.com>
2026-01-20 21:41:33 -08:00
Akshat Anand 9d385f2194 Fix super method call inside let expression (#1383)
Fixes #1309

The issue was that super calls were blocked inside let expressions
because:
1. The compiler's isClassMemberScope() check didn't skip over lambda
scopes created by let expressions
2. The runtime's findSupermethod() didn't traverse past VmFunction
owners to find the actual class prototype

Changes:
- SymbolTable.java: Updated isClassMemberScope() to skip lambda scopes
before checking if the parent is a class or module scope
- InvokeSuperMethodNode.java: Updated findSupermethod() to skip
VmFunction owners when looking for the class prototype

Added regression tests covering:
- Super method calls inside let expressions
- Super property access inside let expressions
- Nested let expressions with super calls

---------

Co-authored-by: Jen Basch <jbasch@apple.com>
2026-01-09 19:59:20 -08:00
Daniel Chao ac4f2fd9a6 Add isNotEmpty, isNotBlank methods (#1396)
Adds convenience methods `isNotEmpty` and `isNotBlank`. This borrows the
same methods from Kotlin.

This helps users write more fluent constraints, for example,
`foo.isNotEmpty.implies(bar)`.

Adds:

* List#isNotEmpty
* Map#isNotEmpty
* Set#isNotEmpty
* Mapping#isNotEmpty
* Listing#isNotEmpty
* String#isNotEmpty
* String#isNotBlank
2026-01-08 13:22:43 -08:00
Daniel Chao 14d58a17b0 Address warning diagnostics (#1395)
This addressess various warning diagnostics throughout the codebase.
2026-01-07 22:11:24 -08:00