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.
Area
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 deriveCloneshould either supportclone()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 --libgenerates Rust that does not wrap model constructors in the generated union enum. Recursive union payloads also lower to Rust recursive types with infinite size, andexpr.clone()on a union reports thatUnion[...]has noclone(...)method even when all variants deriveClone.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:Run:
Repro 2: union of cloneable model variants has no
clone()Run:
Output / logs
Repro 1 fails during Rust build:
Repro 2 fails during typecheck:
A direct recursive enum/union payload also reaches Rust with
E0072infinite-size recursion instead of receiving an Incan diagnostic or supported indirection lowering.Environment
OS: macOS (local worker)
Rust: local toolchain through
incan build --libIncan:
incan 0.3.0-rc2, commit8003bdad(bugfix - bind public callable aliases from manifests (#617))Command:
/Users/danny/Development/encero/incan/target/debug/incan build --liband/Users/danny/Development/encero/incan/target/debug/incan --check repro.incnBlocking 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.