Skip to content

v1: emitDefinitions emits the flat compiled name for custom class types instead of the namespace-qualified type #1758

Description

@markwpearce

Summary

When emitDefinitions: true generates a .d.bs typedef for a function whose signature references a custom class type declared inside a namespace, the emitted parameter/return type is the class's flat compiled symbol name (e.g. BGE_Room) instead of the properly namespace-qualified type reference (BGE.Room) that a consumer would actually need to resolve it against the real class declaration.

This breaks type-checking for any consumer of a published/distributed .d.bs who tries to pass an instance of that class (or a subclass of it) into the annotated function - a very common shape for any object-oriented BrighterScript library.

This reproduces with no ropm involved at all - it's present in this project's own straight bsc build output.

Repro

Source (namespace BGE, unqualified same-namespace type reference - the normal, idiomatic way to write this):

namespace BGE
  sub defineRoom(newRoom as Room)
    ' ...
  end sub
end namespace

Compiled .d.bs (via emitDefinitions: true):

namespace BGE
    sub defineRoom(newRoom as BGE_Room)
    end sub
end namespace

BGE_Room here is the class's flattened runtime symbol name (what Room compiles down to as a constructor-style function), not a real, resolvable type from a consumer's perspective - there is no actual BGE_Room type declared anywhere. I also tried fully qualifying the source annotation (as BGE.Room instead of the same-namespace-shorthand as Room) and got the identical broken output - the flat name is emitted either way, so this isn't something a package author can work around by changing how they write the annotation.

Consumer-side symptom

A downstream project that consumes this typedef (published to npm, installed via plain npm install + a manual roku_modules copy, or via ropm install - reproduced both ways) and does the completely ordinary thing of subclassing an exported class and passing an instance to the annotated function:

class MainRoom extends BGE.Room
  sub new(game as BGE.Game)
    super(game)
  end sub
end class
' ...
game.defineRoom(new MainRoom(game))

...gets:

error argument-type-mismatch: Argument of type 'MainRoom' is not compatible with parameter of type 'BGE_Room'

Every function signature across the whole engine (this reproduced on a real ~200-file game engine library) that takes or returns one of its own classes hits this - defineRoom, addEntity, and many more.

Why this matters more than it might look

Note this is purely a static type-checker false positive - .brs type annotations aren't enforced at runtime, so the actual compiled code runs correctly regardless. But it means any consumer following the common best practice of gating CI on bsc --validate passing cleanly gets real, confusing, unfixable-on-their-end errors for completely ordinary object-oriented usage (subclassing an exported class) - the single most common usage pattern for any published OO BrighterScript library.

Environment

  • brighterscript@^1.0.0-alpha.50
  • Reproduced both with and without ropm in the loop (this is not a ropm bug - see the separate, unrelated issue I filed there, Improve hot functions: #148, for an actual ropm renaming bug found in the same investigation)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions