Skip to content

Commit 74732ff

Browse files
committed
Complete superclass field guarantees and module indexing
1 parent 84a8570 commit 74732ff

2 files changed

Lines changed: 47 additions & 25 deletions

File tree

de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/validation/WurstValidator.java

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ private enum Phase { LIGHT, HEAVY }
6262
private final Map<ClassDef, Map<GlobalVarDef, Integer>> classVarInitOrderCache = new HashMap<>();
6363
private final Map<GlobalVarDef, Boolean> guaranteedClassFieldInitCache = new IdentityHashMap<>();
6464
private final Map<GlobalVarDef, List<GlobalVarDef>> moduleFieldCopiesCache = new IdentityHashMap<>();
65+
private boolean moduleFieldCopiesIndexed;
6566

6667
/**
6768
* When true, the build targets a legacy patch (pre-1.24) whose Blizzard-provided
@@ -87,6 +88,7 @@ public void validate(Collection<CompilationUnit> toCheck) {
8788
heavyBlocks.clear();
8889
guaranteedClassFieldInitCache.clear();
8990
moduleFieldCopiesCache.clear();
91+
moduleFieldCopiesIndexed = false;
9092

9193
lightValidation(toCheck);
9294

@@ -1988,11 +1990,12 @@ private boolean constructorAssignsField(ConstructorDef constructor, GlobalVarDef
19881990
return true;
19891991
}
19901992
FunctionCall thisCall = getFirstThisConstructorCall(constructor);
1991-
if (thisCall == null) {
1992-
return false;
1993+
if (thisCall != null) {
1994+
ConstructorDef target = OverloadingResolver.resolveThisCall(constructorsFor(constructor), thisCall);
1995+
return target != null && target != constructor && constructorAssignsField(target, field, visiting);
19931996
}
1994-
ConstructorDef target = OverloadingResolver.resolveThisCall(constructorsFor(constructor), thisCall);
1995-
return target != null && target != constructor && constructorAssignsField(target, field, visiting);
1997+
ConstructorDef superConstructor = constructor.attrSuperConstructor();
1998+
return superConstructor != null && constructorAssignsField(superConstructor, field, visiting);
19961999
}
19972000

19982001
private List<ConstructorDef> constructorsFor(GlobalVarDef field) {
@@ -2035,36 +2038,32 @@ private List<ConstructorDef> enclosingClassConstructors(GlobalVarDef field) {
20352038
}
20362039

20372040
private List<GlobalVarDef> moduleFieldCopies(GlobalVarDef field) {
2038-
List<GlobalVarDef> cached = moduleFieldCopiesCache.get(field);
2039-
if (cached != null) {
2040-
return cached;
2041-
}
2042-
ClassOrModule owner = field.attrNearestClassOrModule();
2043-
if (!(owner instanceof ModuleDef module)) {
2044-
cached = Collections.emptyList();
2045-
moduleFieldCopiesCache.put(field, cached);
2046-
return cached;
2041+
if (!moduleFieldCopiesIndexed) {
2042+
indexModuleFieldCopies();
20472043
}
2048-
int fieldIndex = module.getVars().indexOf(field);
2049-
if (fieldIndex < 0) {
2050-
cached = Collections.emptyList();
2051-
moduleFieldCopiesCache.put(field, cached);
2052-
return cached;
2044+
return moduleFieldCopiesCache.getOrDefault(field, Collections.emptyList());
2045+
}
2046+
2047+
private void indexModuleFieldCopies() {
2048+
if (moduleFieldCopiesIndexed) {
2049+
return;
20532050
}
2054-
List<GlobalVarDef> copies = new ArrayList<>();
20552051
prog.accept(new Element.DefaultVisitor() {
20562052
@Override
20572053
public void visit(ModuleInstanciation instantiation) {
2058-
if (instantiation.attrModuleOrigin() == module
2059-
&& fieldIndex < instantiation.getVars().size()) {
2060-
copies.add(instantiation.getVars().get(fieldIndex));
2054+
ModuleDef origin = instantiation.attrModuleOrigin();
2055+
if (origin != null) {
2056+
int count = Math.min(origin.getVars().size(), instantiation.getVars().size());
2057+
for (int i = 0; i < count; i++) {
2058+
GlobalVarDef originField = origin.getVars().get(i);
2059+
moduleFieldCopiesCache.computeIfAbsent(originField, ignored -> new ArrayList<>())
2060+
.add(instantiation.getVars().get(i));
2061+
}
20612062
}
20622063
super.visit(instantiation);
20632064
}
20642065
});
2065-
cached = List.copyOf(copies);
2066-
moduleFieldCopiesCache.put(field, cached);
2067-
return cached;
2066+
moduleFieldCopiesIndexed = true;
20682067
}
20692068

20702069
private boolean initializedBySuperConstructor(ConstructorDef constructor, GlobalVarDef field) {

de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/ClassesTests.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,29 @@ public void doesNotWarnForInheritedFieldAfterSuperclassConstructor() {
380380
result.getGui().getWarningList().toString());
381381
}
382382

383+
@Test
384+
public void doesNotWarnForInheritedFieldAfterGrandparentConstructor() {
385+
CompilationResult result = test()
386+
.setStopOnFirstError(false)
387+
.executeProg(false)
388+
.lines(
389+
"package Test",
390+
"class GrandBase",
391+
" int value",
392+
" construct()",
393+
" value = 1",
394+
"class Base extends GrandBase",
395+
" construct()",
396+
"class Child extends Base",
397+
" construct()",
398+
" int copy = value"
399+
);
400+
401+
assertFalse(result.getGui().getWarningList().stream()
402+
.anyMatch(w -> w.getMessage().contains("no explicit initializer and is not definitely assigned")),
403+
result.getGui().getWarningList().toString());
404+
}
405+
383406
@Test
384407
public void doesNotWarnForInheritedFieldInitializerAfterSuperclassConstructor() {
385408
CompilationResult result = test()

0 commit comments

Comments
 (0)