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 @@ -13,6 +13,7 @@
import de.peeeq.wurstio.mpq.MpqEditor;
import de.peeeq.wurstscript.WLogger;
import de.peeeq.wurstscript.ast.Element;
import de.peeeq.wurstscript.ast.GlobalVarDef;
import de.peeeq.wurstscript.attributes.CompileError;
import de.peeeq.wurstscript.attributes.ErrorHandler;
import de.peeeq.wurstscript.gui.WurstGui;
Expand Down Expand Up @@ -750,7 +751,8 @@ private void emitCompiletimeState() {
.thenComparing(ImVar::getName);
modifiedScalars.sort(stableGlobalOrder);
for (ImVar var : modifiedScalars) {
if (!imProg.getGlobals().contains(var) || var.getType() instanceof ImArrayLikeType) {
if (!imProg.getGlobals().contains(var) || var.getType() instanceof ImArrayLikeType
|| !isCompiletimeStateMigrationTarget(var)) {
continue;
}
StateReplayLocation replayLocation = findReplayTarget(var);
Expand Down Expand Up @@ -779,7 +781,7 @@ private void emitCompiletimeState() {
}
modifiedArrays.sort(stableGlobalOrder);
for (ImVar var : modifiedArrays) {
if (!imProg.getGlobals().contains(var)) {
if (!imProg.getGlobals().contains(var) || !isCompiletimeStateMigrationTarget(var)) {
continue;
}
if (!(var.getType() instanceof ImArrayLikeType)) {
Expand Down Expand Up @@ -811,6 +813,13 @@ private void emitCompiletimeState() {
}
}

private boolean isCompiletimeStateMigrationTarget(ImVar var) {
// Compiletime state is deliberately opt-in per global. This keeps
// compiletime-only scratch values and incidental writes out of runtime init.
return var.getTrace() instanceof GlobalVarDef
&& ((GlobalVarDef) var.getTrace()).hasAnnotation("@compiletime");
}

private String sourceDiagnostic(ImVar var) {
return var.getTrace().attrSource().printShort();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3000,9 +3000,9 @@ public void case_GlobalVarDef(GlobalVarDef g) {
} else {
check(VisibilityPublic.class, ModConstant.class, ModReadonly.class, Annotation.class);
}
if (g.hasAnnotation("@compiletime")) {
if (g.attrIsDynamicClassMember() && g.hasAnnotation("@compiletime")) {
g.getAnnotation("@compiletime")
.addWarning("The annotation '@compiletime' has no effect on variables.");
.addWarning("The annotation '@compiletime' has no effect on instance fields.");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@

public class CompiletimeTests extends WurstScriptTest {

@Test
public void compiletimeAnnotationWarnsOnInstanceFields() {
test().expectWarning("has no effect on instance fields")
.lines("package Test",
"class C",
" @compiletime int value");
}

@Test
public void testSimpleCompiletime() {
Expand Down Expand Up @@ -81,29 +88,32 @@ public void testUnsupportedCompiletimeArrayWarningIsAggregatedAndReadable() {
try {
test().withStdLib().testLua(true).luaOnly(true).runCompiletimeFunctions(true)
.lines("package Test",
"@compiletime player array source",
"@compiletime function fill()",
" source[0] = Player(0)",
"init",
" let _firstPlayer = players[0]");
" source[0] = Player(0)");
} finally {
logger.detachAppender(appender);
appender.stop();
}

List<String> playerWarnings = appender.list.stream()
.map(ILoggingEvent::getFormattedMessage)
.filter(message -> message.contains("Player_players"))
.filter(message -> message.contains("Test_source"))
.toList();
assertEquals(playerWarnings.size(), 1, "expected one warning for the entire array");
String warning = playerWarnings.get(0);
assertTrue(warning.contains("28 unsupported compiletime entries"), warning);
assertTrue(warning.contains("Player, line"), warning);
assertTrue(warning.contains("1 unsupported compiletime entries"), warning);
assertTrue(warning.contains("IlConstHandle"), warning);
assertFalse(warning.contains("GlobalVarDef"), warning);
}

@Test
public void testCompiletimePackageScalarState() {
test().testLua(true).luaOnly(false).executeProg(true).executeProgOnlyAfterTransforms().runCompiletimeFunctions(true)
.lines("package A",
"public int source = 1",
"@compiletime public int source = 1",
"@compiletime function fill()",
" source = 42",
"endpackage",
Expand All @@ -123,8 +133,8 @@ public void testCompiletimeObjectAndNullScalarState() {
"native testSuccess()",
"class A",
" int value",
"A source",
"string cleared = \"value\"",
"@compiletime A source",
"@compiletime string cleared = \"value\"",
"@compiletime function fill()",
" source = new A",
" source.value = 42",
Expand All @@ -146,7 +156,7 @@ public void testCompiletimeScalarReplayOnlyWrittenValues() {
"import A",
"native testSuccess()",
"int observed = seed",
"int migrated = 0",
"@compiletime int migrated = 0",
"@compiletime function fill()",
" let snapshot = observed",
" migrated = snapshot + 41",
Expand All @@ -165,7 +175,7 @@ public void testLazyScalarInitializerSideEffectsAreNotReplayed() {
" counter++",
" return counter",
"int observed = bump()",
"int migrated",
"@compiletime int migrated",
"@compiletime function fill()",
" let _snapshot = observed",
" migrated = 42",
Expand All @@ -179,7 +189,7 @@ public void testCompiletimeScalarRuntimeWriteRemainsAuthoritative() {
test().testLua(true).luaOnly(false).executeProg(true).executeProgOnlyAfterTransforms().runCompiletimeFunctions(true)
.lines("package Test",
"native testSuccess()",
"int source = 1",
"@compiletime int source = 1",
"@compiletime function fill()",
" source = 42",
"init",
Expand All @@ -194,7 +204,7 @@ public void testCompiletimeClassStaticScalarState() {
.lines("package Test",
"native testSuccess()",
"class Counter",
" static int value = 1",
" @compiletime static int value = 1",
" static function setValue(int newValue)",
" value = newValue",
" static function getValue() returns int",
Expand All @@ -213,7 +223,7 @@ public void testCompiletimeGenericClassStaticScalarState() {
.lines("package Test",
"native testSuccess()",
"class Counter<T:>",
" static T value",
" @compiletime static T value",
" static function setValue(T newValue)",
" value = newValue",
" static function getValue() returns T",
Expand All @@ -230,7 +240,7 @@ public void testCompiletimeArrayState() {
test().executeProg(true).executeProgOnlyAfterTransforms().runCompiletimeFunctions(true)
.lines("package Test",
"native testSuccess()",
"int array source",
"@compiletime int array source",
"@compiletime function fill()",
" source[0] = 42",
"init",
Expand All @@ -243,7 +253,7 @@ public void testCompiletimeArrayStateAfterSourceInitializer() {
test().executeProg(true).executeProgOnlyAfterTransforms().runCompiletimeFunctions(true)
.lines("package Test",
"native testSuccess()",
"int array source = [1]",
"@compiletime int array source = [1]",
"@compiletime function fill()",
" source[0] = 42",
"init",
Expand All @@ -256,7 +266,7 @@ public void testCompiletimeArrayStateLua() {
test().testLua(true).executeProg(true).executeProgOnlyAfterTransforms().runCompiletimeFunctions(true)
.lines("package Test",
"native testSuccess()",
"int array source = [1]",
"@compiletime int array source = [1]",
"@compiletime function fill()",
" source[0] = 42",
"init",
Expand All @@ -270,7 +280,7 @@ public void testCompiletimeGenericArrayState() {
.lines("package Test",
"native testSuccess()",
"class Box<T:>",
" static T array store",
" @compiletime static T array store",
" static function set(int index, T value)",
" store[index] = value",
" static function get(int index) returns T",
Expand All @@ -288,7 +298,7 @@ public void testCompiletimeGenericArrayStateLua() {
.lines("package Test",
"native testSuccess()",
"class Box<T:>",
" static T array store",
" @compiletime static T array store",
" static function set(int index, T value)",
" store[index] = value",
" static function get(int index) returns T",
Expand All @@ -307,7 +317,7 @@ public void testCompiletimeObjectArrayState() {
"native testSuccess()",
"class A",
" int value",
"A array source",
"@compiletime A array source",
"@compiletime function fill()",
" source[0] = new A",
" source[0].value = 42",
Expand All @@ -326,7 +336,7 @@ public void testCompiletimeHashtableArrayState() {
"@extern native InitHashtable() returns hashtable",
"@extern native LoadInteger(hashtable h, int p, int c) returns int",
"@extern native SaveInteger(hashtable h, int p, int c, int i)",
"hashtable array source",
"@compiletime hashtable array source",
"@compiletime function fill()",
" source[0] = InitHashtable()",
" SaveInteger(source[0], 2, 3, 42)",
Expand All @@ -340,7 +350,7 @@ public void testCompiletimeNullArrayState() {
test().executeProg(true).executeProgOnlyAfterTransforms().runCompiletimeFunctions(true)
.lines("package Test",
"native testSuccess()",
"string array source = [\"value\"]",
"@compiletime string array source = [\"value\"]",
"@compiletime function clear()",
" source[0] = null",
"init",
Expand All @@ -354,7 +364,7 @@ public void testCompiletimeTupleArrayState() {
.lines("package Test",
"native testSuccess()",
"tuple pair(int left, int right)",
"pair array source",
"@compiletime pair array source",
"@compiletime function fill()",
" source[0] = pair(42, 7)",
"init",
Expand All @@ -366,7 +376,7 @@ public void testCompiletimeTupleArrayState() {
public void testCompiletimeArrayStateAcrossPackages() {
test().executeProg(true).executeProgOnlyAfterTransforms().runCompiletimeFunctions(true)
.lines("package A",
"public int array source = [1]",
"@compiletime public int array source = [1]",
"@compiletime function fillA()",
" source[0] = 42",
"init",
Expand All @@ -384,15 +394,15 @@ public void testCompiletimeArrayStateAcrossPackages() {
public void testCompiletimeArrayStateAcrossPackagesWithTwoInitializers() {
test().executeProg(true).executeProgOnlyAfterTransforms().runCompiletimeFunctions(true)
.lines("package A",
"public int array source = [1]",
"@compiletime public int array source = [1]",
"@compiletime function fillA()",
" source[0] = 42",
"init",
" source[0] = 7",
"endpackage",
"package B",
"import A",
"int array other = [2]",
"@compiletime int array other = [2]",
"@compiletime function fillB()",
" other[0] = 9",
"native testSuccess()",
Expand All @@ -407,9 +417,9 @@ public void testCompiletimeArrayReplayPrecedesDependentInitializer() {
test().testLua(true).executeProg(true).executeProgOnlyAfterTransforms().runCompiletimeFunctions(true)
.lines("package Test",
"native testSuccess()",
"int array first = [1]",
"@compiletime int array first = [1]",
"int observed = first[0]",
"int array second = [2]",
"@compiletime int array second = [2]",
"@compiletime function fill()",
" first[0] = 42",
" second[0] = 9",
Expand All @@ -429,7 +439,7 @@ public void testCompiletimeArrayReplayOnlyWrittenEntries() {
"package B",
"import A",
"native testSuccess()",
"int array source = [seed, 0]",
"@compiletime int array source = [seed, 0]",
"@compiletime function fill()",
" source[1] = 42",
"init",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public void compiletimeGenericArrayReplayLeavesAreSplit() {
new RunArgs().with("-lua", "-runcompiletimefunctions", "-functionSplitLimit", "1"),
"package Test",
"class Box<T:>",
" static T array store",
" @compiletime static T array store",
" static function set(int index, T value)",
" store[index] = value",
" static function get(int index) returns T",
Expand Down Expand Up @@ -93,10 +93,10 @@ public void compiletimeArrayReplaySplittingIsDeterministicAcrossPackages() {
RunArgs runArgs = new RunArgs().with(
"-lua", "-runcompiletimefunctions", "-functionSplitLimit", "1");
String[] source = {
"package A", "public int array a = [1]", "@compiletime function fillA()", " a[0] = 10", "endpackage",
"package B", "public int array b = [1]", "@compiletime function fillB()", " b[0] = 20", "endpackage",
"package C", "public int array c = [1]", "@compiletime function fillC()", " c[0] = 30", "endpackage",
"package D", "public int array d = [1]", "@compiletime function fillD()", " d[0] = 40", "endpackage",
"package A", "@compiletime public int array a = [1]", "@compiletime function fillA()", " a[0] = 10", "endpackage",
"package B", "@compiletime public int array b = [1]", "@compiletime function fillB()", " b[0] = 20", "endpackage",
"package C", "@compiletime public int array c = [1]", "@compiletime function fillC()", " c[0] = 30", "endpackage",
"package D", "@compiletime public int array d = [1]", "@compiletime function fillD()", " d[0] = 40", "endpackage",
"package Test", "import A", "import B", "import C", "import D", "native testSuccess()", "init",
" if a[0] + b[0] + c[0] + d[0] == 100", " testSuccess()"
};
Expand All @@ -111,10 +111,10 @@ public void compiletimeScalarReplaySplittingIsDeterministicAcrossPackages() {
RunArgs runArgs = new RunArgs().with(
"-lua", "-runcompiletimefunctions", "-functionSplitLimit", "1");
String[] source = {
"package A", "public int a", "@compiletime function fillA()", " a = 10", "endpackage",
"package B", "public int b", "@compiletime function fillB()", " b = 20", "endpackage",
"package C", "public int c", "@compiletime function fillC()", " c = 30", "endpackage",
"package D", "public int d", "@compiletime function fillD()", " d = 40", "endpackage",
"package A", "@compiletime public int a", "@compiletime function fillA()", " a = 10", "endpackage",
"package B", "@compiletime public int b", "@compiletime function fillB()", " b = 20", "endpackage",
"package C", "@compiletime public int c", "@compiletime function fillC()", " c = 30", "endpackage",
"package D", "@compiletime public int d", "@compiletime function fillD()", " d = 40", "endpackage",
"package Test", "import A", "import B", "import C", "import D", "native testSuccess()", "init",
" if a + b + c + d == 100", " testSuccess()"
};
Expand All @@ -139,6 +139,42 @@ public void compiletimeScalarReplaySplittingIsDeterministicAcrossPackages() {
assertEquals("all compiletime scalar values must still be emitted", 4, persistedAssignments);
}

@Test
public void compiletimeScalarMigrationIsDisabledByDefault() {
String compiled = compileLuaWithRunArgs(
"compiletimeScalarMigrationIsDisabledByDefault",
new RunArgs().with("-lua", "-runcompiletimefunctions"),
"package Test",
"int source = 1",
"@compiletime function fill()",
" source = 42",
"native testSuccess()",
"init",
" if source == 1",
" testSuccess()"
);

assertFalse("scalar compiletime state must not be emitted without the opt-in flag", compiled.contains("initCompiletimeScalarState"));
}

@Test
public void compiletimeArrayMigrationIsDisabledByDefault() {
String compiled = compileLuaWithRunArgs(
"compiletimeArrayMigrationIsDisabledByDefault",
new RunArgs().with("-lua", "-runcompiletimefunctions"),
"package Test",
"int array source = [1]",
"@compiletime function fill()",
" source[0] = 42",
"native testSuccess()",
"init",
" if source[0] == 1",
" testSuccess()"
);

assertFalse("array compiletime state must not be emitted without the opt-in annotation", compiled.contains("initCompiletimeArrayState"));
}

@Test
public void compiletimeInterpreterSeesLuaTarget() {
String compiled = compileLuaWithRunArgs(
Expand All @@ -149,7 +185,7 @@ public void compiletimeInterpreterSeesLuaTarget() {
"endpackage",
"package Test",
"import MagicFunctions",
"int observedBackend",
"@compiletime int observedBackend",
"@compiletime function detectBackend()",
" if isLua",
" observedBackend = 1",
Expand Down
Loading