Skip to content

E043 false positive for nested struct/array initializers since const-folding into constructors (#1826) #1833

Description

@ghaith

Note

This issue was drafted by Claude on behalf of @ghaith.

Bug description

Initializing an array of structs that contain a nested array of structs produces a false-positive E043:

error[E043]: Struct initializers within arrays have to be wrapped by `()`

The inner struct initializers are wrapped in parentheses; the diagnostic is raised anyway and, being error-severity, blocks compilation.

Reproduction

TYPE
    Inner : STRUCT
        value : DINT;
    END_STRUCT;
    Outer : STRUCT
        arr : ARRAY[0..1] OF Inner;
    END_STRUCT;
END_TYPE

FUNCTION main
    VAR
        varArr : ARRAY[0..1] OF Outer := [(arr := [(value := 10), (value := 20)]),
                                          (arr := [(value := 30), (value := 40)])];
    END_VAR
    PRINTF('varArr[0].arr[1].value = %d$N', varArr[0].arr[1].value);
    PRINTF('varArr[1].arr[0].value = %d$N', varArr[1].arr[0].value);
END_FUNCTION

plc --check repro.st reports E043 on each inner (value := ...) element. Expected: compiles cleanly and prints

varArr[0].arr[1].value = 20
varArr[1].arr[0].value = 30

(verified on the commit before the regression). Lit-ready version for the fix:

// RUN: (%COMPILE %s && %RUN) | %CHECK %s
TYPE
    Inner : STRUCT
        value : DINT;
    END_STRUCT;
    Outer : STRUCT
        arr : ARRAY[0..1] OF Inner;
    END_STRUCT;
END_TYPE

FUNCTION main
    VAR
        varArr : ARRAY[0..1] OF Outer := [(arr := [(value := 10), (value := 20)]),
                                          (arr := [(value := 30), (value := 40)])];
    END_VAR
    PRINTF('varArr[0].arr[1].value = %d$N', varArr[0].arr[1].value);
    // CHECK: varArr[0].arr[1].value = 20
    PRINTF('varArr[1].arr[0].value = %d$N', varArr[1].arr[0].value);
    // CHECK: varArr[1].arr[0].value = 30
END_FUNCTION

Root cause

Regressed by 1fc8dea (#1826). Three pieces interact:

  1. Since fix: const-fold array initializers before lowering into constructors #1826, the initializer lowering prefers the const evaluator's folded statement over the raw initializer AST when generating constructor bodies (folded_array_initializer in compiler/plc_lowering/src/initializer.rs).
  2. The const evaluator strips parentheses while folding: evaluating a ParenExpression returns the evaluated inner expression without re-wrapping it (src/resolver/const_evaluator.rs:654). This was harmless before fix: const-fold array initializers before lowering into constructors #1826 because the folded statement was only consumed by codegen's literal generators, which don't care about parens.
  3. Validation runs after lowering, so validate_array_of_structs (src/validation/array.rs) now sees the paren-stripped clone inside the generated constructor: a LiteralArray of bare Assignment nodes where it requires ParenExpression elements. Each element is flagged as E043, reported at the original source spans because the cloned nodes keep their locations.

Only the nested shape (struct → array of structs) is affected — the flat-array cases covered by #1826's test have no struct elements for the validator to check.

Candidate fixes: preserve the ParenExpression wrapper when the const evaluator folds struct initializers (paren-stripping is where the information is lost), or make the post-lowering validation tolerant of folded bare-Assignment elements.

Affected versions

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions