mirror of
https://github.com/apple/pkl.git
synced 2026-06-30 02:01:54 +02:00
Improve error message for aliased references (#1695)
This commit is contained in:
@@ -27,7 +27,10 @@ import com.oracle.truffle.api.frame.FrameSlotKind;
|
||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||
import com.oracle.truffle.api.nodes.ExplodeLoop;
|
||||
import com.oracle.truffle.api.nodes.LoopNode;
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
import com.oracle.truffle.api.nodes.NodeUtil;
|
||||
import com.oracle.truffle.api.source.SourceSection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -38,6 +41,7 @@ import org.jspecify.annotations.Nullable;
|
||||
import org.pkl.core.PType;
|
||||
import org.pkl.core.PType.StringLiteral;
|
||||
import org.pkl.core.PklBugException;
|
||||
import org.pkl.core.StackFrame;
|
||||
import org.pkl.core.TypeParameter;
|
||||
import org.pkl.core.ast.*;
|
||||
import org.pkl.core.ast.builder.SymbolTable.CustomThisScope;
|
||||
@@ -54,6 +58,7 @@ import org.pkl.core.util.EconomicMaps;
|
||||
import org.pkl.core.util.EconomicSets;
|
||||
import org.pkl.core.util.LateInit;
|
||||
import org.pkl.core.util.MutableBoolean;
|
||||
import org.pkl.core.util.MutableReference;
|
||||
|
||||
public abstract class TypeNode extends PklNode {
|
||||
|
||||
@@ -2138,7 +2143,17 @@ public abstract class TypeNode extends PklNode {
|
||||
this.domainTypeNode = domainTypeNode;
|
||||
this.referentTypeNode = referentTypeNode;
|
||||
this.getModuleNode = new GetModuleNode(sourceSection);
|
||||
validateTypeArguments(sourceSection);
|
||||
// A type constraint anywhere in the referent is forbidden, including one reached through a
|
||||
// type alias used in the referent.
|
||||
var constraint = findReferentConstraint();
|
||||
if (constraint != null) {
|
||||
CompilerDirectives.transferToInterpreter();
|
||||
throw exceptionBuilder()
|
||||
.evalError("invalidReferenceTypeAnnotationWithConstraint")
|
||||
.withLeadingStackFrames(
|
||||
buildReferentConstraintFrames(constraint, getSourceSection(), null))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@Specialization
|
||||
@@ -2173,26 +2188,69 @@ public abstract class TypeNode extends PklNode {
|
||||
sourceSection, value, TypeNode.export(domainTypeNode), referentType);
|
||||
}
|
||||
|
||||
public void validateTypeArguments(@Nullable SourceSection aliasSourceSection) {
|
||||
// constraints may not be used in Reference type annotation referents
|
||||
// walk the type and throw if any part of the referent is constrained
|
||||
|
||||
// TODO improve error message when this type node and/or referent constraint are behind type
|
||||
// aliases
|
||||
/**
|
||||
* Type constraints may not appear anywhere in a {@code Reference}'s referent type argument.
|
||||
* Walks the referent type and returns the first offending {@link ConstrainedTypeNode} , or
|
||||
* {@code null} if the referent is constraint-free.
|
||||
*/
|
||||
public @Nullable ConstrainedTypeNode findReferentConstraint() {
|
||||
var found = new MutableReference<@Nullable ConstrainedTypeNode>(null);
|
||||
referentTypeNode.acceptTypeNode(
|
||||
true,
|
||||
(typeNode) -> {
|
||||
if (typeNode instanceof ConstrainedTypeNode) {
|
||||
CompilerDirectives.transferToInterpreter();
|
||||
var err =
|
||||
exceptionBuilder().evalError("invalidReferenceTypeAnnotationWithConstraint");
|
||||
if (aliasSourceSection != null) {
|
||||
err.withSourceSection(aliasSourceSection);
|
||||
}
|
||||
throw err.build();
|
||||
if (typeNode instanceof ConstrainedTypeNode constrainedTypeNode) {
|
||||
found.set(constrainedTypeNode);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return found.getOrNull();
|
||||
}
|
||||
|
||||
/** Builds the frames to show ahead of an "invalid referent constraint" error. */
|
||||
public static List<StackFrame> buildReferentConstraintFrames(
|
||||
ConstrainedTypeNode constraintNode,
|
||||
SourceSection usageSection,
|
||||
@Nullable VmTypeAlias outermostAlias) {
|
||||
var frames = new ArrayList<StackFrame>();
|
||||
for (Node node = constraintNode; node != null; node = node.getParent()) {
|
||||
if (!(node instanceof ConstrainedTypeNode
|
||||
|| node instanceof TypeAliasTypeNode
|
||||
|| node instanceof ReferenceTypeNode)) {
|
||||
continue;
|
||||
}
|
||||
var section = node.getSourceSection();
|
||||
//noinspection ConstantValue
|
||||
if (section == null || !section.isAvailable() || isWithin(usageSection, section)) {
|
||||
continue;
|
||||
}
|
||||
var owner = ownerAlias(node, outermostAlias);
|
||||
if (owner != null) {
|
||||
frames.add(VmUtils.createStackFrame(section, owner.getQualifiedName()));
|
||||
}
|
||||
}
|
||||
return frames;
|
||||
}
|
||||
|
||||
/**
|
||||
* The type alias whose body contains {@code node}: the nearest enclosing alias, else the
|
||||
* outermost alias being instantiated (which is {@code null} for a directly-used Reference).
|
||||
*/
|
||||
@SuppressWarnings("DataFlowIssue")
|
||||
private static @Nullable VmTypeAlias ownerAlias(
|
||||
Node node, @Nullable VmTypeAlias outermostAlias) {
|
||||
var parent = NodeUtil.findParent(node, TypeAliasTypeNode.class);
|
||||
//noinspection ConstantValue
|
||||
if (parent != null) {
|
||||
return parent.typeAlias;
|
||||
}
|
||||
return outermostAlias;
|
||||
}
|
||||
|
||||
private static boolean isWithin(SourceSection outer, SourceSection inner) {
|
||||
return inner.getSource().equals(outer.getSource())
|
||||
&& inner.getCharIndex() >= outer.getCharIndex()
|
||||
&& inner.getCharEndIndex() <= outer.getCharEndIndex();
|
||||
}
|
||||
|
||||
@Fallback
|
||||
@@ -2703,13 +2761,42 @@ public abstract class TypeNode extends PklNode {
|
||||
|
||||
this.typeAlias = typeAlias;
|
||||
this.typeArgumentNodes = typeArgumentNodes;
|
||||
aliasedTypeNode = typeAlias.instantiate(typeArgumentNodes, sourceSection);
|
||||
aliasedTypeNode = typeAlias.instantiate(typeArgumentNodes);
|
||||
checkReferentConstraints(typeAlias);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports a forbidden type constraint that a type argument introduced into a {@code
|
||||
* Reference}'s referent through this (generic) alias. The error is reported at this usage type
|
||||
* expression, with leading frames for the constraint and every alias layer it passed through.
|
||||
*/
|
||||
private void checkReferentConstraints(VmTypeAlias outermostAlias) {
|
||||
aliasedTypeNode.accept(
|
||||
node -> {
|
||||
if (node instanceof ReferenceTypeNode referenceTypeNode) {
|
||||
var constraint = referenceTypeNode.findReferentConstraint();
|
||||
if (constraint != null) {
|
||||
CompilerDirectives.transferToInterpreter();
|
||||
throw exceptionBuilder()
|
||||
.evalError("invalidReferenceTypeAnnotationWithConstraint")
|
||||
.withLeadingStackFrames(
|
||||
ReferenceTypeNode.buildReferentConstraintFrames(
|
||||
constraint, getSourceSection(), outermostAlias))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public TypeNode getAliasedTypeNode() {
|
||||
return aliasedTypeNode;
|
||||
}
|
||||
|
||||
public VmTypeAlias getTypeAlias() {
|
||||
return typeAlias;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FrameSlotKind getFrameSlotKind() {
|
||||
return aliasedTypeNode.getFrameSlotKind();
|
||||
|
||||
@@ -38,6 +38,10 @@ final class StackTraceGenerator {
|
||||
}
|
||||
|
||||
private List<StackFrame> capture() {
|
||||
// frames that aren't part of the runtime call stack are
|
||||
// shown ahead of the captured frames.
|
||||
frames.addAll(exception.getLeadingStackFrames());
|
||||
|
||||
var truffleElements = TruffleStackTrace.getStackTrace(exception);
|
||||
if (truffleElements.isEmpty()) {
|
||||
addFrame(exception.getSourceSection(), exception.getMemberName());
|
||||
|
||||
@@ -38,7 +38,8 @@ public final class VmBugException extends VmException {
|
||||
@Nullable SourceSection sourceSection,
|
||||
@Nullable String memberName,
|
||||
@Nullable BiConsumer<AnsiStringBuilder, Boolean> hintBuilder,
|
||||
Map<CallTarget, StackFrame> insertedStackFrames) {
|
||||
Map<CallTarget, StackFrame> insertedStackFrames,
|
||||
List<StackFrame> leadingStackFrames) {
|
||||
|
||||
super(
|
||||
message,
|
||||
@@ -51,7 +52,8 @@ public final class VmBugException extends VmException {
|
||||
sourceSection,
|
||||
memberName,
|
||||
hintBuilder,
|
||||
insertedStackFrames);
|
||||
insertedStackFrames,
|
||||
leadingStackFrames);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -37,7 +37,8 @@ public class VmEvalException extends VmException {
|
||||
@Nullable SourceSection sourceSection,
|
||||
@Nullable String memberName,
|
||||
@Nullable BiConsumer<AnsiStringBuilder, Boolean> hintBuilder,
|
||||
Map<CallTarget, StackFrame> insertedStackFrames) {
|
||||
Map<CallTarget, StackFrame> insertedStackFrames,
|
||||
List<StackFrame> leadingStackFrames) {
|
||||
|
||||
super(
|
||||
message,
|
||||
@@ -50,6 +51,7 @@ public class VmEvalException extends VmException {
|
||||
sourceSection,
|
||||
memberName,
|
||||
hintBuilder,
|
||||
insertedStackFrames);
|
||||
insertedStackFrames,
|
||||
leadingStackFrames);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ public abstract class VmException extends AbstractTruffleException {
|
||||
private final @Nullable SourceSection sourceSection;
|
||||
private final @Nullable String memberName;
|
||||
private final Map<CallTarget, StackFrame> insertedStackFrames;
|
||||
private final List<StackFrame> leadingStackFrames;
|
||||
@Nullable private final BiConsumer<AnsiStringBuilder, Boolean> messageBuilder;
|
||||
@Nullable protected BiConsumer<AnsiStringBuilder, Boolean> hintBuilder;
|
||||
|
||||
@@ -48,7 +49,8 @@ public abstract class VmException extends AbstractTruffleException {
|
||||
@Nullable SourceSection sourceSection,
|
||||
@Nullable String memberName,
|
||||
@Nullable BiConsumer<AnsiStringBuilder, Boolean> hintBuilder,
|
||||
Map<CallTarget, StackFrame> insertedStackFrames) {
|
||||
Map<CallTarget, StackFrame> insertedStackFrames,
|
||||
List<StackFrame> leadingStackFrames) {
|
||||
super(message, cause, UNLIMITED_STACK_TRACE, location);
|
||||
assert message != null || messageBuilder != null;
|
||||
this.messageBuilder = messageBuilder;
|
||||
@@ -58,6 +60,7 @@ public abstract class VmException extends AbstractTruffleException {
|
||||
this.sourceSection = sourceSection;
|
||||
this.memberName = memberName;
|
||||
this.insertedStackFrames = insertedStackFrames;
|
||||
this.leadingStackFrames = leadingStackFrames;
|
||||
this.hintBuilder = hintBuilder;
|
||||
}
|
||||
|
||||
@@ -89,6 +92,14 @@ public abstract class VmException extends AbstractTruffleException {
|
||||
return insertedStackFrames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stack frames to prepend to the rendered stack trace, ahead of the captured frames. Used to show
|
||||
* source locations that aren't part of the runtime call stack.
|
||||
*/
|
||||
public final List<StackFrame> getLeadingStackFrames() {
|
||||
return leadingStackFrames;
|
||||
}
|
||||
|
||||
public @Nullable BiConsumer<AnsiStringBuilder, Boolean> getMessageBuilder() {
|
||||
return messageBuilder;
|
||||
}
|
||||
|
||||
@@ -99,6 +99,7 @@ public final class VmExceptionBuilder {
|
||||
private @Nullable Node location;
|
||||
private @Nullable SourceSection sourceSection;
|
||||
private @Nullable String memberName;
|
||||
private List<StackFrame> leadingStackFrames = List.of();
|
||||
|
||||
public VmExceptionBuilder typeMismatch(Object value, VmClass expectedType) {
|
||||
if (value instanceof VmNull) {
|
||||
@@ -359,6 +360,15 @@ public final class VmExceptionBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frames to show ahead of the captured stack trace (see {@link
|
||||
* VmException#getLeadingStackFrames()}).
|
||||
*/
|
||||
public VmExceptionBuilder withLeadingStackFrames(List<StackFrame> leadingStackFrames) {
|
||||
this.leadingStackFrames = leadingStackFrames;
|
||||
return this;
|
||||
}
|
||||
|
||||
public VmException build() {
|
||||
if (message != null && messageBuilder != null) {
|
||||
throw new IllegalStateException("Both message and messageBuilder are set");
|
||||
@@ -387,7 +397,8 @@ public final class VmExceptionBuilder {
|
||||
sourceSection,
|
||||
memberName,
|
||||
hintBuilder,
|
||||
effectiveInsertedStackFrames);
|
||||
effectiveInsertedStackFrames,
|
||||
leadingStackFrames);
|
||||
case UNDEFINED_VALUE ->
|
||||
new VmUndefinedValueException(
|
||||
message,
|
||||
@@ -401,7 +412,8 @@ public final class VmExceptionBuilder {
|
||||
memberName,
|
||||
hintBuilder,
|
||||
receiver,
|
||||
effectiveInsertedStackFrames);
|
||||
effectiveInsertedStackFrames,
|
||||
leadingStackFrames);
|
||||
case BUG ->
|
||||
new VmBugException(
|
||||
message,
|
||||
@@ -414,7 +426,8 @@ public final class VmExceptionBuilder {
|
||||
sourceSection,
|
||||
memberName,
|
||||
hintBuilder,
|
||||
effectiveInsertedStackFrames);
|
||||
effectiveInsertedStackFrames,
|
||||
leadingStackFrames);
|
||||
case WRAPPED -> {
|
||||
assert wrappedException != null;
|
||||
yield new VmWrappedEvalException(
|
||||
@@ -429,6 +442,7 @@ public final class VmExceptionBuilder {
|
||||
memberName,
|
||||
hintBuilder,
|
||||
effectiveInsertedStackFrames,
|
||||
leadingStackFrames,
|
||||
wrappedException);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -32,6 +32,7 @@ public final class VmStackOverflowException extends VmException {
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
new HashMap<>());
|
||||
new HashMap<>(),
|
||||
List.of());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ import org.pkl.core.TypeParameter;
|
||||
import org.pkl.core.ast.VmModifier;
|
||||
import org.pkl.core.ast.type.TypeNode;
|
||||
import org.pkl.core.ast.type.TypeNode.ConstrainedTypeNode;
|
||||
import org.pkl.core.ast.type.TypeNode.ReferenceTypeNode;
|
||||
import org.pkl.core.ast.type.TypeNode.TypeVariableNode;
|
||||
import org.pkl.core.ast.type.TypeNode.UnknownTypeNode;
|
||||
import org.pkl.core.util.LateInit;
|
||||
@@ -178,8 +177,7 @@ public final class VmTypeAlias extends VmValue {
|
||||
}
|
||||
|
||||
@TruffleBoundary
|
||||
public TypeNode instantiate(
|
||||
TypeNode[] typeArgumentNodes, SourceSection typeAliasTypeNodeSourceSection) {
|
||||
public TypeNode instantiate(TypeNode[] typeArgumentNodes) {
|
||||
// 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
|
||||
@@ -201,13 +199,6 @@ public final class VmTypeAlias extends VmValue {
|
||||
}
|
||||
return true;
|
||||
});
|
||||
clone.accept(
|
||||
node -> {
|
||||
if (node instanceof ReferenceTypeNode referenceTypeNode) {
|
||||
referenceTypeNode.validateTypeArguments(typeAliasTypeNodeSourceSection);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,8 @@ public final class VmUndefinedValueException extends VmEvalException {
|
||||
@Nullable String memberName,
|
||||
@Nullable BiConsumer<AnsiStringBuilder, Boolean> hintBuilder,
|
||||
@Nullable Object receiver,
|
||||
@Nullable Map<CallTarget, StackFrame> insertedStackFrames) {
|
||||
@Nullable Map<CallTarget, StackFrame> insertedStackFrames,
|
||||
List<StackFrame> leadingStackFrames) {
|
||||
|
||||
super(
|
||||
message,
|
||||
@@ -56,7 +57,8 @@ public final class VmUndefinedValueException extends VmEvalException {
|
||||
sourceSection,
|
||||
memberName,
|
||||
hintBuilder,
|
||||
insertedStackFrames == null ? Collections.emptyMap() : insertedStackFrames);
|
||||
insertedStackFrames == null ? Collections.emptyMap() : insertedStackFrames,
|
||||
leadingStackFrames);
|
||||
|
||||
this.receiver = receiver;
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ public class VmWrappedEvalException extends VmEvalException {
|
||||
@Nullable String memberName,
|
||||
@Nullable BiConsumer<AnsiStringBuilder, Boolean> hintBuilder,
|
||||
Map<CallTarget, StackFrame> insertedStackFrames,
|
||||
List<StackFrame> leadingStackFrames,
|
||||
VmException wrappedException) {
|
||||
super(
|
||||
message,
|
||||
@@ -53,7 +54,8 @@ public class VmWrappedEvalException extends VmEvalException {
|
||||
sourceSection,
|
||||
memberName,
|
||||
hintBuilder,
|
||||
insertedStackFrames);
|
||||
insertedStackFrames,
|
||||
leadingStackFrames);
|
||||
this.wrappedException = wrappedException;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
import "pkl:ref"
|
||||
|
||||
typealias Ref<T> = ref.Reference<ref.Domain, T>
|
||||
|
||||
typealias Ref2<T> = Ref<T>
|
||||
|
||||
foo: Ref2<String(isEmpty)>
|
||||
@@ -0,0 +1,6 @@
|
||||
import "pkl:ref"
|
||||
|
||||
typealias Ref<T> = ref.Reference<ref.Domain, T>
|
||||
typealias Ref2<T> = Ref<T(isEmpty)>
|
||||
|
||||
foo: Ref2<String>
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
import "pkl:ref"
|
||||
|
||||
typealias Foo1 = Foo2
|
||||
typealias Foo2 = String(isEmpty)
|
||||
|
||||
foo: ref.Reference<ref.Domain, Foo1>
|
||||
@@ -1,6 +1,10 @@
|
||||
–– Pkl Error ––
|
||||
`Reference` referent type argument may not include type constraints.
|
||||
|
||||
x | typealias Ref<T> = ref.Reference<D, T>
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
at reference10#Ref (file:///$snippetsDir/input/errors/reference10.pkl)
|
||||
|
||||
x | test = ref.Reference(d, String, "") as Ref<Listing<String(true)>>
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
at reference10#test (file:///$snippetsDir/input/errors/reference10.pkl)
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
–– Pkl Error ––
|
||||
`Reference` referent type argument may not include type constraints.
|
||||
|
||||
xx | typealias Alias2 = String(length < 5)
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
at reference11#Alias2 (file:///$snippetsDir/input/errors/reference11.pkl)
|
||||
|
||||
xx | typealias Alias1 = Int | Alias2?
|
||||
^^^^^^
|
||||
at reference11#Alias1 (file:///$snippetsDir/input/errors/reference11.pkl)
|
||||
|
||||
x | typealias Ref<T> = ref.Reference<D, T>
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
at reference11#Ref (file:///$snippetsDir/input/errors/reference11.pkl)
|
||||
|
||||
x | test = ref.Reference(d, String, "") as Ref<Alias1?>
|
||||
^^^^^^^^^^^^
|
||||
at reference11#test (file:///$snippetsDir/input/errors/reference11.pkl)
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
–– Pkl Error ––
|
||||
`Reference` referent type argument may not include type constraints.
|
||||
|
||||
xx | typealias Alias2 = String(length < 5)
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
at reference12#Alias2 (file:///$snippetsDir/input/errors/reference12.pkl)
|
||||
|
||||
x | typealias RefAlias1 = ref.Reference<D, Alias1?>
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
at reference12#RefAlias1 (file:///$snippetsDir/input/errors/reference12.pkl)
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
–– Pkl Error ––
|
||||
`Reference` referent type argument may not include type constraints.
|
||||
|
||||
x | typealias Ref<T> = ref.Reference<ref.Domain, T>
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
at reference21#Ref (file:///$snippetsDir/input/errors/reference21.pkl)
|
||||
|
||||
x | typealias Ref2<T> = Ref<T>
|
||||
^^^^^^
|
||||
at reference21#Ref2 (file:///$snippetsDir/input/errors/reference21.pkl)
|
||||
|
||||
x | foo: Ref2<String(isEmpty)>
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
at reference21 (file:///$snippetsDir/input/errors/reference21.pkl)
|
||||
@@ -0,0 +1,14 @@
|
||||
–– Pkl Error ––
|
||||
`Reference` referent type argument may not include type constraints.
|
||||
|
||||
x | typealias Ref<T> = ref.Reference<ref.Domain, T>
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
at reference22#Ref (file:///$snippetsDir/input/errors/reference22.pkl)
|
||||
|
||||
x | typealias Ref2<T> = Ref<T(isEmpty)>
|
||||
^^^^^^^^^^^^^^^
|
||||
at reference22#Ref2 (file:///$snippetsDir/input/errors/reference22.pkl)
|
||||
|
||||
x | foo: Ref2<String>
|
||||
^^^^
|
||||
at reference22 (file:///$snippetsDir/input/errors/reference22.pkl)
|
||||
@@ -0,0 +1,10 @@
|
||||
–– Pkl Error ––
|
||||
`Reference` referent type argument may not include type constraints.
|
||||
|
||||
x | typealias Foo2 = String(isEmpty)
|
||||
^^^^^^^^^^^^^^^
|
||||
at reference23#Foo2 (file:///$snippetsDir/input/errors/reference23.pkl)
|
||||
|
||||
x | foo: ref.Reference<ref.Domain, Foo1>
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
at reference23 (file:///$snippetsDir/input/errors/reference23.pkl)
|
||||
@@ -1,6 +1,10 @@
|
||||
–– Pkl Error ––
|
||||
`Reference` referent type argument may not include type constraints.
|
||||
|
||||
x | typealias Ref<T> = ref.Reference<D, T>
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
at reference8#Ref (file:///$snippetsDir/input/errors/reference8.pkl)
|
||||
|
||||
x | test = ref.Reference(d, String, "") as Ref<String(true)>
|
||||
^^^^^^^^^^^^^^^^^
|
||||
at reference8#test (file:///$snippetsDir/input/errors/reference8.pkl)
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
–– Pkl Error ––
|
||||
`Reference` referent type argument may not include type constraints.
|
||||
|
||||
x | typealias Ref<T> = ref.Reference<D, T>
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
at reference9#Ref (file:///$snippetsDir/input/errors/reference9.pkl)
|
||||
|
||||
x | test = ref.Reference(d, String, "") as Ref<String(true) | Int>
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
at reference9#test (file:///$snippetsDir/input/errors/reference9.pkl)
|
||||
|
||||
Reference in New Issue
Block a user