Switch type argument syntax (#1940)
This changes type argument syntax to "standard" style, and away from turbofish. The motivation here is that turbofish-style type arguments are hard to read, and developers who are not already deeply knowledgeable about Pkl might struggle to understand such code. In most languages, the grammar for "method call with type args" don't introduce any additional symbols between the identifier and the type argument list (e.g. C++, TypeScript, C#, Scala, Go).
This commit is contained in:
1 parent
6ad50eb589
commit
a9b7fe3a33
96 files changed
+1448
-376
No files matched your search
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2024 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.
|
||||
@@ -29,5 +29,12 @@ public enum MemberLookupMode {
|
||||
IMPLICIT_THIS,
|
||||
|
||||
/** Member lookup with explicit receiver (e.g., {@code foo.bar}). */
|
||||
EXPLICIT_RECEIVER
|
||||
EXPLICIT_RECEIVER,
|
||||
|
||||
/** Member lookup with explicit {@code super.}. */
|
||||
EXPLICIT_SUPER;
|
||||
|
||||
public boolean isImplicitReceiver() {
|
||||
return this != EXPLICIT_RECEIVER && this != EXPLICIT_SUPER;
|
||||
}
|
||||
}
|
||||
+9
-2
@@ -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.
|
||||
@@ -19,6 +19,7 @@ import com.oracle.truffle.api.CompilerDirectives;
|
||||
import com.oracle.truffle.api.dsl.Idempotent;
|
||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||
import com.oracle.truffle.api.source.SourceSection;
|
||||
import org.pkl.core.ast.MemberLookupMode;
|
||||
import org.pkl.core.ast.PklNode;
|
||||
import org.pkl.core.ast.member.ObjectMember;
|
||||
import org.pkl.core.runtime.Identifier;
|
||||
@@ -63,7 +64,13 @@ public abstract class GeneratorMemberNode extends PklNode {
|
||||
if (classProperty == null) {
|
||||
var exception =
|
||||
exceptionBuilder()
|
||||
.cannotFindProperty(clazz.getPrototype(), memberName, false, false)
|
||||
.cannotFindProperty(
|
||||
clazz.getPrototype(),
|
||||
clazz.getPrototype(),
|
||||
memberName,
|
||||
false,
|
||||
MemberLookupMode.EXPLICIT_RECEIVER,
|
||||
null)
|
||||
.build();
|
||||
if (member.getHeaderSection().isAvailable()) {
|
||||
exception
|
||||
|
||||
+8
-1
@@ -29,6 +29,7 @@ import org.graalvm.collections.EconomicMap;
|
||||
import org.graalvm.collections.UnmodifiableEconomicMap;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.pkl.core.ast.ExpressionNode;
|
||||
import org.pkl.core.ast.MemberLookupMode;
|
||||
import org.pkl.core.ast.member.ObjectMember;
|
||||
import org.pkl.core.ast.type.UnresolvedTypeNode;
|
||||
import org.pkl.core.runtime.*;
|
||||
@@ -80,7 +81,13 @@ public abstract class SpecializedObjectLiteralNode extends ObjectLiteralNode {
|
||||
var memberName = member.getName();
|
||||
if (!parentClass.hasProperty(memberName)) {
|
||||
throw exceptionBuilder()
|
||||
.cannotFindProperty(parentClass.getPrototype(), memberName, false, false)
|
||||
.cannotFindProperty(
|
||||
parentClass.getPrototype(),
|
||||
parentClass.getPrototype(),
|
||||
memberName,
|
||||
false,
|
||||
MemberLookupMode.EXPLICIT_RECEIVER,
|
||||
null)
|
||||
.withSourceSection(member.getHeaderSection())
|
||||
.build();
|
||||
}
|
||||
|
||||
+10
-4
@@ -37,6 +37,7 @@ import org.pkl.core.ast.type.UnresolvedTypeNode;
|
||||
import org.pkl.core.runtime.Identifier;
|
||||
import org.pkl.core.runtime.VmClass;
|
||||
import org.pkl.core.runtime.VmFunction;
|
||||
import org.pkl.core.runtime.VmUtils;
|
||||
|
||||
/** A virtual method call. */
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
@@ -89,6 +90,8 @@ public abstract class InvokeMethodVirtualNode extends AbstractInvokeMethodNode {
|
||||
*/
|
||||
public abstract Object executeWith(VirtualFrame frame, Object value, VmClass clazz);
|
||||
|
||||
protected abstract ExpressionNode getReceiverNode();
|
||||
|
||||
/** Intrinsifies `FunctionN.apply()` calls. */
|
||||
@Specialization(guards = {"methodName == APPLY", "receiver.getCallTarget() == cachedCallTarget"})
|
||||
protected Object evalFunctionCached(
|
||||
@@ -119,7 +122,7 @@ public abstract class InvokeMethodVirtualNode extends AbstractInvokeMethodNode {
|
||||
Object receiver,
|
||||
@SuppressWarnings("unused") VmClass receiverClass,
|
||||
@Cached("receiverClass") @SuppressWarnings("unused") VmClass cachedReceiverClass,
|
||||
@Cached("resolveMethod(receiverClass)") ClassMethod method,
|
||||
@Cached("resolveMethod(frame, receiverClass)") ClassMethod method,
|
||||
@Cached("create(method.getCallTarget(sourceSection))") DirectCallNode callNode) {
|
||||
var args = evalArgs(frame, method, method.getOwner(), receiver);
|
||||
return callNode.call(args);
|
||||
@@ -131,7 +134,7 @@ public abstract class InvokeMethodVirtualNode extends AbstractInvokeMethodNode {
|
||||
Object receiver,
|
||||
VmClass receiverClass,
|
||||
@Exclusive @Cached("create()") IndirectCallNode callNode) {
|
||||
var method = resolveMethod(receiverClass);
|
||||
var method = resolveMethod(frame, receiverClass);
|
||||
var args = evalArgs(frame, method, method.getOwner(), receiver);
|
||||
|
||||
// Deprecation should not report here (getCallTarget(sourceSection)), as this happens for each
|
||||
@@ -139,7 +142,7 @@ public abstract class InvokeMethodVirtualNode extends AbstractInvokeMethodNode {
|
||||
return callNode.call(method.getCallTarget(), args);
|
||||
}
|
||||
|
||||
protected ClassMethod resolveMethod(VmClass receiverClass) {
|
||||
protected ClassMethod resolveMethod(VirtualFrame frame, VmClass receiverClass) {
|
||||
var method = receiverClass.getMethod(methodName);
|
||||
if (method != null) {
|
||||
checkConst(method);
|
||||
@@ -151,9 +154,12 @@ public abstract class InvokeMethodVirtualNode extends AbstractInvokeMethodNode {
|
||||
throw exceptionBuilder()
|
||||
.cannotFindMethod(
|
||||
receiverClass.getPrototype(),
|
||||
VmUtils.getOwner(frame),
|
||||
methodName,
|
||||
argumentNodes.length,
|
||||
lookupMode != MemberLookupMode.EXPLICIT_RECEIVER)
|
||||
lookupMode,
|
||||
unresolvedTypeArgumentNodes != null,
|
||||
getReceiverNode())
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
+9
-1
@@ -23,6 +23,7 @@ import com.oracle.truffle.api.nodes.DirectCallNode;
|
||||
import com.oracle.truffle.api.source.SourceSection;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.pkl.core.ast.ExpressionNode;
|
||||
import org.pkl.core.ast.MemberLookupMode;
|
||||
import org.pkl.core.ast.member.ClassMethod;
|
||||
import org.pkl.core.ast.type.UnresolvedTypeNode;
|
||||
import org.pkl.core.runtime.Identifier;
|
||||
@@ -84,7 +85,14 @@ public abstract class InvokeSuperMethodNode extends AbstractInvokeMethodNode {
|
||||
var parent = owner.getParent();
|
||||
assert parent != null;
|
||||
throw exceptionBuilder()
|
||||
.cannotFindMethod(parent, methodName, argumentNodes.length, false)
|
||||
.cannotFindMethod(
|
||||
parent,
|
||||
VmUtils.getOwner(frame),
|
||||
methodName,
|
||||
argumentNodes.length,
|
||||
MemberLookupMode.EXPLICIT_SUPER,
|
||||
unresolvedTypeArgumentNodes != null,
|
||||
null)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import com.oracle.truffle.api.CompilerDirectives;
|
||||
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
|
||||
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
|
||||
import com.oracle.truffle.api.dsl.*;
|
||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||
import com.oracle.truffle.api.nodes.DirectCallNode;
|
||||
import com.oracle.truffle.api.nodes.IndirectCallNode;
|
||||
import com.oracle.truffle.api.nodes.NodeInfo;
|
||||
@@ -32,7 +33,7 @@ import org.pkl.core.runtime.VmReference.VmReferenceAccessError;
|
||||
import org.pkl.core.util.ErrorMessages;
|
||||
|
||||
@NodeInfo(shortName = ".")
|
||||
@ImportStatic(BaseModule.class)
|
||||
@ImportStatic({BaseModule.class, VmUtils.class})
|
||||
@NodeChild(value = "receiverNode", type = ExpressionNode.class)
|
||||
public abstract class ReadPropertyNode extends ExpressionNode {
|
||||
protected final Identifier propertyName;
|
||||
@@ -63,6 +64,8 @@ public abstract class ReadPropertyNode extends ExpressionNode {
|
||||
this(sourceSection, propertyName, MemberLookupMode.EXPLICIT_RECEIVER, false);
|
||||
}
|
||||
|
||||
protected abstract ExpressionNode getReceiverNode();
|
||||
|
||||
protected String getReferenceErrorHint(VmReference reference, VmReferenceAccessError err) {
|
||||
var myType = reference.getReferentType();
|
||||
return switch (err.getErrorType()) {
|
||||
@@ -102,6 +105,7 @@ public abstract class ReadPropertyNode extends ExpressionNode {
|
||||
// https://www.graalvm.org/22.0/graalvm-as-a-platform/language-implementation-framework/TruffleLibraries/#strategy-2-java-interfaces
|
||||
@Specialization(guards = "receiver.getClass() == cachedClass", limit = "99")
|
||||
protected Object evalObject(
|
||||
VirtualFrame frame,
|
||||
Object receiver,
|
||||
@Cached("getVmObjectSubclassOrNull(receiver)") Class<? extends VmObjectLike> cachedClass,
|
||||
@Cached("create()") IndirectCallNode callNode) {
|
||||
@@ -112,15 +116,16 @@ public abstract class ReadPropertyNode extends ExpressionNode {
|
||||
if (result != null) return result;
|
||||
|
||||
CompilerDirectives.transferToInterpreter();
|
||||
throw cannotFindProperty(object);
|
||||
throw cannotFindProperty(VmUtils.getOwner(frame), object);
|
||||
}
|
||||
|
||||
// specializations for all other types
|
||||
@Specialization(guards = "receiver.getClass() == cachedClass", limit = "99")
|
||||
protected Object evalOther(
|
||||
VirtualFrame frame,
|
||||
Object receiver,
|
||||
@Cached("receiver.getClass()") @SuppressWarnings("unused") Class<?> cachedClass,
|
||||
@Cached("resolveProperty(receiver)") ClassProperty resolvedProperty,
|
||||
@Cached("resolveProperty(getOwner(frame), receiver)") ClassProperty resolvedProperty,
|
||||
@Cached("createCallNode(resolvedProperty)") DirectCallNode callNode) {
|
||||
|
||||
return callNode.call(receiver, resolvedProperty.getOwner(), resolvedProperty.getName());
|
||||
@@ -131,13 +136,13 @@ public abstract class ReadPropertyNode extends ExpressionNode {
|
||||
return value instanceof VmObjectLike objectLike ? objectLike.getClass() : null;
|
||||
}
|
||||
|
||||
protected ClassProperty resolveProperty(Object value) {
|
||||
protected ClassProperty resolveProperty(VmObjectLike owner, Object value) {
|
||||
var clazz = VmUtils.getClass(value);
|
||||
var propertyDef = clazz.getProperty(propertyName);
|
||||
if (propertyDef != null) return propertyDef;
|
||||
|
||||
CompilerDirectives.transferToInterpreter();
|
||||
throw cannotFindProperty(clazz.getPrototype());
|
||||
throw cannotFindProperty(owner, clazz.getPrototype());
|
||||
}
|
||||
|
||||
// This method should only be used for standard library properties implemented as nodes.
|
||||
@@ -147,10 +152,9 @@ public abstract class ReadPropertyNode extends ExpressionNode {
|
||||
}
|
||||
|
||||
@TruffleBoundary
|
||||
private VmException cannotFindProperty(VmObjectLike receiver) {
|
||||
private VmException cannotFindProperty(VmObjectLike owner, VmObjectLike receiver) {
|
||||
return exceptionBuilder()
|
||||
.cannotFindProperty(
|
||||
receiver, propertyName, true, lookupMode != MemberLookupMode.EXPLICIT_RECEIVER)
|
||||
.cannotFindProperty(receiver, owner, propertyName, true, lookupMode, getReceiverNode())
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -152,7 +152,7 @@ public final class FunctionNode extends RegularMemberNode {
|
||||
// this behavior needs to be overridden so the type arg check on return type still runs.
|
||||
// otherwise, this code would succeed instead of failing:
|
||||
// ```
|
||||
// res = List("foo", "hello", "a").map::<String>((it) -> it.length)
|
||||
// res = List("foo", "hello", "a").map<String>((it) -> it.length)
|
||||
// ```
|
||||
// Assumption: this does not need to account for type args in enclosing frames because
|
||||
// no type parameters exist in the stdlib that would require this.
|
||||
|
||||
@@ -2300,7 +2300,7 @@ public abstract class TypeNode extends PklNode {
|
||||
// e.g.
|
||||
// ```
|
||||
// function foo<T>(arg: T)
|
||||
// res = foo::<Person>(new {}) // `Person` is passed in via `typeArgumentOverrides`
|
||||
// res = foo<Person>(new {}) // `Person` is passed in via `typeArgumentOverrides`
|
||||
// ```
|
||||
if (levelsUp == 0 && isPreCall) {
|
||||
return typeArgumentOverrides == null ? null : typeArgumentOverrides[typeParameter.index()];
|
||||
|
||||
@@ -18,6 +18,8 @@ package org.pkl.core.runtime;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.pkl.core.ast.MemberLookupMode;
|
||||
import org.pkl.core.ast.PklNode;
|
||||
import org.pkl.core.ast.member.ClassMethod;
|
||||
import org.pkl.core.ast.member.Member;
|
||||
import org.pkl.core.runtime.MemberLookupSuggestions.Candidate.Kind;
|
||||
@@ -30,7 +32,8 @@ public final class MemberLookupSuggestions {
|
||||
// names that differ in their first character similar
|
||||
private static final double SIMILARITY_THRESHOLD = 0.77;
|
||||
|
||||
private final VmObjectLike composite;
|
||||
private final VmObjectLike receiver;
|
||||
private final VmObjectLike owner;
|
||||
private final Object memberName;
|
||||
// -1 for property, #arguments for function
|
||||
private final int memberArity;
|
||||
@@ -39,8 +42,13 @@ public final class MemberLookupSuggestions {
|
||||
private final Set<Candidate> candidates = new LinkedHashSet<>();
|
||||
|
||||
public MemberLookupSuggestions(
|
||||
VmObjectLike composite, Object memberName, int memberArity, Set<Candidate.Kind> memberKinds) {
|
||||
this.composite = composite;
|
||||
VmObjectLike receiver,
|
||||
VmObjectLike owner,
|
||||
Object memberName,
|
||||
int memberArity,
|
||||
Set<Kind> memberKinds) {
|
||||
this.receiver = receiver;
|
||||
this.owner = owner;
|
||||
this.memberName = memberName;
|
||||
this.memberArity = memberArity;
|
||||
this.memberKinds = memberKinds;
|
||||
@@ -49,45 +57,76 @@ public final class MemberLookupSuggestions {
|
||||
// use same search order as in member lookup,
|
||||
// so that in case of members with same name,
|
||||
// (only) the correct one is suggested
|
||||
public List<Candidate> find(boolean isImplicitReceiver) {
|
||||
public List<Candidate> find(MemberLookupMode memberLookupMode, @Nullable PklNode receiverNode) {
|
||||
candidates.clear();
|
||||
|
||||
if (isImplicitReceiver) {
|
||||
for (var curr = composite; curr != null; curr = curr.getEnclosingOwner()) {
|
||||
addPropertyCandidates(curr, true);
|
||||
if (memberLookupMode.isImplicitReceiver()) {
|
||||
for (var curr = receiver; curr != null; curr = curr.getEnclosingOwner()) {
|
||||
addPropertyCandidates(curr, true, memberLookupMode, receiverNode);
|
||||
if (curr.isPrototype()) {
|
||||
addMethodCandidates(curr.getVmClass().getDeclaredMethods(), true);
|
||||
addMethodCandidates(
|
||||
curr.getVmClass().getDeclaredMethods(), true, memberLookupMode, receiverNode);
|
||||
}
|
||||
}
|
||||
addPropertyCandidates(BaseModule.getModule(), false);
|
||||
addMethodCandidates(BaseModule.getModule().getVmClass().getMethods(), false);
|
||||
// if we resolved to implicit `this` at parse time, try searching the lexical scope of the
|
||||
// owner too.
|
||||
for (var curr = owner; curr != null; curr = curr.getEnclosingOwner()) {
|
||||
addPropertyCandidates(curr, true, memberLookupMode, receiverNode);
|
||||
if (curr.isPrototype()) {
|
||||
addMethodCandidates(
|
||||
curr.getVmClass().getDeclaredMethods(), true, memberLookupMode, receiverNode);
|
||||
}
|
||||
}
|
||||
addPropertyCandidates(BaseModule.getModule(), false, memberLookupMode, receiverNode);
|
||||
addMethodCandidates(
|
||||
BaseModule.getModule().getVmClass().getMethods(), false, memberLookupMode, receiverNode);
|
||||
}
|
||||
|
||||
for (var curr = composite; curr != null; curr = curr.getParent()) {
|
||||
addPropertyCandidates(curr, false);
|
||||
for (var curr = receiver; curr != null; curr = curr.getParent()) {
|
||||
addPropertyCandidates(curr, false, memberLookupMode, receiverNode);
|
||||
}
|
||||
addMethodCandidates(composite.getVmClass().getMethods(), false);
|
||||
addMethodCandidates(receiver.getVmClass().getMethods(), false, memberLookupMode, receiverNode);
|
||||
|
||||
return candidates.stream().sorted(Comparator.naturalOrder()).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private void addPropertyCandidates(VmObjectLike object, boolean includeLocal) {
|
||||
private void addPropertyCandidates(
|
||||
VmObjectLike object,
|
||||
boolean includeLocal,
|
||||
MemberLookupMode memberLookupMode,
|
||||
@Nullable PklNode receiverNode) {
|
||||
if (!memberKinds.contains(Kind.PROPERTY)) return;
|
||||
|
||||
for (var member : EconomicMaps.getValues(object.getMembers())) {
|
||||
addIfSimilar(member, Candidate.Kind.PROPERTY, -1, includeLocal);
|
||||
addIfSimilar(
|
||||
member, Candidate.Kind.PROPERTY, -1, includeLocal, memberLookupMode, receiverNode);
|
||||
}
|
||||
}
|
||||
|
||||
private void addMethodCandidates(Iterable<ClassMethod> methods, boolean includeLocal) {
|
||||
private void addMethodCandidates(
|
||||
Iterable<ClassMethod> methods,
|
||||
boolean includeLocal,
|
||||
MemberLookupMode memberLookupMode,
|
||||
@Nullable PklNode receiverNode) {
|
||||
if (!memberKinds.contains(Kind.METHOD)) return;
|
||||
|
||||
for (var method : methods) {
|
||||
addIfSimilar(method, Candidate.Kind.METHOD, method.getParameterCount(), includeLocal);
|
||||
addIfSimilar(
|
||||
method,
|
||||
Candidate.Kind.METHOD,
|
||||
method.getParameterCount(),
|
||||
includeLocal,
|
||||
memberLookupMode,
|
||||
receiverNode);
|
||||
}
|
||||
}
|
||||
|
||||
private void addIfSimilar(Member member, Candidate.Kind kind, int arity, boolean includeLocal) {
|
||||
private void addIfSimilar(
|
||||
Member member,
|
||||
Kind kind,
|
||||
int arity,
|
||||
boolean includeLocal,
|
||||
MemberLookupMode memberLookupMode,
|
||||
@Nullable PklNode receiverNode) {
|
||||
|
||||
var memberName = member.getNameOrNull();
|
||||
if (memberName == null) return;
|
||||
@@ -99,15 +138,26 @@ public final class MemberLookupSuggestions {
|
||||
var arityDifference = Math.abs(arity - memberArity);
|
||||
var signature = member.getCallSignature();
|
||||
assert signature != null;
|
||||
var nameWithReceiver = memberName.toString();
|
||||
// `receiverNode` is not necessarily null; we use `MemberLookupMode.EXPLICIT_RECEIVER`
|
||||
// in places that are not property/method calls, e.g.
|
||||
// `org.pkl.core.ast.expression.literal.SpecializedObjectLiteralNode.checkIsValidTypedAmendment`
|
||||
if (memberLookupMode == MemberLookupMode.EXPLICIT_RECEIVER && receiverNode != null) {
|
||||
nameWithReceiver =
|
||||
receiverNode.getSourceSection().getCharacters().toString() + "." + memberName;
|
||||
} else if (memberLookupMode == MemberLookupMode.EXPLICIT_SUPER) {
|
||||
nameWithReceiver = "super." + memberName;
|
||||
}
|
||||
if (nameSimilarity < 1 || memberArity == 0) {
|
||||
candidates.add(
|
||||
new Candidate(
|
||||
kind, memberName.toString(), signature, nameSimilarity, arityDifference));
|
||||
kind, memberName, nameWithReceiver, signature, nameSimilarity, arityDifference));
|
||||
} else if (nameSimilarity == 1 && memberArity >= 0) {
|
||||
candidates.add(
|
||||
new Candidate(
|
||||
kind,
|
||||
memberName.toString(),
|
||||
memberName,
|
||||
nameWithReceiver,
|
||||
signature + ".apply(...)",
|
||||
nameSimilarity,
|
||||
arityDifference));
|
||||
@@ -116,22 +166,14 @@ public final class MemberLookupSuggestions {
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Candidate implements Comparable<Candidate> {
|
||||
private final Kind kind;
|
||||
private final String name;
|
||||
private final String callSignature;
|
||||
private final double nameSimilarity;
|
||||
private final int arityDifference;
|
||||
|
||||
public Candidate(
|
||||
Kind kind, String name, String callSignature, double nameSimilarity, int arityDifference) {
|
||||
this.kind = kind;
|
||||
this.name = name;
|
||||
this.callSignature = callSignature;
|
||||
this.nameSimilarity = nameSimilarity;
|
||||
this.arityDifference = arityDifference;
|
||||
}
|
||||
|
||||
public record Candidate(
|
||||
Kind kind,
|
||||
Identifier memberName,
|
||||
String memberNameWithReceiver,
|
||||
String callSignature,
|
||||
double nameSimilarity,
|
||||
int arityDifference)
|
||||
implements Comparable<Candidate> {
|
||||
// note: not consistent with equals (hence cannot use TreeSet)
|
||||
@Override
|
||||
public int compareTo(Candidate other) {
|
||||
@@ -146,12 +188,12 @@ public final class MemberLookupSuggestions {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof Candidate other)) return false;
|
||||
// member lookup is name rather than signature based (but distinguishes kind)
|
||||
return kind == other.kind && name.equals(other.name);
|
||||
return kind == other.kind && memberNameWithReceiver.equals(other.memberNameWithReceiver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return kind.hashCode() * 31 + name.hashCode();
|
||||
return kind.hashCode() * 31 + memberNameWithReceiver.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -24,6 +24,8 @@ import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.pkl.core.StackFrame;
|
||||
import org.pkl.core.ast.MemberLookupMode;
|
||||
import org.pkl.core.ast.PklNode;
|
||||
import org.pkl.core.runtime.MemberLookupSuggestions.Candidate.Kind;
|
||||
import org.pkl.core.runtime.VmException.ProgramValue;
|
||||
import org.pkl.core.util.AnsiStringBuilder;
|
||||
@@ -137,7 +139,8 @@ public final class VmExceptionBuilder {
|
||||
|
||||
public VmExceptionBuilder cannotFindMember(VmObjectLike receiver, Object memberKey) {
|
||||
if (memberKey instanceof Identifier identifier) {
|
||||
return cannotFindProperty(receiver, identifier, true, false);
|
||||
return cannotFindProperty(
|
||||
receiver, receiver, identifier, true, MemberLookupMode.EXPLICIT_RECEIVER, null);
|
||||
}
|
||||
if (memberKey instanceof String string) {
|
||||
var candidates = KeyLookupSuggestions.forObject(receiver, string);
|
||||
@@ -153,19 +156,21 @@ public final class VmExceptionBuilder {
|
||||
|
||||
public VmExceptionBuilder cannotFindProperty(
|
||||
VmObjectLike receiver,
|
||||
VmObjectLike owner,
|
||||
Identifier propertyName,
|
||||
// true -> property read, false -> property definition
|
||||
boolean isRead,
|
||||
boolean isImplicitReceiver) {
|
||||
MemberLookupMode memberLookupMode,
|
||||
@Nullable PklNode receiverNode) {
|
||||
|
||||
var memberKinds = isRead ? EnumSet.allOf(Kind.class) : EnumSet.of(Kind.PROPERTY);
|
||||
|
||||
var candidates =
|
||||
new MemberLookupSuggestions(receiver, propertyName, -1, memberKinds)
|
||||
.find(isImplicitReceiver);
|
||||
new MemberLookupSuggestions(receiver, owner, propertyName, -1, memberKinds)
|
||||
.find(memberLookupMode, receiverNode);
|
||||
|
||||
if (candidates.isEmpty()) {
|
||||
if (isImplicitReceiver) {
|
||||
if (memberLookupMode.isImplicitReceiver()) {
|
||||
// probably wouldn't be useful to list all members in scope (includes all pkl.base members)
|
||||
evalError("cannotFindPropertyInScope", propertyName);
|
||||
} else if (receiver.isModuleObject()) {
|
||||
@@ -183,7 +188,7 @@ public final class VmExceptionBuilder {
|
||||
propertyNames.isEmpty() ? "(none)" : new MultilineValue(propertyNames));
|
||||
}
|
||||
} else {
|
||||
if (isImplicitReceiver) {
|
||||
if (memberLookupMode.isImplicitReceiver()) {
|
||||
evalError(
|
||||
"cannotFindPropertyInScopeListCandidates",
|
||||
propertyName,
|
||||
@@ -208,14 +213,20 @@ public final class VmExceptionBuilder {
|
||||
|
||||
// `foo.bar()`
|
||||
public VmExceptionBuilder cannotFindMethod(
|
||||
VmObjectLike receiver, Identifier methodName, int arity, boolean isImplicitReceiver) {
|
||||
VmObjectLike receiver,
|
||||
VmObjectLike owner,
|
||||
Identifier methodName,
|
||||
int arity,
|
||||
MemberLookupMode memberLookupMode,
|
||||
boolean hasTypeArgs,
|
||||
@Nullable PklNode receiverNode) {
|
||||
|
||||
var candidates =
|
||||
new MemberLookupSuggestions(receiver, methodName, arity, EnumSet.allOf(Kind.class))
|
||||
.find(isImplicitReceiver);
|
||||
new MemberLookupSuggestions(receiver, owner, methodName, arity, EnumSet.allOf(Kind.class))
|
||||
.find(memberLookupMode, receiverNode);
|
||||
|
||||
if (candidates.isEmpty()) {
|
||||
if (isImplicitReceiver) {
|
||||
if (memberLookupMode.isImplicitReceiver()) {
|
||||
// probably not useful to list all members in scope (includes all pkl.base members)
|
||||
evalError("cannotFindMethodInScope", methodName);
|
||||
} else if (receiver.isModuleObject()) {
|
||||
@@ -232,7 +243,15 @@ public final class VmExceptionBuilder {
|
||||
new MultilineValue(collectMethodNames(receiver.getVmClass())));
|
||||
}
|
||||
} else {
|
||||
if (isImplicitReceiver) {
|
||||
var exactPropertyMatch =
|
||||
candidates.stream()
|
||||
.filter((it) -> it.nameSimilarity() == 1 && it.kind() == Kind.PROPERTY)
|
||||
.findFirst();
|
||||
if (hasTypeArgs && exactPropertyMatch.isPresent()) {
|
||||
var candidate = exactPropertyMatch.get();
|
||||
evalError(
|
||||
"cannotFindMethodMaybeComparisonExpr", methodName, candidate.memberNameWithReceiver());
|
||||
} else if (memberLookupMode.isImplicitReceiver()) {
|
||||
evalError(
|
||||
"cannotFindMethodInScopeListCandidates", methodName, new MultilineValue(candidates));
|
||||
} else if (receiver.isModuleObject()) {
|
||||
|
||||
@@ -21,7 +21,7 @@ import java.util.Arrays;
|
||||
/**
|
||||
* The Jaro–Winkler distance metric is designed and best suited for short strings such as person
|
||||
* names, and to detect typos; it is (roughly) a variation of Damerau-Levenshtein, where the
|
||||
* substitution of 2 close characters is considered less important then the substitution of 2
|
||||
* substitution of 2 close characters is considered less important than the substitution of 2
|
||||
* characters that a far from each other. Jaro-Winkler was developed in the area of record linkage
|
||||
* (duplicate detection) (Winkler, 1990). It returns a value in the interval [0.0, 1.0]. The
|
||||
* distance is computed as 1 - Jaro-Winkler similarity.
|
||||
|
||||
@@ -419,6 +419,14 @@ Cannot reference property `{0}` because it is defined inside external class `{1}
|
||||
cannotFindMethodInScope=\
|
||||
Cannot find method `{0}`.
|
||||
|
||||
cannotFindMethodMaybeComparisonExpr=\
|
||||
Cannot find method `{0}`.\n\
|
||||
\n\
|
||||
This code is interpreted as a method call with type arguments.\n\
|
||||
If you meant to write a comparison expression instead, wrap the left-hand side with parentheses:\n\
|
||||
\n\
|
||||
({1}) < ...
|
||||
|
||||
cannotFindMethodInScopeListCandidates=\
|
||||
Cannot find method `{0}`.\n\
|
||||
\n\
|
||||
|
||||
@@ -30,8 +30,8 @@ facts {
|
||||
isVerbose = false
|
||||
}.run()
|
||||
|
||||
run::<Int>().iterations == 3
|
||||
run::<String>().iterations == 3
|
||||
run<Int>().iterations == 3
|
||||
run<String>().iterations == 3
|
||||
}
|
||||
|
||||
["run output benchmark (in verbose mode)"] {
|
||||
|
||||
@@ -17,11 +17,11 @@ class D extends ref.AbstractDomain {
|
||||
|
||||
local const d: D = new {}
|
||||
typealias Ref<T> = ref.Reference<D, T>
|
||||
const function Ref<T>(data: Any): Ref<T> = ref.Reference::<D, T>(d, data)
|
||||
const function Ref<T>(data: Any): Ref<T> = ref.Reference<D, T>(d, data)
|
||||
|
||||
abstract class Resource {
|
||||
name: String
|
||||
hidden fixed $: Ref<this> = Ref::<this>(this)
|
||||
hidden fixed $: Ref<this> = Ref<this>(this)
|
||||
}
|
||||
|
||||
class A extends Resource {
|
||||
@@ -123,32 +123,32 @@ kInterpolation = "\(k)"
|
||||
aValuesJoined = k.aValues.join("\n")
|
||||
|
||||
// ensure that type arguments that are unions are handled correctly
|
||||
typeArgs = Ref::<TypeHolder>(null).prop as Ref<Listing<Number | Boolean | String>>
|
||||
typeArgs = Ref<TypeHolder>(null).prop as Ref<Listing<Number | Boolean | String>>
|
||||
class TypeHolder {
|
||||
prop: Listing<String | Boolean | Number>
|
||||
mappingAnyKey: Mapping<Any, Int>
|
||||
mappingTypeArgKey: Mapping<Listing<Int>, Int>
|
||||
}
|
||||
typeArgs2 = Ref::<Listing<Number | Boolean | String>>(null) as Ref<Listing<Number | Boolean | String>>
|
||||
typeArgs2 = Ref<Listing<Number | Boolean | String>>(null) as Ref<Listing<Number | Boolean | String>>
|
||||
|
||||
class BadResource extends Resource {
|
||||
// return a reference with referent that isn't `this`
|
||||
fixed $ = Ref::<A>(this)
|
||||
fixed $ = Ref<A>(this)
|
||||
}
|
||||
|
||||
badThisRef = test.catch(() -> new BadResource { name = "bad" }.$.toString())
|
||||
|
||||
// test that a bare function type toStrings/exports okay
|
||||
bareFunctionType = test.catch(() -> ref.Reference::<D, Function4>(d, null) as Ref<String>)
|
||||
bareFunctionType = test.catch(() -> ref.Reference<D, Function4>(d, null) as Ref<String>)
|
||||
|
||||
// test for allowing constraints during reference construction
|
||||
constraintInConstructor = Ref::<String(length > 5)>(null)
|
||||
constraintInConstructor = Ref<String(length > 5)>(null)
|
||||
|
||||
mappingAnyKey = Ref::<TypeHolder>(null).mappingAnyKey["foo"]
|
||||
mappingAnyKey = Ref<TypeHolder>(null).mappingAnyKey["foo"]
|
||||
|
||||
// this one should be an editor error but can't be caught in the runtime
|
||||
// because VmListing/VmMapping don't track their type args
|
||||
mappingTypeArgKey = Ref ::<TypeHolder>(null).mappingTypeArgKey[new Listing<String> { "foo" }]
|
||||
mappingTypeArgKey = Ref<TypeHolder>(null).mappingTypeArgKey[new Listing<String> { "foo" }]
|
||||
|
||||
output {
|
||||
renderer {
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ hidden children: List<module>
|
||||
|
||||
typealias R = ref.Reference<D, referenceWithFinalModuleType?>
|
||||
|
||||
res0 = ref.Reference::<D, module>(new D {}, null)
|
||||
res0 = ref.Reference<D, module>(new D {}, null)
|
||||
res1: R = res0.parent
|
||||
res2: R = res0.parent.parent
|
||||
res3: R = res0.children[0]
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ hidden children: List<module>
|
||||
|
||||
typealias R = ref.Reference<D, referenceWithOpenModuleType?>
|
||||
|
||||
res0 = ref.Reference::<D, module>(new D {}, null)
|
||||
res0 = ref.Reference<D, module>(new D {}, null)
|
||||
res1: R = res0.parent
|
||||
res2: R = res0.parent.parent
|
||||
res3: R = res0.children[0]
|
||||
|
||||
+2
-2
@@ -22,14 +22,14 @@ open class Node2 {
|
||||
typealias R = ref.Reference<D, Node?>
|
||||
typealias R2 = ref.Reference<D, Node2?>
|
||||
|
||||
res0: R = ref.Reference::<D, Node>(new D {}, null)
|
||||
res0: R = ref.Reference<D, Node>(new D {}, null)
|
||||
res1: R = res0.parent
|
||||
res2: R = res0.parent.parent
|
||||
res3: R = res0.children[0]
|
||||
res4: R = res0.children[0].parent
|
||||
res5: R = res0.children[0].children[0]
|
||||
|
||||
res0a: R2 = ref.Reference::<D, Node2>(new D {}, null)
|
||||
res0a: R2 = ref.Reference<D, Node2>(new D {}, null)
|
||||
res1a: R2 = res0a.parent
|
||||
res2a: R2 = res0a.parent.parent
|
||||
res3a: R2 = res0a.children[0]
|
||||
|
||||
@@ -25,9 +25,9 @@ local class OtherHolder {
|
||||
constrainedType: String(isEmpty)
|
||||
}
|
||||
|
||||
local holderRef: Ref<Holder> = ref.Reference::<D, Holder>(d, null)
|
||||
local holderRef2: Ref<Holder> = ref.Reference::<D, Holder>(d, null)
|
||||
local otherHolderRef: Ref<OtherHolder> = ref.Reference::<D, OtherHolder>(d, null)
|
||||
local holderRef: Ref<Holder> = ref.Reference<D, Holder>(d, null)
|
||||
local holderRef2: Ref<Holder> = ref.Reference<D, Holder>(d, null)
|
||||
local otherHolderRef: Ref<OtherHolder> = ref.Reference<D, OtherHolder>(d, null)
|
||||
|
||||
facts {
|
||||
["equality"] {
|
||||
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
abstract class Base {
|
||||
prop = 10
|
||||
}
|
||||
|
||||
class Child extends Base {
|
||||
result = prop < foo > (1)
|
||||
}
|
||||
|
||||
result = new Child {}.result
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
abstract class Base {
|
||||
prop = 10
|
||||
}
|
||||
|
||||
class Child extends Base {
|
||||
result = super.prop < foo > (1)
|
||||
}
|
||||
|
||||
result = new Child {}.result
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
abstract class Base {
|
||||
prop = 10
|
||||
}
|
||||
|
||||
class Child extends Base {
|
||||
local self = this
|
||||
|
||||
result = self.prop < foo > (1)
|
||||
}
|
||||
|
||||
result = new Child {}.result
|
||||
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
// `fooz` and `fool` both fit the string similarity threshold,
|
||||
// but `fooz` is an exact match. So, still show the specialized error
|
||||
// message about comparisons instead of generic method call
|
||||
fooz = true
|
||||
|
||||
fool = false
|
||||
|
||||
res {
|
||||
fooz < bar > (fool)
|
||||
}
|
||||
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
fooz = true
|
||||
|
||||
fool = false
|
||||
|
||||
class Foo {
|
||||
prop1: Int
|
||||
prop2: Int
|
||||
prop3: Int
|
||||
qux: Boolean
|
||||
}
|
||||
|
||||
res {
|
||||
// exercise super long receivers
|
||||
new Foo {
|
||||
prop1 = 1
|
||||
prop2 = 2
|
||||
prop3 = 3
|
||||
}.qux < bar > (fool)
|
||||
}
|
||||
@@ -6,4 +6,4 @@ class D extends ref.AbstractDomain {
|
||||
local d: D = new {}
|
||||
typealias Ref<T> = ref.Reference<D, T>
|
||||
|
||||
test = ref.Reference::<D, String>(d, "") as Ref<Int>
|
||||
test = ref.Reference<D, String>(d, "") as Ref<Int>
|
||||
@@ -5,4 +5,4 @@ class D extends ref.AbstractDomain {
|
||||
}
|
||||
local d: D = new {}
|
||||
|
||||
test = ref.Reference::<D, Mapping>(d, "").default
|
||||
test = ref.Reference<D, Mapping>(d, "").default
|
||||
@@ -5,4 +5,4 @@ class D extends ref.AbstractDomain {
|
||||
}
|
||||
local d: D = new {}
|
||||
|
||||
test = ref.Reference::<D, Listing>(d, "").default
|
||||
test = ref.Reference<D, Listing>(d, "").default
|
||||
@@ -5,4 +5,4 @@ class D extends ref.AbstractDomain {
|
||||
}
|
||||
local d: D = new {}
|
||||
|
||||
test = ref.Reference::<D, Dynamic>(d, "").default
|
||||
test = ref.Reference<D, Dynamic>(d, "").default
|
||||
@@ -7,4 +7,4 @@ class D extends ref.AbstractDomain {
|
||||
}
|
||||
local d: D = new {}
|
||||
|
||||
test = ref.Reference::<D, ReferencedModule>(d, "").output
|
||||
test = ref.Reference<D, ReferencedModule>(d, "").output
|
||||
@@ -7,4 +7,4 @@ class D extends ref.AbstractDomain {
|
||||
}
|
||||
local d: D = new {}
|
||||
|
||||
test = ref.Reference::<D, ReferencedModuleWithOutputOverride>(d, "").output
|
||||
test = ref.Reference<D, ReferencedModuleWithOutputOverride>(d, "").output
|
||||
@@ -9,4 +9,4 @@ class D extends ref.AbstractDomain {
|
||||
}
|
||||
local d: D = new {}
|
||||
|
||||
test = ref.Reference::<D, ModuleSubclass>(d, "").output
|
||||
test = ref.Reference<D, ModuleSubclass>(d, "").output
|
||||
@@ -9,4 +9,4 @@ class D extends ref.AbstractDomain {
|
||||
}
|
||||
local d: D = new {}
|
||||
|
||||
test = ref.Reference::<D, A>(d, "").foo as ref.Reference<D, Int | Boolean>
|
||||
test = ref.Reference<D, A>(d, "").foo as ref.Reference<D, Int | Boolean>
|
||||
@@ -6,4 +6,4 @@ class D extends ref.AbstractDomain {
|
||||
local d: D = new {}
|
||||
typealias Ref<T> = ref.Reference<D, T>
|
||||
|
||||
test = ref.Reference::<D, String>(d, "") as Ref<Boolean | Int>
|
||||
test = ref.Reference<D, String>(d, "") as Ref<Boolean | Int>
|
||||
@@ -9,7 +9,7 @@ class D extends ref.AbstractDomain {
|
||||
}
|
||||
local d: D = new {}
|
||||
|
||||
local test = ref.Reference::<D, A>(d, "").foo
|
||||
local test = ref.Reference<D, A>(d, "").foo
|
||||
testInterpolation = "test:\(test)"
|
||||
|
||||
// this tests that the interpolation appears in the output when renderReference throws
|
||||
@@ -8,6 +8,6 @@ class Bird {
|
||||
name: String
|
||||
}
|
||||
|
||||
myRef: ref.Reference<D, Bird | Int> = ref.Reference::<D, Bird | Int>(new D {}, null)
|
||||
myRef: ref.Reference<D, Bird | Int> = ref.Reference<D, Bird | Int>(new D {}, null)
|
||||
|
||||
res = myRef.name
|
||||
@@ -4,6 +4,6 @@ class D extends ref.AbstractDomain {
|
||||
function renderReference(_): String = throw("not implemented")
|
||||
}
|
||||
|
||||
local myRef = ref.Reference::<D, Duration | Listing<String>>(new D {}, null)
|
||||
local myRef = ref.Reference<D, Duration | Listing<String>>(new D {}, null)
|
||||
|
||||
res = myRef[0]
|
||||
@@ -4,6 +4,6 @@ class D extends ref.AbstractDomain {
|
||||
function renderReference(_): String = throw("not implemented")
|
||||
}
|
||||
|
||||
local myRef = ref.Reference::<D, Listing>(new D {}, null)
|
||||
local myRef = ref.Reference<D, Listing>(new D {}, null)
|
||||
|
||||
res = myRef.name
|
||||
@@ -4,6 +4,6 @@ class D extends ref.AbstractDomain {
|
||||
function renderReference(_): String = throw("not implemented")
|
||||
}
|
||||
|
||||
local myRef = ref.Reference::<D, (Int) -> Boolean>(new D {}, null)
|
||||
local myRef = ref.Reference<D, (Int) -> Boolean>(new D {}, null)
|
||||
|
||||
res = myRef.name
|
||||
@@ -6,4 +6,4 @@ class D extends ref.AbstractDomain {
|
||||
local d: D = new {}
|
||||
typealias Ref<T> = ref.Reference<D, T>
|
||||
|
||||
test = ref.Reference::<D, String>(d, "") as Ref<Listing<String>>
|
||||
test = ref.Reference<D, String>(d, "") as Ref<Listing<String>>
|
||||
@@ -6,7 +6,7 @@ class D extends ref.AbstractDomain {
|
||||
local d: D = new {}
|
||||
typealias Ref<T> = ref.Reference<D, T>
|
||||
|
||||
test = ref.Reference::<D, String>(d, "") as Ref<Alias1>
|
||||
test = ref.Reference<D, String>(d, "") as Ref<Alias1>
|
||||
|
||||
typealias Alias1 = Int | Alias2
|
||||
typealias Alias2 = Boolean
|
||||
@@ -11,4 +11,4 @@ class D2 extends ref.AbstractDomain {
|
||||
}
|
||||
local d2: D2 = new {}
|
||||
|
||||
test = ref.Reference::<D2, String>(d2, "") as Ref<String>
|
||||
test = ref.Reference<D2, String>(d2, "") as Ref<String>
|
||||
@@ -10,4 +10,4 @@ class A {
|
||||
b: String
|
||||
}
|
||||
|
||||
test = ref.Reference::<D, String>(d, new A {}).c
|
||||
test = ref.Reference<D, String>(d, new A {}).c
|
||||
@@ -6,4 +6,4 @@ class D extends ref.AbstractDomain {
|
||||
local d: D = new {}
|
||||
typealias Ref<T> = ref.Reference<D, T>
|
||||
|
||||
test = ref.Reference::<D, List>(d, List())["hi"]
|
||||
test = ref.Reference<D, List>(d, List())["hi"]
|
||||
+29
-29
@@ -8,14 +8,14 @@ class Domain extends ref.AbstractDomain {
|
||||
}
|
||||
|
||||
directCall {
|
||||
pair = Pair::<List<String>, Set<String>>(List("foo"), Set("bar"))
|
||||
pairSelf = Pair::<module, module>(new module {}, new module {}).first.getClass().toString()
|
||||
pairErr = test.catch(() -> Pair::<List<String>, Set<String>>(List(0), Set("bar")))
|
||||
pairSelfErr = test.catch(() -> Pair::<module, module>(List(), new module {}))
|
||||
listMap = List("hi", "foo", "a").map::<Int>((it) -> it.length)
|
||||
listMapErr = test.catch(() -> List("hi", "foo", "a").map::<String>((it) -> it.length))
|
||||
wrongTypeArgCount = test.catch(() -> Pair::<String, Int, Boolean> ("foo", 10))
|
||||
nonGenericMethod = test.catch(() -> Regex::<String> ("foo"))
|
||||
pair = Pair<List<String>, Set<String>>(List("foo"), Set("bar"))
|
||||
pairSelf = Pair<module, module>(new module {}, new module {}).first.getClass().toString()
|
||||
pairErr = test.catch(() -> Pair<List<String>, Set<String>>(List(0), Set("bar")))
|
||||
pairSelfErr = test.catch(() -> Pair<module, module>(List(), new module {}))
|
||||
listMap = List("hi", "foo", "a").map<Int>((it) -> it.length)
|
||||
listMapErr = test.catch(() -> List("hi", "foo", "a").map<String>((it) -> it.length))
|
||||
wrongTypeArgCount = test.catch(() -> Pair<String, Int, Boolean> ("foo", 10))
|
||||
nonGenericMethod = test.catch(() -> Regex<String> ("foo"))
|
||||
}
|
||||
|
||||
open class A {
|
||||
@@ -23,12 +23,12 @@ open class A {
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
function doIt<T>(arg: List): Boolean = super.doIt::<T>(arg) || super.doIt::<List<T>>(arg)
|
||||
function doIt<T>(arg: List): Boolean = super.doIt<T>(arg) || super.doIt<List<T>>(arg)
|
||||
}
|
||||
|
||||
superCall {
|
||||
local function doIt(a: A, arg: List): Boolean =
|
||||
a.doIt::<String>(arg)
|
||||
a.doIt<String>(arg)
|
||||
|
||||
// should be true:
|
||||
doIt(new A {}, List(""))
|
||||
@@ -45,16 +45,16 @@ local num = 5
|
||||
|
||||
objectMethod {
|
||||
local function foo<T>(): T = "hi"
|
||||
res = test.catch(() -> foo::<String(length > num)>())
|
||||
res = test.catch(() -> foo<String(length > num)>())
|
||||
}
|
||||
|
||||
function lazy1<T>(it): Listing<T> = new Listing { it }
|
||||
local function lazy2<T>(it): Listing<T> = new Listing { it }
|
||||
lazyTypeCheck {
|
||||
local function lazy3<T>(it): Listing<T> = new Listing { it }
|
||||
res1 = test.catch(() -> lazy1::<String>(5))
|
||||
res2 = test.catch(() -> lazy2::<String>(5))
|
||||
res3 = test.catch(() -> lazy3::<String>(5))
|
||||
res1 = test.catch(() -> lazy1<String>(5))
|
||||
res2 = test.catch(() -> lazy2<String>(5))
|
||||
res3 = test.catch(() -> lazy3<String>(5))
|
||||
|
||||
eager {
|
||||
local myListing: Listing<String> = new { "Hello, world!" }
|
||||
@@ -62,7 +62,7 @@ lazyTypeCheck {
|
||||
result = myListing is T
|
||||
}
|
||||
// should be false:
|
||||
res = myFunc::<Listing<Duration>>().result
|
||||
res = myFunc<Listing<Duration>>().result
|
||||
}
|
||||
|
||||
closure {
|
||||
@@ -70,7 +70,7 @@ lazyTypeCheck {
|
||||
local function myFunc<T>() = new {
|
||||
result = myListing as T
|
||||
}
|
||||
res = test.catch(() -> myFunc::<Listing<Duration>>())
|
||||
res = test.catch(() -> myFunc<Listing<Duration>>())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,13 +86,13 @@ typeDefaults {
|
||||
new { name = val }
|
||||
}
|
||||
local function makeFromParam<T>(val: T): Listing<T> = new { val }
|
||||
res1 = makeNamed::<Person>("bob")
|
||||
res1 = makeNamed<Person>("bob")
|
||||
res1a = res1.getClass().toString()
|
||||
res2 = makeNamedListing::<Person>("bob")
|
||||
res2 = makeNamedListing<Person>("bob")
|
||||
res2a = res2.first.getClass().toString()
|
||||
res3 = makeFromParam::<Person>(new { name = "bob" })
|
||||
res3 = makeFromParam<Person>(new { name = "bob" })
|
||||
res3a = res3.first.getClass().toString()
|
||||
res3b = test.catch(() -> makeFromParam::<Person>(new Bird { name = "joe" }))
|
||||
res3b = test.catch(() -> makeFromParam<Person>(new Bird { name = "joe" }))
|
||||
}
|
||||
|
||||
class Bird {
|
||||
@@ -104,10 +104,10 @@ class Bird {
|
||||
polymorphism {
|
||||
// test that method type parameters are considered non-final
|
||||
local function make<T>(): T = new T { name = "fred" }
|
||||
res1 = make::<Person>()
|
||||
res2 = make::<Bird>()
|
||||
res1 = make<Person>()
|
||||
res2 = make<Bird>()
|
||||
|
||||
local function call(obj: Bird | Person) = obj.greet::<Int, String>()
|
||||
local function call(obj: Bird | Person) = obj.greet<Int, String>()
|
||||
res3 = call(new Person { name = "fred" })
|
||||
res4 = test.catch(() -> call(new Bird { name = "pigeon" }))
|
||||
res5 = call(new Person { name = "bob" })
|
||||
@@ -116,21 +116,21 @@ polymorphism {
|
||||
typeCast {
|
||||
local function cast<U>(l: Listing<Any>): Listing<U> = l
|
||||
|
||||
res1 = cast::<String(startsWith("Bob"))>(new Listing { "Bobbert" })
|
||||
res1 = cast<String(startsWith("Bob"))>(new Listing { "Bobbert" })
|
||||
|
||||
res2 = test.catch(() -> cast::<String(length > 10)>(res1).toString())
|
||||
res2 = test.catch(() -> cast<String(length > 10)>(res1).toString())
|
||||
}
|
||||
|
||||
constraintReadsFrameSlot {
|
||||
local function id<T>(x) = x is T
|
||||
local function f(n: Int) = id::<String(length > n)>("hi")
|
||||
local function f(n: Int) = id<String(length > n)>("hi")
|
||||
|
||||
res1 = f(1)
|
||||
res2 = let (n = 1) id::<String(length > n)>("hi")
|
||||
res3 = ((n) -> id::<String(length > n)>("hi")).apply(1)
|
||||
res2 = let (n = 1) id<String(length > n)>("hi")
|
||||
res3 = ((n) -> id<String(length > n)>("hi")).apply(1)
|
||||
res4 = new Listing {
|
||||
for (n in List(1)) {
|
||||
id::<String(length > n)>("hi")
|
||||
id<String(length > n)>("hi")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+14
-14
@@ -7,23 +7,23 @@ local function prefix4() = "hi"
|
||||
|
||||
class Bar {
|
||||
x: Int = 10
|
||||
function baz<T>(val): Boolean = foo::<T>(val)
|
||||
function qux<T>(val): Boolean = foo::<T(length < x)>(val)
|
||||
function baz<T>(val): Boolean = foo<T>(val)
|
||||
function qux<T>(val): Boolean = foo<T(length < x)>(val)
|
||||
}
|
||||
|
||||
res {
|
||||
res1a = foo::<String(startsWith(prefix1))>("high five")
|
||||
res1b = foo::<String(startsWith(prefix2))>("high five")
|
||||
res1c = foo::<String(startsWith(prefix3()))>("high five")
|
||||
res1d = foo::<String(startsWith(prefix4()))>("high five")
|
||||
res1a = foo<String(startsWith(prefix1))>("high five")
|
||||
res1b = foo<String(startsWith(prefix2))>("high five")
|
||||
res1c = foo<String(startsWith(prefix3()))>("high five")
|
||||
res1d = foo<String(startsWith(prefix4()))>("high five")
|
||||
|
||||
res2a = new Bar {}.baz::<String(startsWith(prefix1))>("high five")
|
||||
res2b = new Bar {}.baz::<String(startsWith(prefix2))>("high five")
|
||||
res2c = new Bar {}.baz::<String(startsWith(prefix3()))>("high five")
|
||||
res2d = new Bar {}.baz::<String(startsWith(prefix4()))>("high five")
|
||||
res2a = new Bar {}.baz<String(startsWith(prefix1))>("high five")
|
||||
res2b = new Bar {}.baz<String(startsWith(prefix2))>("high five")
|
||||
res2c = new Bar {}.baz<String(startsWith(prefix3()))>("high five")
|
||||
res2d = new Bar {}.baz<String(startsWith(prefix4()))>("high five")
|
||||
|
||||
res3a = new Bar {}.qux::<String(startsWith(prefix1))>("high five")
|
||||
res3b = new Bar {}.qux::<String(startsWith(prefix2))>("high five")
|
||||
res3c = new Bar {}.qux::<String(startsWith(prefix3()))>("high five")
|
||||
res3d = new Bar {}.qux::<String(startsWith(prefix4()))>("high five")
|
||||
res3a = new Bar {}.qux<String(startsWith(prefix1))>("high five")
|
||||
res3b = new Bar {}.qux<String(startsWith(prefix2))>("high five")
|
||||
res3c = new Bar {}.qux<String(startsWith(prefix3()))>("high five")
|
||||
res3d = new Bar {}.qux<String(startsWith(prefix4()))>("high five")
|
||||
}
|
||||
Vendored
+16
-16
@@ -15,13 +15,13 @@ class Person {
|
||||
|
||||
lexical {
|
||||
local function f<T>(): Dynamic = new { res = 5 as T }
|
||||
res1 = test.catch(() -> f::<String>().res)
|
||||
res1 = test.catch(() -> f<String>().res)
|
||||
|
||||
local function g<T>(): Dynamic = new {
|
||||
local myProp: T = 5
|
||||
res = myProp
|
||||
}
|
||||
res2 = test.catch(() -> g::<String>().res)
|
||||
res2 = test.catch(() -> g<String>().res)
|
||||
|
||||
local function nested<T>() = new Dynamic {
|
||||
local function inner<U>(x: Listing<T>, y: U) = x
|
||||
@@ -30,40 +30,40 @@ lexical {
|
||||
local function inner4<U>() = new Dynamic {
|
||||
local function innest1<V>(x: T, y: U, z: V) = x
|
||||
local function innest2(x: T) = x
|
||||
res1 = innest1::<String>(new { name = "x" }, 1, "hi")
|
||||
res1 = innest1<String>(new { name = "x" }, 1, "hi")
|
||||
res2 = innest1(new { name = "x" }, 1, "hi")
|
||||
res3 = test.catch(() -> innest2(1))
|
||||
}
|
||||
|
||||
res1 = inner::<Int>(new { new { name = "x" } }, 1)
|
||||
res2 = inner2::<Int>(new { name = "x" }, 1)
|
||||
res1 = inner<Int>(new { new { name = "x" } }, 1)
|
||||
res2 = inner2<Int>(new { name = "x" }, 1)
|
||||
res3 = inner(new { new { name = "x" } }, 1)
|
||||
res4 = inner2(new { name = "x" }, 1)
|
||||
res5 = test.catch(() -> inner3(1))
|
||||
nested = inner4::<Int>()
|
||||
nested = inner4<Int>()
|
||||
}
|
||||
nested = nested::<Person>()
|
||||
nested = nested<Person>()
|
||||
|
||||
inEagerScope {
|
||||
local function k1<T>() = new {
|
||||
[let (elem = "key" as T) elem] = "value"
|
||||
}
|
||||
test.catch(() -> k1::<Int>())
|
||||
test.catch(() -> k1<Int>())
|
||||
|
||||
local function k2<T>() = new {
|
||||
for (i in List(1, 2, 3)) {
|
||||
[let (elem = "key".repeat(i) as T) elem as T] = "value"
|
||||
}
|
||||
}
|
||||
k2::<String(length < 10)>()
|
||||
k2<String(length < 10)>()
|
||||
}
|
||||
|
||||
reify {
|
||||
local function makeMyObj<T>() = new {
|
||||
res = ref.Reference::<Domain, T>(new {}, null)
|
||||
res = ref.Reference<Domain, T>(new {}, null)
|
||||
}
|
||||
|
||||
res = makeMyObj::<Person>().res.name
|
||||
res = makeMyObj<Person>().res.name
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,18 +74,18 @@ local function nested<T>(foo) = new Dynamic {
|
||||
local function inner4<U>() = new Dynamic {
|
||||
local function innest1<V>(x: T, y: U, z: V) = x
|
||||
local function innest2(x: T) = x
|
||||
res1 = innest1::<String>(new { name = "x" }, 1, "hi")
|
||||
res1 = innest1<String>(new { name = "x" }, 1, "hi")
|
||||
res2 = innest1(new { name = "x" }, 1, "hi")
|
||||
res3 = test.catch(() -> innest2(1))
|
||||
}
|
||||
res1 = inner::<Int>(new { new { name = "x" } }, foo)
|
||||
res2 = inner2::<Int>(new { name = "x" }, 1)
|
||||
res1 = inner<Int>(new { new { name = "x" } }, foo)
|
||||
res2 = inner2<Int>(new { name = "x" }, 1)
|
||||
res3 = inner(new { new { name = "x" } }, 1)
|
||||
res4 = inner2(new { name = "x" }, 1)
|
||||
res5 = test.catch(() -> inner3(1))
|
||||
nested = inner4::<Int>()
|
||||
nested = inner4<Int>()
|
||||
}
|
||||
nested = nested::<Person>(1)
|
||||
nested = nested<Person>(1)
|
||||
|
||||
output {
|
||||
renderer {
|
||||
|
||||
pkl-core/src/test/files/LanguageSnippetTests/input/methods/callWithTypeArgumentsNestedWithOffset.pkl
Vendored
+2
-2
@@ -3,6 +3,6 @@
|
||||
local function make<T>(): Listing<T> = new Listing<T> { 1; 2 }
|
||||
local function amend<T, U>(l: Listing<Any>): Listing<U> = (l) { 3 } as Listing<U>
|
||||
|
||||
local parent = make::<Int>()
|
||||
local child = amend::<String, Int>(parent)
|
||||
local parent = make<Int>()
|
||||
local child = amend<String, Int>(parent)
|
||||
res = child[0]
|
||||
Vendored
+7
-7
@@ -1,18 +1,18 @@
|
||||
open class A {
|
||||
function foo<T, U, V>(val): List<Boolean> = List(val is T, val is U, val is V)
|
||||
function a<T, U>(val): List<Boolean> = this.foo::<T, U, this>(val)
|
||||
function a<T, U>(val): List<Boolean> = this.foo<T, U, this>(val)
|
||||
}
|
||||
|
||||
open class B extends A {
|
||||
function b1<T>(val): List<Boolean> = this.a::<T, this>(val)
|
||||
function b2<T>(val): List<Boolean> = super.a::<T, this>(val)
|
||||
function b1<T>(val): List<Boolean> = this.a<T, this>(val)
|
||||
function b2<T>(val): List<Boolean> = super.a<T, this>(val)
|
||||
}
|
||||
|
||||
class C extends B {
|
||||
function c1(val): List<Boolean> = this.b1::<this>(val)
|
||||
function c2(val): List<Boolean> = super.b1::<this>(val)
|
||||
function c3(val): List<Boolean> = this.b2::<this>(val)
|
||||
function c4(val): List<Boolean> = super.b2::<this>(val)
|
||||
function c1(val): List<Boolean> = this.b1<this>(val)
|
||||
function c2(val): List<Boolean> = super.b1<this>(val)
|
||||
function c3(val): List<Boolean> = this.b2<this>(val)
|
||||
function c4(val): List<Boolean> = super.b2<this>(val)
|
||||
}
|
||||
|
||||
resAaA = new A {}.a(new A {})
|
||||
|
||||
Vendored
+2
-2
@@ -1,5 +1,5 @@
|
||||
function foo<T>(bar) = bar as T
|
||||
|
||||
function baz<T>(qux) = foo::<List<T>>(qux)
|
||||
function baz<T>(qux) = foo<List<T>>(qux)
|
||||
|
||||
res = baz::<String(throw("oops"))>(List("a"))
|
||||
res = baz<String(throw("oops"))>(List("a"))
|
||||
Vendored
+1
-1
@@ -4,4 +4,4 @@ function bar<T>() = new {
|
||||
prop = foo as T
|
||||
}
|
||||
|
||||
res = bar::<Duration>()
|
||||
res = bar<Duration>()
|
||||
Vendored
+23
@@ -0,0 +1,23 @@
|
||||
–– Pkl Error ––
|
||||
Cannot find method `prop`.
|
||||
|
||||
x | result = prop < foo > (1)
|
||||
^^^^^^^^^^^^^^^^
|
||||
at functionNotFoundMaybeComparison#Child.result (file:///$snippetsDir/input/errors/functionNotFoundMaybeComparison.pkl)
|
||||
|
||||
This code is interpreted as a method call with type arguments.
|
||||
If you meant to write a comparison expression instead, wrap the left-hand side with parentheses:
|
||||
|
||||
(prop) < ...
|
||||
|
||||
x | result = new Child {}.result
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
at functionNotFoundMaybeComparison#result (file:///$snippetsDir/input/errors/functionNotFoundMaybeComparison.pkl)
|
||||
|
||||
xxx | renderer.renderDocument(value)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
at pkl.base#Module.output.text (pkl:base)
|
||||
|
||||
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||
^^^^
|
||||
at pkl.base#Module.output.bytes (pkl:base)
|
||||
Vendored
+23
@@ -0,0 +1,23 @@
|
||||
–– Pkl Error ––
|
||||
Cannot find method `prop`.
|
||||
|
||||
x | result = super.prop < foo > (1)
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
at functionNotFoundMaybeComparison2#Child.result (file:///$snippetsDir/input/errors/functionNotFoundMaybeComparison2.pkl)
|
||||
|
||||
This code is interpreted as a method call with type arguments.
|
||||
If you meant to write a comparison expression instead, wrap the left-hand side with parentheses:
|
||||
|
||||
(super.prop) < ...
|
||||
|
||||
x | result = new Child {}.result
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
at functionNotFoundMaybeComparison2#result (file:///$snippetsDir/input/errors/functionNotFoundMaybeComparison2.pkl)
|
||||
|
||||
xxx | renderer.renderDocument(value)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
at pkl.base#Module.output.text (pkl:base)
|
||||
|
||||
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||
^^^^
|
||||
at pkl.base#Module.output.bytes (pkl:base)
|
||||
Vendored
+23
@@ -0,0 +1,23 @@
|
||||
–– Pkl Error ––
|
||||
Cannot find method `prop`.
|
||||
|
||||
x | result = self.prop < foo > (1)
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
at functionNotFoundMaybeComparison3#Child.result (file:///$snippetsDir/input/errors/functionNotFoundMaybeComparison3.pkl)
|
||||
|
||||
This code is interpreted as a method call with type arguments.
|
||||
If you meant to write a comparison expression instead, wrap the left-hand side with parentheses:
|
||||
|
||||
(self.prop) < ...
|
||||
|
||||
xx | result = new Child {}.result
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
at functionNotFoundMaybeComparison3#result (file:///$snippetsDir/input/errors/functionNotFoundMaybeComparison3.pkl)
|
||||
|
||||
xxx | renderer.renderDocument(value)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
at pkl.base#Module.output.text (pkl:base)
|
||||
|
||||
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||
^^^^
|
||||
at pkl.base#Module.output.bytes (pkl:base)
|
||||
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
–– Pkl Error ––
|
||||
Cannot find method `fooz`.
|
||||
|
||||
x | fooz < bar > (fool)
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
at functionNotFoundMaybeComparison4#res[#1] (file:///$snippetsDir/input/errors/functionNotFoundMaybeComparison4.pkl)
|
||||
|
||||
This code is interpreted as a method call with type arguments.
|
||||
If you meant to write a comparison expression instead, wrap the left-hand side with parentheses:
|
||||
|
||||
(fooz) < ...
|
||||
|
||||
xxx | renderer.renderDocument(value)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
at pkl.base#Module.output.text (pkl:base)
|
||||
|
||||
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||
^^^^
|
||||
at pkl.base#Module.output.bytes (pkl:base)
|
||||
Vendored
+23
@@ -0,0 +1,23 @@
|
||||
–– Pkl Error ––
|
||||
Cannot find method `qux`.
|
||||
|
||||
xx | new Foo {
|
||||
^^^^^^^^^
|
||||
at functionNotFoundMaybeComparison5#res[#1] (file:///$snippetsDir/input/errors/functionNotFoundMaybeComparison5.pkl)
|
||||
|
||||
This code is interpreted as a method call with type arguments.
|
||||
If you meant to write a comparison expression instead, wrap the left-hand side with parentheses:
|
||||
|
||||
(new Foo {
|
||||
prop1 = 1
|
||||
prop2 = 2
|
||||
prop3 = 3
|
||||
}.qux) < ...
|
||||
|
||||
xxx | renderer.renderDocument(value)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
at pkl.base#Module.output.text (pkl:base)
|
||||
|
||||
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||
^^^^
|
||||
at pkl.base#Module.output.bytes (pkl:base)
|
||||
@@ -6,8 +6,8 @@ x | typealias Ref<T> = ref.Reference<D, T>
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
at reference1#test (file:///$snippetsDir/input/errors/reference1.pkl)
|
||||
|
||||
x | test = ref.Reference::<D, String>(d, "") as Ref<Int>
|
||||
^^^^^^^^
|
||||
x | test = ref.Reference<D, String>(d, "") as Ref<Int>
|
||||
^^^^^^^^
|
||||
at reference1#test (file:///$snippetsDir/input/errors/reference1.pkl)
|
||||
|
||||
xxx | renderer.renderDocument(value)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
–– Pkl Error ––
|
||||
Cannot find property `default` in object of type `pkl.ref#Reference<reference13#D, Mapping>`.
|
||||
|
||||
x | test = ref.Reference::<D, Mapping>(d, "").default
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
x | test = ref.Reference<D, Mapping>(d, "").default
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
at reference13#test (file:///$snippetsDir/input/errors/reference13.pkl)
|
||||
|
||||
Cannot reference property `default` in class `Mapping`.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
–– Pkl Error ––
|
||||
Cannot find property `default` in object of type `pkl.ref#Reference<reference14#D, Listing>`.
|
||||
|
||||
x | test = ref.Reference::<D, Listing>(d, "").default
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
x | test = ref.Reference<D, Listing>(d, "").default
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
at reference14#test (file:///$snippetsDir/input/errors/reference14.pkl)
|
||||
|
||||
Cannot reference property `default` in class `Listing`.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
–– Pkl Error ––
|
||||
Cannot find property `default` in object of type `pkl.ref#Reference<reference15#D, Dynamic>`.
|
||||
|
||||
x | test = ref.Reference::<D, Dynamic>(d, "").default
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
x | test = ref.Reference<D, Dynamic>(d, "").default
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
at reference15#test (file:///$snippetsDir/input/errors/reference15.pkl)
|
||||
|
||||
Cannot reference property `default` in class `Dynamic`.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
–– Pkl Error ––
|
||||
Cannot find property `output` in object of type `pkl.ref#Reference<reference16#D, ReferencedModule>`.
|
||||
|
||||
xx | test = ref.Reference::<D, ReferencedModule>(d, "").output
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
xx | test = ref.Reference<D, ReferencedModule>(d, "").output
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
at reference16#test (file:///$snippetsDir/input/errors/reference16.pkl)
|
||||
|
||||
Cannot reference property `output` because it is defined inside external class `Module`.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
–– Pkl Error ––
|
||||
Cannot find property `output` in object of type `pkl.ref#Reference<reference17#D, ReferencedModuleWithOutputOverride>`.
|
||||
|
||||
xx | test = ref.Reference::<D, ReferencedModuleWithOutputOverride>(d, "").output
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
xx | test = ref.Reference<D, ReferencedModuleWithOutputOverride>(d, "").output
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
at reference17#test (file:///$snippetsDir/input/errors/reference17.pkl)
|
||||
|
||||
Cannot reference property `output` because it is defined inside external class `Module`.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
–– Pkl Error ––
|
||||
Cannot find property `output` in object of type `pkl.ref#Reference<reference18#D, reference18#ModuleSubclass>`.
|
||||
|
||||
xx | test = ref.Reference::<D, ModuleSubclass>(d, "").output
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
xx | test = ref.Reference<D, ModuleSubclass>(d, "").output
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
at reference18#test (file:///$snippetsDir/input/errors/reference18.pkl)
|
||||
|
||||
Cannot reference property `output` because it is defined inside external class `Module`.
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
Expected value of type `pkl.ref#Reference<reference19#D, Int | Boolean>`, but got type `pkl.ref#Reference<reference19#D, Boolean | Int | String>`.
|
||||
Value: Reference(new reference19#D {}, Boolean | Int | String, "").foo
|
||||
|
||||
xx | test = ref.Reference::<D, A>(d, "").foo as ref.Reference<D, Int | Boolean>
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
xx | test = ref.Reference<D, A>(d, "").foo as ref.Reference<D, Int | Boolean>
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
at reference19#test (file:///$snippetsDir/input/errors/reference19.pkl)
|
||||
|
||||
xxx | renderer.renderDocument(value)
|
||||
|
||||
@@ -6,8 +6,8 @@ x | typealias Ref<T> = ref.Reference<D, T>
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
at reference2#test (file:///$snippetsDir/input/errors/reference2.pkl)
|
||||
|
||||
x | test = ref.Reference::<D, String>(d, "") as Ref<Boolean | Int>
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
x | test = ref.Reference<D, String>(d, "") as Ref<Boolean | Int>
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
at reference2#test (file:///$snippetsDir/input/errors/reference2.pkl)
|
||||
|
||||
xxx | renderer.renderDocument(value)
|
||||
|
||||
@@ -6,8 +6,8 @@ x | typealias Ref<T> = ref.Reference<D, T>
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
at reference3#test (file:///$snippetsDir/input/errors/reference3.pkl)
|
||||
|
||||
x | test = ref.Reference::<D, String>(d, "") as Ref<Listing<String>>
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
x | test = ref.Reference<D, String>(d, "") as Ref<Listing<String>>
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
at reference3#test (file:///$snippetsDir/input/errors/reference3.pkl)
|
||||
|
||||
xxx | renderer.renderDocument(value)
|
||||
|
||||
@@ -6,8 +6,8 @@ x | typealias Ref<T> = ref.Reference<D, T>
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
at reference4#test (file:///$snippetsDir/input/errors/reference4.pkl)
|
||||
|
||||
x | test = ref.Reference::<D, String>(d, "") as Ref<Alias1>
|
||||
^^^^^^^^^^^
|
||||
x | test = ref.Reference<D, String>(d, "") as Ref<Alias1>
|
||||
^^^^^^^^^^^
|
||||
at reference4#test (file:///$snippetsDir/input/errors/reference4.pkl)
|
||||
|
||||
xxx | renderer.renderDocument(value)
|
||||
|
||||
@@ -6,8 +6,8 @@ x | typealias Ref<T> = ref.Reference<D, T>
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
at reference5#test (file:///$snippetsDir/input/errors/reference5.pkl)
|
||||
|
||||
xx | test = ref.Reference::<D2, String>(d2, "") as Ref<String>
|
||||
^^^^^^^^^^^
|
||||
xx | test = ref.Reference<D2, String>(d2, "") as Ref<String>
|
||||
^^^^^^^^^^^
|
||||
at reference5#test (file:///$snippetsDir/input/errors/reference5.pkl)
|
||||
|
||||
xxx | renderer.renderDocument(value)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
–– Pkl Error ––
|
||||
Cannot find property `c` in object of type `pkl.ref#Reference<reference6#D, String>`.
|
||||
|
||||
xx | test = ref.Reference::<D, String>(d, new A {}).c
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
xx | test = ref.Reference<D, String>(d, new A {}).c
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
at reference6#test (file:///$snippetsDir/input/errors/reference6.pkl)
|
||||
|
||||
Cannot find property `c` in type `String`.
|
||||
|
||||
@@ -3,8 +3,8 @@ Operator `[]` is not defined for operand types `pkl.ref#Reference<reference7#D,
|
||||
Left operand : Reference(new reference7#D {}, List, List())
|
||||
Right operand: "hi"
|
||||
|
||||
x | test = ref.Reference::<D, List>(d, List())["hi"]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
x | test = ref.Reference<D, List>(d, List())["hi"]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
at reference7#test (file:///$snippetsDir/input/errors/reference7.pkl)
|
||||
|
||||
Operator `[]` is not defined for operand types `List` and `String`.
|
||||
|
||||
Vendored
+8
-8
@@ -1,24 +1,24 @@
|
||||
–– Pkl Error ––
|
||||
oops
|
||||
|
||||
x | res = baz::<String(throw("oops"))>(List("a"))
|
||||
^^^^^^^^^^^^^
|
||||
x | res = baz<String(throw("oops"))>(List("a"))
|
||||
^^^^^^^^^^^^^
|
||||
at callWithTypeArgumentsStacktrace#res.<typearg#1> (file:///$snippetsDir/input/methods/callWithTypeArgumentsStacktrace.pkl)
|
||||
|
||||
x | function baz<T>(qux) = foo::<List<T>>(qux)
|
||||
^
|
||||
x | function baz<T>(qux) = foo<List<T>>(qux)
|
||||
^
|
||||
at callWithTypeArgumentsStacktrace#baz.<typearg#1> (file:///$snippetsDir/input/methods/callWithTypeArgumentsStacktrace.pkl)
|
||||
|
||||
x | function foo<T>(bar) = bar as T
|
||||
^
|
||||
at callWithTypeArgumentsStacktrace#foo (file:///$snippetsDir/input/methods/callWithTypeArgumentsStacktrace.pkl)
|
||||
|
||||
x | function baz<T>(qux) = foo::<List<T>>(qux)
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
x | function baz<T>(qux) = foo<List<T>>(qux)
|
||||
^^^^^^^^^^^^^^^^^
|
||||
at callWithTypeArgumentsStacktrace#baz (file:///$snippetsDir/input/methods/callWithTypeArgumentsStacktrace.pkl)
|
||||
|
||||
x | res = baz::<String(throw("oops"))>(List("a"))
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
x | res = baz<String(throw("oops"))>(List("a"))
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
at callWithTypeArgumentsStacktrace#res (file:///$snippetsDir/input/methods/callWithTypeArgumentsStacktrace.pkl)
|
||||
|
||||
xxx | renderer.renderDocument(value)
|
||||
|
||||
Vendored
+2
-2
@@ -2,8 +2,8 @@
|
||||
Expected value of type `Duration`, but got type `Int`.
|
||||
Value: 5
|
||||
|
||||
x | res = bar::<Duration>()
|
||||
^^^^^^^^
|
||||
x | res = bar<Duration>()
|
||||
^^^^^^^^
|
||||
at callWithTypeArgumentsStacktrace2#bar.prop (file:///$snippetsDir/input/methods/callWithTypeArgumentsStacktrace2.pkl)
|
||||
|
||||
x | prop = foo as T
|
||||
|
||||
@@ -930,7 +930,7 @@ class EvaluatorTest {
|
||||
evaluator.evaluateOutputText(
|
||||
text(
|
||||
"""
|
||||
res = List(1, 2, 3).map::<String>((it) -> it + 1)
|
||||
res = List(1, 2, 3).map<String>((it) -> it + 1)
|
||||
"""
|
||||
.trimIndent()
|
||||
)
|
||||
|
||||
Reference in new issue
Block a user