Thanks for the detailed report, PaulS. That was a real bug, not anything you were doing wrong, and it's now fixed for the next release: https://feedback.objo.dev/bug/1143
What was happening
The error wasn't actually specific to concatenation. Any bare reference to a module constant or variable from a method failed if the member was declared after the method in the module:
Module modGlobal
Sub Build(IconName As String)
Var iconfile As String = IconName + file_extension_svg # "Undefined identifier"
End Sub
Const file_extension_svg As String = ".svg"
End Module
The generated code and the runtime were fine with this all along - it was purely a compile-time resolution bug. The type checker resolves bare module members through the lexical scope as it reads the file top-to-bottom, and the module fallback path only knew about methods, not constants or variables. So:
- A constant or variable declared after the method that used it wasn't visible →
Undefined identifier.
- Declaring it before the method worked.
- Qualifying it (
modGlobal.file_extension_svg) worked, because qualified access uses an order-independent member table.
- Class constants were never affected because they take a different (order-independent) resolution path.
bgrommes, this is why your class-level constants worked — and why PaulS's workaround (moving the constant to modGlobal and qualifying it) made it vanish.
The fix
Module methods can now reference module constants and variables by their bare name regardless of declaration order - matching how module-to-module method calls already behaved, and how class members behave. Your original line now compiles as written:
Module modGlobal
Sub Build(IconName As String)
Var iconfile As String = IconName + file_extension_svg # works now
End Sub
Const file_extension_svg As String = ".svg"
End Module
Of course end users can't really determine the order declarations are processed - the IDE handles this so this was a nasty bug that has now been squashed.