Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import de.peeeq.wurstscript.ast.*;
import de.peeeq.wurstscript.types.WurstType;
import de.peeeq.wurstscript.types.WurstTypeTypeParam;
import de.peeeq.wurstscript.types.WurstTypeVararg;
import de.peeeq.wurstscript.utils.NotNullList;
import de.peeeq.wurstscript.utils.Utils;
import org.eclipse.jdt.annotation.Nullable;
Expand All @@ -23,6 +24,27 @@ public abstract class OverloadingResolver<F extends Element, C> {

abstract void handleError(List<String> hints);

boolean isVararg(F f) {
int paramCount = getParameterCount(f);
return paramCount > 0 && getParameterType(f, paramCount - 1) instanceof WurstTypeVararg;
}

int getMinParameterCount(F f) {
return isVararg(f) ? getParameterCount(f) - 1 : getParameterCount(f);
}

boolean hasValidParameterCount(F f, C caller) {
int argCount = getArgumentCount(caller);
return argCount >= getMinParameterCount(f) && (isVararg(f) || argCount <= getParameterCount(f));
}

WurstType getParameterTypeForArg(F f, int i) {
if (isVararg(f) && i >= getParameterCount(f) - 1) {
return ((WurstTypeVararg) getParameterType(f, getParameterCount(f) - 1)).getBaseType();
}
return getParameterType(f, i);
}

Optional<F> resolve(Iterable<F> alternativeFunctions, C caller) {
int size = Utils.size(alternativeFunctions);
if (size == 0) {
Expand All @@ -35,13 +57,18 @@ Optional<F> resolve(Iterable<F> alternativeFunctions, C caller) {

Map<F, Integer> numMatches = new HashMap<>();
for (F f : alternativeFunctions) {
if (!hasValidParameterCount(f, caller)) {
numMatches.put(f, -1);
continue;
}
int matches = 0;
for (int i = 0; i < getArgumentCount(caller) && i < getParameterCount(f); i++) {
for (int i = 0; i < getArgumentCount(caller); i++) {
WurstType expectedParamType = getParameterTypeForArg(f, i);
if (getArgumentType(caller, i) instanceof WurstTypeTypeParam
&& getParameterType(f, i) instanceof WurstTypeTypeParam) {
&& expectedParamType instanceof WurstTypeTypeParam) {
// should be ok!
} else if (!getArgumentType(caller, i).isSubtypeOf(getParameterType(f, i), f)) {
hints.add("Expected " + getParameterType(f, i)
} else if (!getArgumentType(caller, i).isSubtypeOf(expectedParamType, f)) {
hints.add("Expected " + expectedParamType
+ " as parameter " + i + " ,but found " + getArgumentType(caller, i) + ".");
continue;
}
Expand All @@ -67,7 +94,7 @@ && getParameterType(f, i) instanceof WurstTypeTypeParam) {

List<F> rightNumberOfParams = new ArrayList<>();
for (F f1 : funcs) {
if (getParameterCount(f1) == getArgumentCount(caller)) {
if (hasValidParameterCount(f1, caller)) {
rightNumberOfParams.add(f1);
}
}
Expand Down Expand Up @@ -108,7 +135,7 @@ int getParameterCount(ConstructorDef f) {

@Override
WurstType getParameterType(ConstructorDef f, int i) {
return f.getParameters().get(i).getTyp().attrTyp().dynamic();
return f.getParameters().get(i).attrTyp();
}

@Override
Expand Down Expand Up @@ -138,7 +165,7 @@ int getParameterCount(ConstructorDef f) {

@Override
WurstType getParameterType(ConstructorDef f, int i) {
return f.getParameters().get(i).getTyp().attrTyp().dynamic();
return f.getParameters().get(i).attrTyp();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,10 @@ public static LocalState runFunc(ProgramState globalState, ImFunction f, @Nullab

try {
// --- varargs rewrite ---
if (f.hasFlag(FunctionFlagEnum.IS_VARARG)) {
if (f.hasFlag(FunctionFlagEnum.IS_VARARG)
&& !(args.length == f.getParameters().size()
&& args.length > 0
&& args[args.length - 1] instanceof VarargArray)) {
ILconst[] newArgs = new ILconst[f.getParameters().size()];
if (newArgs.length - 1 >= 0) {
System.arraycopy(args, 0, newArgs, 0, newArgs.length - 1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1400,8 +1400,12 @@ public ImFunction getConstructFunc(ConstructorDef constr) {
for (WParameter p : constr.getParameters()) {
params.add(getVarFor(p));
}

f = ImFunction(constr, name, ImTypeVars(), params, ImVoid(), ImVars(), ImStmts(), flags());
List<FunctionFlag> constructorFlags = flags();
if (!constr.getParameters().isEmpty()
&& constr.getParameters().get(constr.getParameters().size() - 1).attrIsVararg()) {
constructorFlags.add(IS_VARARG);
}
f = ImFunction(constr, name, ImTypeVars(), params, ImVoid(), ImVars(), ImStmts(), constructorFlags);
addFunction(f, constr);
constructorFuncs.put(constr, f);
}
Expand Down Expand Up @@ -1433,8 +1437,12 @@ public ImFunction getConstructNewFunc(ConstructorDef constr) {
ImFunction f = constrNewFuncs.get(constr);
if (f == null) {
String name = "new_" + constr.attrNearestClassDef().getName();

f = ImFunction(constr, name, ImTypeVars(), ImVars(), selfType(constr.attrNearestClassOrInterface()), ImVars(), ImStmts(), flags());
List<FunctionFlag> constructorFlags = flags();
if (!constr.getParameters().isEmpty()
&& constr.getParameters().get(constr.getParameters().size() - 1).attrIsVararg()) {
constructorFlags.add(IS_VARARG);
}
f = ImFunction(constr, name, ImTypeVars(), ImVars(), selfType(constr.attrNearestClassOrInterface()), ImVars(), ImStmts(), constructorFlags);
addFunction(f, constr);
constrNewFuncs.put(constr, f);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1419,7 +1419,13 @@ private boolean isValidVarnameStart(String varName) {
private void visit(WParameter p) {
checkVarName(p, false);
if (p.attrIsVararg()) {
if (p.attrNearestFuncDef().getParameters().size() != 1) {
Element owner = p.getParent().getParent();
if (owner instanceof ConstructorDef) {
WParameters params = ((ConstructorDef) owner).getParameters();
if (params.get(params.size() - 1) != p) {
p.addError("Vararg parameter in constructors must be last");
}
} else if (p.attrNearestFuncDef().getParameters().size() != 1) {
p.addError("Vararg functions may only have one parameter");
}
}
Expand Down Expand Up @@ -1769,17 +1775,24 @@ private void checkParams(Element where, String preMsg, List<Expr> args, Function

@Deprecated
private void checkParams(Element where, String preMsg, List<Expr> args, List<WurstType> parameterTypes) {
if (args.size() > parameterTypes.size()) {
where.addError(preMsg + "Too many parameters.");

} else if (args.size() < parameterTypes.size()) {
boolean isVararg = !parameterTypes.isEmpty() && Utils.getLast(parameterTypes) instanceof WurstTypeVararg;
int minParameters = isVararg ? parameterTypes.size() - 1 : parameterTypes.size();
if (args.size() < minParameters) {
where.addError(preMsg + "Missing parameters.");
} else if (!isVararg && args.size() > parameterTypes.size()) {
where.addError(preMsg + "Too many parameters.");
} else {
WurstType varargBaseType = isVararg
? ((WurstTypeVararg) Utils.getLast(parameterTypes)).getBaseType()
: null;
for (int i = 0; i < args.size(); i++) {

WurstType actual = args.get(i).attrTyp();
WurstType expected = parameterTypes.get(i);
// if (expected instanceof AstElementWithTypeArgs)
WurstType expected;
if (isVararg && i >= parameterTypes.size() - 1) {
expected = varargBaseType;
} else {
expected = parameterTypes.get(i);
}
if (!actual.isSubtypeOf(expected, where)) {
args.get(i).addError(
preMsg + "Expected " + expected + " as parameter " + (i + 1) + " but found " + actual);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -303,5 +303,42 @@ public void varargOverride() {

}

@Test
public void varargConstructor() {
testAssertOkLines(true,
"package test",
"native testSuccess()",
"class A",
" int value = 0",
" construct(int i, vararg string strings)",
" value = i",
" for s in strings",
" value++",
"init",
" let a = new A(2, \"x\", \"y\", \"z\")",
" if a.value == 5",
" testSuccess()");
}

@Test
public void varargConstructorSuperCall() {
testAssertOkLines(true,
"package test",
"native testSuccess()",
"class A",
" int sum = 0",
" construct(int i, vararg int xs)",
" sum = i",
" for x in xs",
" sum += x",
"class B extends A",
" construct()",
" super(1,2,3,4)",
"init",
" let b = new B()",
" if b.sum == 10",
" testSuccess()");
}


}
Loading