Skip to content

Multi-file compilation fails when a non-implementing FB that consumes an interface is in its own file #1649

@ghaith

Description

@ghaith

Multi-file compilation fails when a non-implementing FB that consumes an interface is in its own file

Description

When compiling multiple .st files, a function block that:

  1. Holds an interface reference as a member variable
  2. Calls methods on it
  3. Does not itself IMPLEMENTS the interface

...fails with Unknown type: ____itable_<Interface>_<Method> if it is in a separate file from both the interface definition and any implementor.

The same code works in a single file, or when the consumer FB shares a file with either the interface definition or an implementor.

Minimal reproduction

iface.st

INTERFACE IFoo
    METHOD bar : DINT
    END_METHOD
END_INTERFACE

impl.st

FUNCTION_BLOCK FbImpl IMPLEMENTS IFoo
    METHOD bar : DINT
        bar := 42;
    END_METHOD
END_FUNCTION_BLOCK

consumer.st

FUNCTION_BLOCK FbConsumer
    VAR
        stored : IFoo;
    END_VAR

    METHOD invoke : DINT
        invoke := stored.bar();
    END_METHOD
END_FUNCTION_BLOCK

main.st

FUNCTION main
    VAR
        impl : FbImpl;
        consumer : FbConsumer;
    END_VAR
END_FUNCTION
$ plc iface.st impl.st consumer.st main.st -o out
Unknown type: ____itable_IFoo_bar.

What works

Layout Result
All in one file
consumer + interface in same file
consumer + implementor in same file
consumer in its own file Unknown type: ____itable_...

Analysis

This is the itable analogue of the vtable dependency bug fixed in #1535.

PR #1535 added explicit __vtable_<POU> dependency resolution in get_datatype_dependencies (src/resolver.rs) for the Class | FunctionBlock case, because the vtable pointer is declared as VOID and the actual struct type would otherwise be missed.

The same gap exists for itables. The itable struct types (__itable_<Interface>) are generated in generate_itable_definitions (src/lowering/polymorphism/table/interface.rs), which only iterates over unit.interfaces — i.e. interfaces declared in the current compilation unit. When an FB in a separate file merely consumes an interface (holds it as a member, calls methods on it) without declaring or implementing it, no itable types are emitted for that unit, and the internal function pointer types (____itable_<Interface>_<Method>) are never generated.

Workaround

Keep the consumer FB in the same file as either the interface definition or one of its implementors.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions