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>
This commit is contained in:
Daniel Chao
2026-01-20 21:41:33 -08:00
committed by GitHub
parent 3cd294b62a
commit 03a7676e64
107 changed files with 2133 additions and 290 deletions

View File

@@ -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.

View File

@@ -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.
@@ -31,6 +31,10 @@ public record Span(int charIndex, int length) {
return charIndex + length - 1;
}
public int stopIndexExclusive() {
return charIndex + length;
}
public Span stopSpan() {
return new Span(charIndex + length - 1, 1);
}
@@ -42,4 +46,9 @@ public record Span(int charIndex, int length) {
public Span grow(int amount) {
return new Span(charIndex, length + amount);
}
/** Tells if {@code other} is entirely within this span. */
public boolean contains(Span other) {
return charIndex <= other.charIndex && other.charIndex + other.length <= charIndex + length;
}
}

View File

@@ -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.
@@ -191,6 +191,35 @@ public enum Token {
};
}
public boolean isOperator() {
return switch (this) {
case POW,
STAR,
DIV,
INT_DIV,
MOD,
PLUS,
MINUS,
GT,
GTE,
LT,
LTE,
IS,
AS,
EQUAL,
NOT_EQUAL,
AND,
OR,
PIPE,
COALESCE,
DOT,
QDOT,
LBRACK ->
true;
default -> false;
};
}
public boolean isAffix() {
return switch (this) {
case LINE_COMMENT, BLOCK_COMMENT, SEMICOLON -> true;

View File

@@ -127,7 +127,22 @@ public abstract sealed class Expr extends AbstractNode {
}
}
public static final class SingleLineStringLiteralExpr extends Expr {
public abstract static sealed class StringLiteralExpr extends Expr
permits SingleLineStringLiteralExpr, MultiLineStringLiteralExpr {
public abstract List<StringPart> getParts();
public StringLiteralExpr(Span span, List<StringPart> parts) {
super(span, parts);
}
public final boolean hasInterpolation() {
var children = children();
assert children != null;
return children.size() > 1;
}
}
public static final class SingleLineStringLiteralExpr extends StringLiteralExpr {
private final Span startDelimiterSpan;
private final Span endDelimiterSpan;
@@ -158,7 +173,7 @@ public abstract sealed class Expr extends AbstractNode {
}
}
public static final class MultiLineStringLiteralExpr extends Expr {
public static final class MultiLineStringLiteralExpr extends StringLiteralExpr {
private final Span startDelimiterSpan;
private final Span endDelimiterSpan;