Skip to content

bug - Union model variants fail build/codegen and do not derive Clone #620

@dannymeijer

Description

@dannymeijer

Area

  • Compiler (frontend/backend/codegen)
  • Incan Language (syntax/semantics)

Summary

Expected: A Union[...] of model variants should build when constructors are used at values of the union type, and a union whose variants all derive Clone should either support clone() or produce a clear typechecking diagnostic before codegen. Recursive expression trees should also need a clear supported pattern or a frontend diagnostic if direct recursion is not supported.

Actual: Type checking accepts the source, but incan build --lib generates Rust that does not wrap model constructors in the generated union enum. Recursive union payloads also lower to Rust recursive types with infinite size, and expr.clone() on a union reports that Union[...] has no clone(...) method even when all variants derive Clone.

This surfaced while converting InQL's scalar expression tree from a tag/payload model to a v0.3 union-shaped model for PR dannys-code-corner/InQL#29.

Reproduction steps

Repro 1: model union constructors are not wrapped in generated Rust

Create /tmp/union_list_repro:

# incan.toml
[project]
name = "union_list_repro"
version = "0.1.0"
# src/lib.incn
@derive(Clone)
pub model Leaf:
    pub value: int


@derive(Clone)
pub model Pair:
    pub args: list[Expr]


pub type Expr = Union[Leaf, Pair]


pub def pair() -> Expr:
    return Pair(args=[Leaf(value=1), Leaf(value=2)])


pub def sum_expr(expr: Expr) -> int:
    match expr:
        Leaf(leaf) => return leaf.value
        Pair(pair) => return sum_expr(pair.args[0])

Run:

/Users/danny/Development/encero/incan/target/debug/incan build --lib

Repro 2: union of cloneable model variants has no clone()

@derive(Clone)
model Leaf:
    value: int


@derive(Clone)
model Pair:
    left: Expr
    right: Expr


type Expr = Union[Leaf, Pair]


def use_expr(expr: Expr) -> int:
    match expr:
        Leaf(leaf) => return leaf.value
        Pair(pair) => return use_expr(pair.left)


def clone_expr(expr: Expr) -> Expr:
    return expr.clone()

Run:

/Users/danny/Development/encero/incan/target/debug/incan --check repro.incn

Output / logs

Repro 1 fails during Rust build:

error[E0308]: mismatched types
  --> src/lib.rs:60:20
   |
60 |         args: vec![Leaf { value : 1 }, Leaf { value : 2 }],
   |                    ^^^^^^^^^^^^^^^^^^ expected `__IncanUniond44f4244dd4f043b`, found `Leaf`
   |
help: try wrapping the expression in `__IncanUniond44f4244dd4f043b::V0`

error[E0308]: mismatched types
  --> src/lib.rs:59:12
   |
58 |   pub fn pair() -> Expr {
   |                    ---- expected `__IncanUniond44f4244dd4f043b` because of return type
59 |       return Pair {
   |  ____________^
60 | |         args: vec![Leaf { value : 1 }, Leaf { value : 2 }],
61 | |     };
   | |_____^ expected `__IncanUniond44f4244dd4f043b`, found `Pair`

Repro 2 fails during typecheck:

type error: Type 'Union[Leaf, Pair]' has no method 'clone(...)'
  --> repro.incn:22:12
   |
22 |     return expr.clone()
   |            ^^^^^^^^^^^^

A direct recursive enum/union payload also reaches Rust with E0072 infinite-size recursion instead of receiving an Incan diagnostic or supported indirection lowering.

Environment

OS: macOS (local worker)
Rust: local toolchain through incan build --lib
Incan: incan 0.3.0-rc2, commit 8003bdad (bugfix - bind public callable aliases from manifests (#617))
Command: /Users/danny/Development/encero/incan/target/debug/incan build --lib and /Users/danny/Development/encero/incan/target/debug/incan --check repro.incn

Blocking status / workaround

This blocks an honest InQL refactor to Union[ColumnRefExpr, IntLiteralExpr, ...] model variants. InQL can continue with a data-carrying enum plus list-backed recursive operands, but that is a workaround around union/model codegen rather than the intended v0.3 union-model showcase shape.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingincan compilerSuggestions, features, or bugs related to the Compiler (frontend/backend/codegen)incan language semanticsSuggestions, features, or bugs related to the Incan Language itself (syntax and semantics)

    Type

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions