mirror of
https://github.com/apple/pkl.git
synced 2026-03-28 03:51:14 +01:00
Produce more helpful output when module output is overwritten (#716)
Fix a bug where overwriting `output` causes a PklBugException. This now produces a more helpful message pointing to the actual problem. Co-authored-by: translatenix <119817707+translatenix@users.noreply.github.com>
This commit is contained in:
@@ -137,7 +137,7 @@ public class EvaluatorImpl implements Evaluator {
|
||||
return doEvaluate(
|
||||
moduleSource,
|
||||
(module) -> {
|
||||
var output = (VmTyped) VmUtils.readMember(module, Identifier.OUTPUT);
|
||||
var output = readModuleOutput(module);
|
||||
return VmUtils.readTextProperty(output);
|
||||
});
|
||||
}
|
||||
@@ -147,7 +147,7 @@ public class EvaluatorImpl implements Evaluator {
|
||||
return doEvaluate(
|
||||
moduleSource,
|
||||
(module) -> {
|
||||
var output = (VmTyped) VmUtils.readMember(module, Identifier.OUTPUT);
|
||||
var output = readModuleOutput(module);
|
||||
var value = VmUtils.readMember(output, Identifier.VALUE);
|
||||
if (value instanceof VmValue vmValue) {
|
||||
vmValue.force(false);
|
||||
@@ -162,7 +162,7 @@ public class EvaluatorImpl implements Evaluator {
|
||||
return doEvaluate(
|
||||
moduleSource,
|
||||
(module) -> {
|
||||
var output = (VmTyped) VmUtils.readMember(module, Identifier.OUTPUT);
|
||||
var output = readModuleOutput(module);
|
||||
var filesOrNull = VmUtils.readMember(output, Identifier.FILES);
|
||||
if (filesOrNull instanceof VmNull) {
|
||||
return Map.of();
|
||||
@@ -243,7 +243,7 @@ public class EvaluatorImpl implements Evaluator {
|
||||
return doEvaluate(
|
||||
moduleSource,
|
||||
(module) -> {
|
||||
var output = (VmTyped) VmUtils.readMember(module, Identifier.OUTPUT);
|
||||
var output = readModuleOutput(module);
|
||||
var value = VmUtils.readMember(output, Identifier.VALUE);
|
||||
var valueClassInfo = VmUtils.getClass(value).getPClassInfo();
|
||||
if (valueClassInfo.equals(classInfo)) {
|
||||
@@ -365,13 +365,40 @@ public class EvaluatorImpl implements Evaluator {
|
||||
"evaluationTimedOut", (timeout.getSeconds() + timeout.getNano() / 1_000_000_000d)));
|
||||
}
|
||||
|
||||
private VmTyped readModuleOutput(VmTyped module) {
|
||||
var value = VmUtils.readMember(module, Identifier.OUTPUT);
|
||||
if (value instanceof VmTyped typedOutput
|
||||
&& typedOutput.getVmClass().getPClassInfo() == PClassInfo.ModuleOutput) {
|
||||
return typedOutput;
|
||||
}
|
||||
|
||||
var moduleUri = module.getModuleInfo().getModuleKey().getUri();
|
||||
var builder =
|
||||
new VmExceptionBuilder()
|
||||
.evalError(
|
||||
"invalidModuleOutput",
|
||||
"output",
|
||||
PClassInfo.ModuleOutput.getDisplayName(),
|
||||
VmUtils.getClass(value).getPClassInfo().getDisplayName(),
|
||||
moduleUri);
|
||||
var outputMember = module.getMember(Identifier.OUTPUT);
|
||||
assert outputMember != null;
|
||||
var uriOfValueMember = outputMember.getSourceSection().getSource().getURI();
|
||||
// If `output` was explicitly re-assigned, show that in the stack trace.
|
||||
if (!uriOfValueMember.equals(PClassInfo.pklBaseUri)) {
|
||||
builder.withSourceSection(outputMember.getBodySection()).withMemberName("output");
|
||||
}
|
||||
throw builder.build();
|
||||
}
|
||||
|
||||
private VmException moduleOutputValueTypeMismatch(
|
||||
VmTyped module, PClassInfo<?> expectedClassInfo, Object value, VmTyped output) {
|
||||
var moduleUri = module.getModuleInfo().getModuleKey().getUri();
|
||||
var builder =
|
||||
new VmExceptionBuilder()
|
||||
.evalError(
|
||||
"invalidModuleOutputValue",
|
||||
"invalidModuleOutput",
|
||||
"output.value",
|
||||
expectedClassInfo.getDisplayName(),
|
||||
VmUtils.getClass(value).getPClassInfo().getDisplayName(),
|
||||
moduleUri);
|
||||
|
||||
@@ -61,6 +61,8 @@ public final class PClassInfo<T> implements Serializable {
|
||||
public static final PClassInfo<LinkedHashMap> Mapping =
|
||||
pklBaseClassInfo("Mapping", LinkedHashMap.class);
|
||||
public static final PClassInfo<PModule> Module = pklBaseClassInfo("Module", PModule.class);
|
||||
public static final PClassInfo<PObject> ModuleOutput =
|
||||
pklBaseClassInfo("ModuleOutput", PObject.class);
|
||||
public static final PClassInfo<PClass> Class = pklBaseClassInfo("Class", PClass.class);
|
||||
public static final PClassInfo<TypeAlias> TypeAlias =
|
||||
pklBaseClassInfo("TypeAlias", TypeAlias.class);
|
||||
@@ -216,6 +218,7 @@ public final class PClassInfo<T> implements Serializable {
|
||||
entry(Listing.className, Listing),
|
||||
entry(Mapping.className, Mapping),
|
||||
entry(Module.className, Module),
|
||||
entry(ModuleOutput.className, ModuleOutput),
|
||||
entry(Class.className, Class),
|
||||
entry(TypeAlias.className, TypeAlias),
|
||||
entry(Regex.className, Regex),
|
||||
|
||||
@@ -833,8 +833,8 @@ A type union cannot have more than one default type.
|
||||
notAUnion=\
|
||||
Only type unions can have a default marker (*).
|
||||
|
||||
invalidModuleOutputValue=\
|
||||
Expected `output.value` of module `{2}` to be of type `{0}`, but got type `{1}`.
|
||||
invalidModuleOutput=\
|
||||
Expected `{0}` of module `{3}` to be of type `{1}`, but got type `{2}`.
|
||||
|
||||
cannotResolveDependencyWithoutHierarchicalUris=\
|
||||
Cannot import dependency because project URI `{0}` does not have a hierarchical path.
|
||||
|
||||
1
pkl-core/src/test/files/LanguageSnippetTests/input/errors/invalidOutput1.pkl
vendored
Normal file
1
pkl-core/src/test/files/LanguageSnippetTests/input/errors/invalidOutput1.pkl
vendored
Normal file
@@ -0,0 +1 @@
|
||||
output: String = "abc"
|
||||
3
pkl-core/src/test/files/LanguageSnippetTests/input/errors/invalidOutput2.pkl
vendored
Normal file
3
pkl-core/src/test/files/LanguageSnippetTests/input/errors/invalidOutput2.pkl
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
class Test {}
|
||||
|
||||
output: Test = new {}
|
||||
1
pkl-core/src/test/files/LanguageSnippetTests/input/errors/invalidOutput3.pkl
vendored
Normal file
1
pkl-core/src/test/files/LanguageSnippetTests/input/errors/invalidOutput3.pkl
vendored
Normal file
@@ -0,0 +1 @@
|
||||
output = null
|
||||
6
pkl-core/src/test/files/LanguageSnippetTests/output/errors/invalidOutput1.err
vendored
Normal file
6
pkl-core/src/test/files/LanguageSnippetTests/output/errors/invalidOutput1.err
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
–– Pkl Error ––
|
||||
Expected `output` of module `file:///$snippetsDir/input/errors/invalidOutput1.pkl` to be of type `ModuleOutput`, but got type `String`.
|
||||
|
||||
x | output: String = "abc"
|
||||
^^^^^
|
||||
at output (file:///$snippetsDir/input/errors/invalidOutput1.pkl)
|
||||
6
pkl-core/src/test/files/LanguageSnippetTests/output/errors/invalidOutput2.err
vendored
Normal file
6
pkl-core/src/test/files/LanguageSnippetTests/output/errors/invalidOutput2.err
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
–– Pkl Error ––
|
||||
Expected `output` of module `file:///$snippetsDir/input/errors/invalidOutput2.pkl` to be of type `ModuleOutput`, but got type `invalidOutput2#Test`.
|
||||
|
||||
x | output: Test = new {}
|
||||
^^^^^^
|
||||
at output (file:///$snippetsDir/input/errors/invalidOutput2.pkl)
|
||||
10
pkl-core/src/test/files/LanguageSnippetTests/output/errors/invalidOutput3.err
vendored
Normal file
10
pkl-core/src/test/files/LanguageSnippetTests/output/errors/invalidOutput3.err
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
–– Pkl Error ––
|
||||
Expected value of type `ModuleOutput`, but got `null`.
|
||||
|
||||
xx | hidden output: ModuleOutput = new {
|
||||
^^^^^^^^^^^^
|
||||
at pkl.base#Module.output (pkl:base)
|
||||
|
||||
x | output = null
|
||||
^^^^
|
||||
at invalidOutput3#output (file:///$snippetsDir/input/errors/invalidOutput3.pkl)
|
||||
Reference in New Issue
Block a user