Skip to content

fix: 'else if' is now lowered into an else > if > else#1620

Merged
Angus-Bethke-Bachmann merged 6 commits intomasterfrom
antb/PRG-3920
Mar 12, 2026
Merged

fix: 'else if' is now lowered into an else > if > else#1620
Angus-Bethke-Bachmann merged 6 commits intomasterfrom
antb/PRG-3920

Conversation

@Angus-Bethke-Bachmann
Copy link
Contributor

Changed

  • 'else if' is now lowered into an else > if > else to ensure functions that return aggregate are not always evaluated when a previous control statement returns true

Testing

  • Added a lit test to reproduce the error and confirmed that the error is resolved
  • Added a unit test to verify the AST changes

@Angus-Bethke-Bachmann Angus-Bethke-Bachmann linked an issue Mar 5, 2026 that may be closed by this pull request
Copy link
Member

@mhasel mhasel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work!

Can you have a look at the complex_call_statement_in_elif_condition test in rusty/src/lowering/calls.rs - we have an example there with a FIXME comment about side-effects for calls in elsif blocks - they were always being evaluated.

Your PR should solve this, but I'd like to see it proven in a test aswell. E.g.:

IF TRUE THEN
ELSIF printHello()
END_IF

The test should fail if printHello actually prints anything.
Then please also remove the now outdated FIXME comment.

Side note: I feel like this change should have maybe affected some IR snapshots aswell, but that doesn't seem to be the case. Maybe something to look into. Maybe it's a lack of coverage, but I would have expected the generated IR to change if these side effects are now no longer reproducible.

@@ -0,0 +1,255 @@
use plc_ast::{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you maybe add a top-level comment explaining the motivation/reason to do this? if someone is unaware of the aggregate-type lowering regression/behaviour for if/elsif/else blocks, this might look very strange and like an absolutely mental thing to do 😄

Copy link
Contributor Author

@Angus-Bethke-Bachmann Angus-Bethke-Bachmann Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added a top-level comment detailing the purpose of this lowerer.

PS: Replying to your top comment here as well 😄

I have also removed the FIXME and adjusted that test to include the additional lowerer. Snapshot changes look to be as expected.

With regards to the IR changes, it looks like the codegen test utility is not using the pipeline participants, so I have manually added the lowerer to the test utility... but I did leave a comment stating that it is probably a good idea (at some point in the future) for the codegen test utility to use all of the participants (this would give us a more accurate reflection of the code that would be generated by the compiler). Bonus points if we use the same mechanism to fetch the participants as that would mean that if we add a new participant it is automatically consumed by the codegen test utility and all codegen test snapshots would update to reflect that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, of course - the test utils. I've stumbled over this a few times myself. I think one of the reasons we kept them is #1407. Another one is the fact that the compiler isn't yet fully split into separate crates, creating circular dependencies when trying to import certain runners into the rusty main crate.
Definitely something to look at in future.

@@ -0,0 +1,44 @@
// RUN: (%COMPILE %s && %RUN) | %CHECK %s
FUNCTION foo : ARRAY[0..1] OF STRING[10]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to see some codegen (IR-snapshot) tests for this aswell.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done 😄

You will find them under src/codegen/tests/control_statement_tests.rs

assert_eq!(implementation.name, "mainProg");

let control_statement = &implementation.statements[2];
assert_snapshot!(format!("{:#?}", control_statement), @r#"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make use of the AstSerializer here, reads nicer imo.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done 😄

use plc_source::SourceCode;

#[test]
fn elseif_is_lowered_to_else_with_nested_if() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Can you think of some further tests and edge-cases to test here? Maybe brainstorm a bit with a clanker, usually works pretty good (opus 4.6 or gpt 5.X models).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For example

PROGRAM mainProg
VAR
    i : INT;
    val : INT;
    cVar : CHAR;
END_VAR

FOR i := 0 TO 10 DO
    IF val = 3 THEN
        cVar := 'f';
    ELSIF val = 5 THEN
        cVar := 'b';
    ELSE
        cVar := 'x';
    END_IF
END_FOR
END_PROGRAM

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added some additional test cases that I could think of. Is that sufficient?

@Angus-Bethke-Bachmann Angus-Bethke-Bachmann merged commit 045af77 into master Mar 12, 2026
33 checks passed
@Angus-Bethke-Bachmann Angus-Bethke-Bachmann deleted the antb/PRG-3920 branch March 12, 2026 12:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ELSIF conditional regression

3 participants