From cacfbf6ada65bca6a1cf062a7b8df92b6d817338 Mon Sep 17 00:00:00 2001 From: Frotty Date: Tue, 2 Dec 2025 01:28:35 +0100 Subject: [PATCH 1/2] fix bug --- .../wurstscript/attributes/AttrFuncDef.java | 10 +- .../imtranslation/EliminateGenerics.java | 10 +- .../tests/wurstscript/tests/BugTests.java | 131 ++++++++++++++++++ 3 files changed, 143 insertions(+), 8 deletions(-) diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/attributes/AttrFuncDef.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/attributes/AttrFuncDef.java index 6b3f985a3..e653e04fa 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/attributes/AttrFuncDef.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/attributes/AttrFuncDef.java @@ -98,7 +98,7 @@ public static FuncLink calculate(final ExprFuncRef node) { cands.addAll(methods); cands.addAll(exts); - var argTypes = AttrFuncDef.argumentTypesPre(node); + var argTypes = AttrFuncDef.argumentTypes(node); // Pass 1: exact matches java.util.ArrayList exactLinks = new java.util.ArrayList<>(); @@ -242,9 +242,11 @@ public static List argumentTypes(StmtCall node) { pIndex++; } if (hasInferredType) { - // if there are unknown parameter types, use an approximated function type for overloading resolution - WurstType resultType = WurstTypeInfer.instance(); - argType = new WurstTypeClosure(paramTypes, resultType); + WurstType bodyType = closure.getImplementation().attrTyp(); + if (bodyType == null || bodyType instanceof WurstTypeUnknown) { + bodyType = WurstTypeInfer.instance(); + } + argType = new WurstTypeClosure(paramTypes, bodyType); } else { // if there are no unknown types for the argument, then it should be safe to directly calculate the type argType = arg.attrTyp(); diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/EliminateGenerics.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/EliminateGenerics.java index 10e9218f0..daad68e7c 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/EliminateGenerics.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/EliminateGenerics.java @@ -293,10 +293,12 @@ private void adaptSubmethods(List oldSubMethods, ImMethod newM) { newM.getSubMethods().add(specializedSubMethod); } }); - } else { - subClass.getSuperClasses().replaceAll(this::specializeType); - ImClassType newClassTspecialized = specializeType(newClassT); - if (subClass.isSubclassOf(newClassTspecialized.getClassDef())) { + }else { + // DO NOT mutate subClass.getSuperClasses() here. + ImClassType subClassTSpecialized = specializeType(subClassT); + ImClassType newClassTSpecialized = specializeType(newClassT); + + if (subClassTSpecialized.getClassDef().isSubclassOf(newClassTSpecialized.getClassDef())) { newM.getSubMethods().add(subMethod); } } diff --git a/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/BugTests.java b/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/BugTests.java index 97633a923..46e03be35 100644 --- a/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/BugTests.java +++ b/de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/BugTests.java @@ -1679,6 +1679,137 @@ public void linkedListModule_perClassStatics_andTyping_ok() { ); } + @Test + public void testTooltipGenerator() { + test().withStdLib().lines( + "package Test", + "import AbilityObjEditing", + "import HashMap", + "", + "@configurable constant TITLE_COLOR = \"|cff3B97D3\"", + "@configurable constant TITLE_TTYPE = \"Target Type:\"", + "@configurable constant MAX_TITLES = 10", + "", + "@configurable function buildLearnTooltip(string name) returns string", + "\treturn \"|cffFFCC00Learn|r \" + name + \" - [|cffffcc00Level %d|r]\"", + "", + "@configurable function buildActiveTooltip(string name, int lvl) returns string", + "\treturn name + \" - Level \" + lvl.toString()", + "", + "@configurable function buildPassiveTooltip(string name, int lvl) returns string", + "\treturn name + \" - Level \" + lvl.toString()", + "", + "@configurable function buildDescription(string description) returns string", + "\treturn \"|cff919191\" + description + \"|r\"", + "\t", + "public class AbilityTooltipGenerator implements TooltipGenerator", + "\tprivate constant propMap = new IterableMap", + "\tprivate var description = \"\"", + "", + "\tprivate var levels = 1", + "\tprivate var hotkey = \"\"", + "\tprivate var name = \"\"", + "", + "\tconstruct(string description)", + "\t\tthis.description = description", + "", + "\tconstruct()", + "", + "\toverride function addProperty(string title, StringLevelClosure lc)", + "\t\tpropMap.put(title, lc)", + "", + "\toverride function applyToDef(AbilityDefinition def)", + "\t\tlevels = propMap.has(\"Levels\") ? fixValue(propMap.getAndRemove(\"Levels\").run(0)).toInt() : 1", + "\t\tname = propMap.has(\"Name\") ? propMap.getAndRemove(\"Name\").run(0) : \"unnamed\"", + "\t\thotkey = propMap.has(\"Hotkey\") ? propMap.getAndRemove(\"Hotkey\").run(0) : \"Q\"", + "\t\tdef..setTooltipLearn(generateTooltipLearn())", + "\t\t..setTooltipLearnExtended(generateTooltipExtended(-1, true))", + "\t\tfor i = 1 to levels", + "\t\t\tdef..setTooltipNormal(i, generateTooltipNormal(i))", + "\t\t\t..setTooltipNormalExtended(i, generateTooltipExtended(i, false))", + "", + "\tprivate function generateTooltipLearn() returns string", + "\t\treturn buildLearnTooltip(name)", + "", + "\tprivate function generateTooltipNormal(int lvl) returns string", + "\t\treturn buildActiveTooltip(name, lvl)", + "", + "\tprivate function generateTooltipExtended(int lvl, boolean learn) returns string", + "\t\tvar s = \"\"", + "", + "\t\tfor key in propMap", + "\t\t\tvar tmp = \"\"", + "\t\t\tvar isConstantValue = true", + "\t\t\tlet val = fixValue(propMap.get(key).run(1))", + "\t\t\tfor i = 2 to levels", + "\t\t\t\tlet tval = fixValue(propMap.get(key).run(i))", + "\t\t\t\tif val != tval", + "\t\t\t\t\tisConstantValue = false", + "\t\t\t\t\tbreak", + "", + "\t\t\tif isConstantValue", + "\t\t\t\ttmp += \"|cffFFCC00\" + val + \"|r \"", + "\t\t\telse", + "\t\t\t\tfor i = 1 to levels", + "\t\t\t\t\ttmp += fixValue(propMap.get(key).run(i)) + (i < levels ? \"/\" : \"\")", + "", + "\t\t\ts += TITLE_COLOR + key + \":|r \" + colorLevelValue(tmp, lvl, levels) + \"\\n\"", + "\t\ts += \"\\n\"", + "\t\ts += buildDescription(description)", + "\t\treturn s", + "", + "\tprivate static function fixValue(string value) returns string", + "\t\tif value == \"\"", + "\t\t\treturn \"\"", + "\t\tvar s = value", + "\t\tlet len = s.length()", + "\t\tlet lastChar = s.substring(len-1, len)", + "\t\tif lastChar == \".\"", + "\t\t\ts = s.substring(0, len-1)", + "\t\telse if len > 1 and s.substring(len-2, len) == \".0\"", + "\t\t\ts = s.substring(0, len-2)", + "\t\treturn s", + "", + "\tprivate static function colorLevelValue(string oldString, int lvl, int maxLevel) returns string", + "\t\tvar _newString = \"\"", + "\t\tvar charCount = 0", + "\t\tvar charPosCount = 0", + "\t\tint array charPos", + "\t\tlet oldLen = oldString.length()", + "\t\tfor char in oldString", + "\t\t\tif char == \"/\"", + "\t\t\t\tcharPos[charPosCount] = charCount", + "\t\t\t\tcharPosCount++", + "\t\t\tcharCount++", + "\t\tif lvl == -1", + "\t\t\t_newString = oldString", + "\t\telse if charPosCount <= 0", + "\t\t\t_newString = \"|cffFFCC00\" + oldString", + "\t\telse if maxLevel <= 1", + "\t\t\t_newString = \"|cffFFCC00\" + oldString", + "\t\telse if lvl == 1", + "\t\t\t_newString = \"|cffFFCC00\" + oldString.substring(0, charPos[0]) + \"|r\" + oldString.substring(charPos[0], oldLen)", + "\t\telse if lvl == maxLevel", + "\t\t\t_newString = oldString.substring(0, charPos[lvl-2] + 1) + \"|cffFFCC00\" + oldString.substring(charPos[lvl-2] + 1, oldLen) + \"|r\"", + "\t\telse", + "\t\t\t_newString = oldString.substring(0, charPos[lvl-2] + 1) + \"|cffFFCC00\" + oldString.substring(charPos[lvl-2] + 1, charPos[lvl-1]) + \"|r\" + oldString.substring(charPos[lvl-1], oldLen)", + "\t\treturn _newString", + "constant h = compiletime(gen())", + "", + "function gen() returns int", + " let myInt = 20", + " let tgen = new AbilityTooltipGenerator(\"Test1\")", + " new AbilityDefinitionItemHealAoe('1234')", + " ..registerTooltipGenerator(tgen)", + " ..tooltipStartListen()", + " ..addTooltipProperty(\"String\", _ -> \"a\")", + " ..tooltipStopListen(true)", + "", + " return 1", + "init", + " testSuccess()" + ); + } } From 6db0f2847c1bb31e19148fb46427f8dac92c2aad Mon Sep 17 00:00:00 2001 From: Frotty Date: Tue, 2 Dec 2025 01:41:36 +0100 Subject: [PATCH 2/2] Update EliminateGenerics.java --- .../translation/imtranslation/EliminateGenerics.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/EliminateGenerics.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/EliminateGenerics.java index 5ab07fe6b..130b2afa4 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/EliminateGenerics.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/EliminateGenerics.java @@ -343,11 +343,9 @@ private void adaptSubmethods(List oldSubMethods, ImMethod newM) { } }); }else { - // DO NOT mutate subClass.getSuperClasses() here. - ImClassType subClassTSpecialized = specializeType(subClassT); - ImClassType newClassTSpecialized = specializeType(newClassT); - - if (subClassTSpecialized.getClassDef().isSubclassOf(newClassTSpecialized.getClassDef())) { + subClass.getSuperClasses().replaceAll(this::specializeType); + ImClassType newClassTspecialized = specializeType(newClassT); + if (subClass.isSubclassOf(newClassTspecialized.getClassDef())) { newM.getSubMethods().add(subMethod); } }