feat!: move arithmetic from the standard library into the builtins - #1937
Merged
Merged
Conversation
Build Artifacts🐧 Linux
From workflow run 🪟 Windows
From workflow run |
|
5 findings in 8m 56s for $0.37 between
|
|
2 findings in 10m 33s for $0.38 between
|
Problem: `dt + t`, `d1 - d2` and `tod + 5` compile to raw integer operations on values with different units, and nothing tells the user which combinations exist. Solution: A table of the IEC 61131-3 date and time arithmetic in the typesystem, checked by the validator for every binary expression with a date or time operand: an undefined combination reports E156, a missing standard function reports E073, and a duration combined with a bare integer is accepted with warning E157. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Problem: `dt + t` adds seconds to milliseconds, `tod + t` never wraps at midnight, and `t * 1.5` truncates the factor, because the operators on date and time types were plain integer instructions. Solution: The annotator types such an expression by the result the standard defines and replaces it with the call of the standard library function that carries it out (`ADD_DT_TIME`, `SUB_DATE_DATE`, ...), the way a string comparison becomes `STRING_EQUAL`. A scaled duration calls the implementation for the kind of number (`MUL_TIME__LINT`, `__ULINT`, `__REAL`, `__LREAL`), which the standard library now declares, with the number widened to it. A duration combined with a bare integer stays a plain operation of the duration type. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ME width Problem: `MUL_TIME__DINT` and the other short-family monomorphs take and return `i64`, while the compiler passes and reads a 32-bit `TIME`. The mismatch only works because 32-bit register writes zero-extend. Solution: The short-family monomorphs take and return `u32` and compute in 64 bits as before, so every observable result stays: a product wraps modulo 2^32, a saturated float result is `u32::MAX`, a NaN factor yields zero, and a zero integer divisor panics. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Problem: `ADD_LTOD_LTIME` and `SUB_LTOD_LTIME` are plain additions, so a moment of a day can leave the day, while their TIME_OF_DAY counterparts wrap at midnight. Solution: Both reduce their result modulo one day of nanoseconds, the way `ADD_TOD_TIME` and `SUB_TOD_TIME` do in milliseconds. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Problem: The builtins only accept numbers, so `ADD(dt, t)` needs the standard library's generic overload and `ADD(dt, t, t)` is rejected with a wrong argument count. Solution: The builtins accept any type and validate every left-folded pair by the date and time table; a call with a date or time argument expands to the chain of operators, which the resolver replaces with the standard library calls, e.g. `ADD(dt, t1, t2)` becomes `ADD_DT_TIME(ADD_DT_TIME(dt, t1), t2)`. An argument no arithmetic is defined for reports E156. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Problem: The standard library carries a generic overload of ADD and MUL and about sixty `ADD__X__Y`-style functions whose only purpose is to give the compiler's generic resolution a symbol to link against. Solution: The builtins carry out date and time arithmetic through the IEC-named functions now, so the overload, the nine ST shims, and the Rust alias exports go. Object files compiled against those symbols must be recompiled. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
ghaith
force-pushed
the
feat/prg-4854
branch
from
September 29, 2026 05:12
2a79679 to
9148d08
Compare
|
7 findings in 13m 53s for $0.69 between
|
volsa
previously approved these changes
Sep 30, 2026
volsa
marked this pull request as draft
September 30, 2026 10:54
Problem: Codegen stores the result of an expression the resolver replaced (the builtins ADD, SUB, MUL, DIV, date and time operators, string comparisons) without converting it to the type of the target. `x := MUL(t, 1.5)` with an LREAL `x` writes the TIME bits into the double and reads 0.0, and `(tod + T#20s)` in parentheses skips the replacement and does not wrap at midnight. Solution: Generate the replacement where every expression value is generated, so the replaced value takes the same conversion to its hint as any other value, also inside parentheses. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Problem: The built-in reference still limits ADD and MUL to ANY_NUM and says no built-in needs a library, the standard library family table drops the ADD and MUL overloads that still ship, and several technical pages overstate which date and time calls become library calls or report E156 and E157. Solution: Describe the date and time forms of the arithmetic builtins and their library dependency, restore the overloads in the family table, and narrow the affected statements to what the compiler does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
volsa
marked this pull request as ready for review
September 30, 2026 11:24
|
3 findings in 3m 20s for $0.56 between
|
Problem: An expression passed to a by-reference input, such as
`read(ADD(n, f()))` or `read(n + f())` for a `VAR_INPUT {ref}`, was
generated twice: once to find out that it is not an lvalue, and again to
store it in a temporary. A side effect in the argument ran twice.
Solution: Store the value that was already generated, converted to the
type hint of the argument like any other generated expression.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The fallback for an argument no arithmetic is defined for visited the call arguments a second time, although the resolver visits them before it calls the builtin annotation. The biggest argument type is now only computed for a chain of numbers, the only case that uses it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Problem: `t / 0` is rejected with E123, but `DIV(t, 0)` compiled without a diagnostic. For a TIME the call then reaches the standard library, which panics on a zero divisor at runtime. Solution: The DIV builtin applies the zero divisor check of the `/` operator to its argument IN2. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Problem: For reordered named arguments, such as `SUB(IN2 := dt, IN1 := t)`, the E156 diagnostic underlined only `t`, because the span was built in parameter order and its end came before its start in the source. Solution: Span the arguments of each folded step from the first to the last one as they are written in the source. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
3 findings in 3m 46s for $0.60 between
|
The divisor check wrote the parameter names of DIV once more. The DIV validation now names them once and hands them to both of its checks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
0 findings in 3m 12s for $0.56 between |
volsa
enabled auto-merge
October 1, 2026 09:20
volsa
approved these changes
Oct 1, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem: The standard library declares a generic
ADD<T1, T2>andMULoverload and about sixtyADD__X__Y-style functions whose only purpose is to give the compiler's generic resolution a symbol to link against, because the builtins only accept numbers. Arithmetic with a date or time argument depends on those shims, andADD(dt, t, t)is rejected.Solution: The builtins own all arithmetic. A table of the combinations IEC 61131-3 defines types and validates every
ADD/SUB/MUL/DIVcall; numbers expand to chained operators as before, and a call with a date or time argument expands to the same chain, whose operators the resolver already replaces with the standard library calls (ADD(dt, t, t)becomesADD_DT_TIME(ADD_DT_TIME(dt, t), t)). Every shim leaves the standard library; theADDandMULoverloads stay, because they giveADD(IN1 := a, b)its parameter name. Codegen now also converts the result of a replaced expression to the type of its target, sox := MUL(t, 1.5)with anLREALxno longer stores the rawTIMEbits; this affected the numeric builtins and the date and time operators on master too. MovingADD_TIMEand friends into the builtins as well is a follow-up: each row needs its own instructions in codegen (unit conversion for DT and DATE, reduction modulo one day for a time of day, saturation for a real factor, a defined zero divisor).Refs: PRG-4854
Breaking:
ADDon two strings, or on any argument no arithmetic is defined for, is an error now (E156).ADD__*,SUB__*,MUL__TIME__*,DIV__TIME__*symbols and their long-family counterparts are gone fromiec61131std; objects compiled against them must be recompiled.🤖 Generated with Claude Code