From ca15457b358d7b57cf14f3a1215ce609645c942b Mon Sep 17 00:00:00 2001 From: Frotty Date: Sat, 18 Oct 2025 19:21:19 +0200 Subject: [PATCH] Correctly set type args binding for derived classes, fixes #871 --- .../validation/WurstValidator.java | 25 ++++++++----- .../tests/wurstscript/tests/BugTests.java | 36 +++++++++++++++++++ 2 files changed, 53 insertions(+), 8 deletions(-) diff --git a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/validation/WurstValidator.java b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/validation/WurstValidator.java index 28ad77798..126f624bc 100644 --- a/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/validation/WurstValidator.java +++ b/de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/validation/WurstValidator.java @@ -1742,7 +1742,7 @@ private void checkParams(Element where, String preMsg, List args, List paramTypes = Lists.newArrayList(); + // Build expected param types in the subclass binding context + List expected = Lists.newArrayList(); + + // The binding that maps the superclass type params to the subclass type args + VariableBinding binding = extendedClass.getTypeArgBinding(); + for (WParameter p : sc.getParameters()) { - paramTypes.add(p.attrTyp()); + WurstType t = p.attrTyp(); + t = t.setTypeArgs(binding); + + expected.add(t); } + if (d.getSuperConstructorCall() instanceof NoSuperConstructorCall - && paramTypes.size() > 0) { + && !expected.isEmpty()) { c.addError("The extended class <" + extendedClass.getName() + "> does not expose a no-arg constructor. " + - "You must define a constructor that calls super(..) appropriately, in this class."); + "You must define a constructor that calls super(..) appropriately, in this class."); } else { - checkParams(d, "Incorrect call to super constructor: ", superArgs(d), paramTypes); + checkParams(d, "Incorrect call to super constructor: ", superArgs(d), expected); } } } @@ -2383,6 +2391,7 @@ private void checkConstructor(ConstructorDef d) { } + private void checkArrayAccess(ExprVarArrayAccess ea) { checkNameRefDeprecated(ea, ea.tryGetNameDef()); for (Expr index : ea.getIndexes()) { 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 864fedda7..6163af115 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 @@ -1459,5 +1459,41 @@ public void duplicateNameInClassHierachy() { "endpackage"); } + @Test + public void derivedGenericClassConstructor() { + testAssertOkLinesWithStdLib(true, + "package test", + "import LinkedList", + "public class ListIterator extends LLIterator", + " construct(LinkedList parent)", + " super(parent)", + "init", + " let b = new ListIterator(new LinkedList())", + " if b != null", + " testSuccess()", + "endpackage"); + } + + @Test + public void derivedGenericClassConstructorNewGenerics() { + testAssertOkLines(true, + "package test", + "native testSuccess()", + "class A", + " T value", + "class B", + " A a", + " construct(A a)", + " this.a = a", + "public class C extends B", + " construct(A parent)", + " super(parent)", + "init", + " let b = new C(new A())", + " if b != null", + " testSuccess()", + "endpackage"); + } + }