mirror of
https://github.com/apple/pkl.git
synced 2026-04-21 16:01:31 +02: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(
|
return doEvaluate(
|
||||||
moduleSource,
|
moduleSource,
|
||||||
(module) -> {
|
(module) -> {
|
||||||
var output = (VmTyped) VmUtils.readMember(module, Identifier.OUTPUT);
|
var output = readModuleOutput(module);
|
||||||
return VmUtils.readTextProperty(output);
|
return VmUtils.readTextProperty(output);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -147,7 +147,7 @@ public class EvaluatorImpl implements Evaluator {
|
|||||||
return doEvaluate(
|
return doEvaluate(
|
||||||
moduleSource,
|
moduleSource,
|
||||||
(module) -> {
|
(module) -> {
|
||||||
var output = (VmTyped) VmUtils.readMember(module, Identifier.OUTPUT);
|
var output = readModuleOutput(module);
|
||||||
var value = VmUtils.readMember(output, Identifier.VALUE);
|
var value = VmUtils.readMember(output, Identifier.VALUE);
|
||||||
if (value instanceof VmValue vmValue) {
|
if (value instanceof VmValue vmValue) {
|
||||||
vmValue.force(false);
|
vmValue.force(false);
|
||||||
@@ -162,7 +162,7 @@ public class EvaluatorImpl implements Evaluator {
|
|||||||
return doEvaluate(
|
return doEvaluate(
|
||||||
moduleSource,
|
moduleSource,
|
||||||
(module) -> {
|
(module) -> {
|
||||||
var output = (VmTyped) VmUtils.readMember(module, Identifier.OUTPUT);
|
var output = readModuleOutput(module);
|
||||||
var filesOrNull = VmUtils.readMember(output, Identifier.FILES);
|
var filesOrNull = VmUtils.readMember(output, Identifier.FILES);
|
||||||
if (filesOrNull instanceof VmNull) {
|
if (filesOrNull instanceof VmNull) {
|
||||||
return Map.of();
|
return Map.of();
|
||||||
@@ -243,7 +243,7 @@ public class EvaluatorImpl implements Evaluator {
|
|||||||
return doEvaluate(
|
return doEvaluate(
|
||||||
moduleSource,
|
moduleSource,
|
||||||
(module) -> {
|
(module) -> {
|
||||||
var output = (VmTyped) VmUtils.readMember(module, Identifier.OUTPUT);
|
var output = readModuleOutput(module);
|
||||||
var value = VmUtils.readMember(output, Identifier.VALUE);
|
var value = VmUtils.readMember(output, Identifier.VALUE);
|
||||||
var valueClassInfo = VmUtils.getClass(value).getPClassInfo();
|
var valueClassInfo = VmUtils.getClass(value).getPClassInfo();
|
||||||
if (valueClassInfo.equals(classInfo)) {
|
if (valueClassInfo.equals(classInfo)) {
|
||||||
@@ -365,13 +365,40 @@ public class EvaluatorImpl implements Evaluator {
|
|||||||
"evaluationTimedOut", (timeout.getSeconds() + timeout.getNano() / 1_000_000_000d)));
|
"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(
|
private VmException moduleOutputValueTypeMismatch(
|
||||||
VmTyped module, PClassInfo<?> expectedClassInfo, Object value, VmTyped output) {
|
VmTyped module, PClassInfo<?> expectedClassInfo, Object value, VmTyped output) {
|
||||||
var moduleUri = module.getModuleInfo().getModuleKey().getUri();
|
var moduleUri = module.getModuleInfo().getModuleKey().getUri();
|
||||||
var builder =
|
var builder =
|
||||||
new VmExceptionBuilder()
|
new VmExceptionBuilder()
|
||||||
.evalError(
|
.evalError(
|
||||||
"invalidModuleOutputValue",
|
"invalidModuleOutput",
|
||||||
|
"output.value",
|
||||||
expectedClassInfo.getDisplayName(),
|
expectedClassInfo.getDisplayName(),
|
||||||
VmUtils.getClass(value).getPClassInfo().getDisplayName(),
|
VmUtils.getClass(value).getPClassInfo().getDisplayName(),
|
||||||
moduleUri);
|
moduleUri);
|
||||||
|
|||||||
@@ -61,6 +61,8 @@ public final class PClassInfo<T> implements Serializable {
|
|||||||
public static final PClassInfo<LinkedHashMap> Mapping =
|
public static final PClassInfo<LinkedHashMap> Mapping =
|
||||||
pklBaseClassInfo("Mapping", LinkedHashMap.class);
|
pklBaseClassInfo("Mapping", LinkedHashMap.class);
|
||||||
public static final PClassInfo<PModule> Module = pklBaseClassInfo("Module", PModule.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<PClass> Class = pklBaseClassInfo("Class", PClass.class);
|
||||||
public static final PClassInfo<TypeAlias> TypeAlias =
|
public static final PClassInfo<TypeAlias> TypeAlias =
|
||||||
pklBaseClassInfo("TypeAlias", TypeAlias.class);
|
pklBaseClassInfo("TypeAlias", TypeAlias.class);
|
||||||
@@ -216,6 +218,7 @@ public final class PClassInfo<T> implements Serializable {
|
|||||||
entry(Listing.className, Listing),
|
entry(Listing.className, Listing),
|
||||||
entry(Mapping.className, Mapping),
|
entry(Mapping.className, Mapping),
|
||||||
entry(Module.className, Module),
|
entry(Module.className, Module),
|
||||||
|
entry(ModuleOutput.className, ModuleOutput),
|
||||||
entry(Class.className, Class),
|
entry(Class.className, Class),
|
||||||
entry(TypeAlias.className, TypeAlias),
|
entry(TypeAlias.className, TypeAlias),
|
||||||
entry(Regex.className, Regex),
|
entry(Regex.className, Regex),
|
||||||
|
|||||||
@@ -833,8 +833,8 @@ A type union cannot have more than one default type.
|
|||||||
notAUnion=\
|
notAUnion=\
|
||||||
Only type unions can have a default marker (*).
|
Only type unions can have a default marker (*).
|
||||||
|
|
||||||
invalidModuleOutputValue=\
|
invalidModuleOutput=\
|
||||||
Expected `output.value` of module `{2}` to be of type `{0}`, but got type `{1}`.
|
Expected `{0}` of module `{3}` to be of type `{1}`, but got type `{2}`.
|
||||||
|
|
||||||
cannotResolveDependencyWithoutHierarchicalUris=\
|
cannotResolveDependencyWithoutHierarchicalUris=\
|
||||||
Cannot import dependency because project URI `{0}` does not have a hierarchical path.
|
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