Arithmetic on a parameter of class DATE does not keep the DATE class: p - 7 is inferred as INTEGER, so the expression is rejected everywhere a DATE is required. The same arithmetic on a DATE-valued property or function is accepted.
The computed value is never wrong — only the inferred class is. The failure is therefore a load-time type error, not a data problem.
Reproduction
A self-contained module. Add DateParamRepro to the top module's REQUIRE and start the server.
MODULE DateParamRepro;
REQUIRE System, Utils, Time;
CLASS Sample 'Sample';
day 'Day' = DATA DATE (Sample);
// the parameter itself is a perfectly good DATE
plain (Sample s, DATE p) { day(s) <- p; } // OK
// ... but arithmetic on it is not
minusParam (Sample s, DATE p) { day(s) <- p - 7; } // FAILS
Observed
Each construct was checked on its own, because one semantic error is reported per load:
| construct |
result |
day(s) <- p; |
OK — the parameter is a DATE |
day(s) <- p - 7; |
ASSIGN's arguments' types don't match |
day(s) <- p + 7; |
ASSIGN's arguments' types don't match |
older (Sample s, DATE p) = TRUE IF day(s) < p - 7; |
value of class 'DATE' is not comparable with value of class 'INTEGER' |
day(s) <- DATE(p - 7); |
OK |
day(s) <- sum(p, -7); |
OK |
day(s) <- day(s) - 7; |
OK — property on the left |
day(s) <- currentDate() - 7; |
OK — function on the left |
The comparison case is the informative one: it names the inferred class outright, so p - 7 is coming out as INTEGER.
The last two rows are the contrast that makes this look like a bug rather than a deliberate restriction — the very same <expr> - 7, differing only in whether the left operand is a parameter or a property/function, is accepted.
The value is correct
Only the inference is affected. Checked at runtime through /eval with p = 2026-08-21:
run(DATE p) {
RETURN 'p-7 raw=' + STRING[30](p - 7)
+ ' | DATE(p-7)=' + STRING[30](DATE(p - 7))
+ ' | sum(p,-7)=' + STRING[30](sum(p, -7));
}
p-7 raw=2026-08-14 | DATE(p-7)=2026-08-14 | sum(p,-7)=2026-08-14
All three forms produce the right date, so DATE(p - 7) is a genuine workaround rather than a cast that papers over a wrong value.
Expected
DATE ± INTEGER should yield DATE regardless of whether the left operand is a parameter, a property or a function — matching sum[DATE, INTEGER] and subtract[DATE, LONG] from Time.
Why it is easy to get wrong
The two error messages point in different directions, and neither mentions the parameter:
ASSIGN's arguments' types don't match names neither operand class nor the parameter, so from the assignment alone the natural (and wrong) conclusion is that DATE ± INTEGER is simply not assignable to a DATE property.
- Only the comparison message names
INTEGER, and a codebase can easily have no comparison on a parameter — every currentDate() + N and dateProp(x) - N in it keeps working, which hides the pattern.
If the current behaviour turns out to be intended, an error message naming the parameter and its inferred class would already remove most of the confusion.
Workarounds
day(s) <- sum(p, -7); // Time helper - preferred
day(s) <- DATE(p - 7); // explicit cast, verified to give the same value
Environment
- lsFusion 7.0-SNAPSHOT, build 392
- Java 17.0.9, Windows 11, PostgreSQL 18
- Reproduced at load time — both on a normal server start and with
-Dsettings.dryRun=true
Only DATE was checked; DATETIME and TIME parameters were not tested.
Arithmetic on a parameter of class
DATEdoes not keep theDATEclass:p - 7is inferred asINTEGER, so the expression is rejected everywhere aDATEis required. The same arithmetic on aDATE-valued property or function is accepted.The computed value is never wrong — only the inferred class is. The failure is therefore a load-time type error, not a data problem.
Reproduction
A self-contained module. Add
DateParamReproto the top module'sREQUIREand start the server.Observed
Each construct was checked on its own, because one semantic error is reported per load:
day(s) <- p;DATEday(s) <- p - 7;ASSIGN's arguments' types don't matchday(s) <- p + 7;ASSIGN's arguments' types don't matcholder (Sample s, DATE p) = TRUE IF day(s) < p - 7;value of class 'DATE' is not comparable with value of class 'INTEGER'day(s) <- DATE(p - 7);day(s) <- sum(p, -7);day(s) <- day(s) - 7;day(s) <- currentDate() - 7;The comparison case is the informative one: it names the inferred class outright, so
p - 7is coming out asINTEGER.The last two rows are the contrast that makes this look like a bug rather than a deliberate restriction — the very same
<expr> - 7, differing only in whether the left operand is a parameter or a property/function, is accepted.The value is correct
Only the inference is affected. Checked at runtime through
/evalwithp = 2026-08-21:All three forms produce the right date, so
DATE(p - 7)is a genuine workaround rather than a cast that papers over a wrong value.Expected
DATE ± INTEGERshould yieldDATEregardless of whether the left operand is a parameter, a property or a function — matchingsum[DATE, INTEGER]andsubtract[DATE, LONG]fromTime.Why it is easy to get wrong
The two error messages point in different directions, and neither mentions the parameter:
ASSIGN's arguments' types don't matchnames neither operand class nor the parameter, so from the assignment alone the natural (and wrong) conclusion is thatDATE ± INTEGERis simply not assignable to aDATEproperty.INTEGER, and a codebase can easily have no comparison on a parameter — everycurrentDate() + NanddateProp(x) - Nin it keeps working, which hides the pattern.If the current behaviour turns out to be intended, an error message naming the parameter and its inferred class would already remove most of the confusion.
Workarounds
Environment
-Dsettings.dryRun=trueOnly
DATEwas checked;DATETIMEandTIMEparameters were not tested.