Skip to content

Inheritance/interface override of a REFERENCE TO property is rejected #1750

Description

@Angus-Bethke-Bachmann

Describe the bug
Inheritance/interface override of a REFERENCE TO property is rejected. Both an override in a derived FB and an FB implementing an interface that declares a REFERENCE TO property fail at the signature-compatibility check, because the synthesized return-val parameter is named after the enclosing POU rather than after the property.

To Reproduce

// A derived FB overrides a parent's PROPERTY_GET ... REFERENCE TO ...
// We then access through both the parent ref and the child ref.

TYPE Pair :
    STRUCT
        a : INT;
        b : INT;
    END_STRUCT
END_TYPE

FUNCTION_BLOCK parent
    VAR
        _p_parent : Pair;
    END_VAR

    PROPERTY_GET p : REFERENCE TO Pair
        p REF= _p_parent;
    END_PROPERTY
END_FUNCTION_BLOCK

FUNCTION_BLOCK child EXTENDS parent
    VAR
        _p_child : Pair;
    END_VAR

    // Override the GET: route to the child's own pair instead.
    PROPERTY_GET p : REFERENCE TO Pair
        p REF= _p_child;
    END_PROPERTY
END_FUNCTION_BLOCK

FUNCTION main : INT
    VAR
        c : child;
        v_parent_field : INT;
        v_child_field : INT;
    END_VAR
    c._p_parent.a := 1;     // mutate parent's struct directly
    c._p_child.a  := 2;     // mutate child's struct directly

    // Read through the overridden child property — should yield 2
    v_child_field := c.p.a;

    main := v_child_field;
END_FUNCTION

/*
  error[E112]: Derived methods with conflicting signatures, parameters do not match:
  note[E118]: Expected parameter `__parent___get_p_return_val`
              but got        `__child___get_p_return_val`
*/
// REFERENCE TO property declared in an INTERFACE,
// accessed through an interface-typed variable.
// Stresses the polymorphism+REFERENCE-TO interaction (the new fat-pointer
// constructor calls in interface dispatch snapshots came from this PR).

TYPE Pair :
    STRUCT
        a : INT;
        b : INT;
    END_STRUCT
END_TYPE

INTERFACE IPair
    PROPERTY_GET p : REFERENCE TO Pair END_PROPERTY
END_INTERFACE

FUNCTION_BLOCK fb IMPLEMENTS IPair
    VAR
        _p : Pair;
    END_VAR
    PROPERTY_GET p : REFERENCE TO Pair
        p REF= _p;
    END_PROPERTY
END_FUNCTION_BLOCK

FUNCTION main : INT
    VAR
        x      : fb;
        iface  : IPair;
        v      : INT;
    END_VAR
    iface := x;
    x._p.a := 13;
    v := iface.p.a;
    main := v;       // expect 13
END_FUNCTION

/*
  error[E112]: Derived methods with conflicting signatures, parameters do not match:
  note[E118]: Expected parameter `__IPair___get_p_return_val`
              but got        `__fb___get_p_return_val`
*/

Expected behavior
No error should occur.

Suggested Fix
Keep the per-POU parameter naming (which is genuinely needed to disambiguate same-named properties across unrelated POUs) but teach the signature-compat validator to ignore synthesized parameters. The override check should compare only the user-written property types — i.e. the original REFERENCE TO Pair declaration on both sides — not the synthetic return-val slot that the lowerer is about to add.

Concretely, this probably wants:

  • An explicit marker on VariableIndexEntry (e.g. is_synthetic_property_return_ref: bool) set by ReferenceToReturnLowerer::visit_pou when it inserts the new VAR_INPUT variable.
  • The override-compatibility checker filters out parameters carrying that flag before comparing parameter lists / return types.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions