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:
- Holds an interface reference as a member variable
- Calls methods on it
- 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.
Multi-file compilation fails when a non-implementing FB that consumes an interface is in its own file
Description
When compiling multiple
.stfiles, a function block that:IMPLEMENTSthe 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
impl.st
consumer.st
main.st
What works
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 inget_datatype_dependencies(src/resolver.rs) for theClass | FunctionBlockcase, because the vtable pointer is declared asVOIDand the actual struct type would otherwise be missed.The same gap exists for itables. The itable struct types (
__itable_<Interface>) are generated ingenerate_itable_definitions(src/lowering/polymorphism/table/interface.rs), which only iterates overunit.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.