Skip to content

[bug] A generic instance reads its pattern's lifecycle facts, so an enum over Box<i32> is SC116E #85

Closed

Description

@Ze7111

Compiler version

kairo-0.1.1+dev.20261024

Compiler stage

Stage 1 (self-hosted)

Host platform

Linux (x86_64)

Minimal reproduction

// Tests/Bugs/Triage/F3-generic-instance-lifecycle-facts-unknown.k

// build: kairo F3-generic-instance-lifecycle-facts-unknown.k   (expect exit 0)
class <T> Box { pub var v: T }

// Box<i32> is trivially copyable, but its facts are read off the pattern
// Box<T>, where they are Unknown.
enum W { Has { b: Box<i32> }, Empty }

fn main() -> i32 {
    var w = W::Has { b: Box<i32>() }
    return 0
}

Command line

build/x86_64-linux-gnu/debug/bin/kairo --resource-dir=build/llvm/lib/clang/22 --builtins-dir=Lib/builtin --std-dir=Lib/std Tests/Bugs/Triage/F3-generic-instance-lifecycle-facts-unknown.k

Actual behavior

error @ Tests/Bugs/Triage/F3-generic-instance-lifecycle-facts-unknown.k:6
    4 | // Box<i32> is trivially copyable, but its facts are read off the pattern
    5 | // Box<T>, where they are Unknown.
    6 | enum W { Has { b: Box<i32> }, Empty }
      |      ^         ^^^^^^^^^^^
      |      [SC116E] an enum whose payload's lifecycle is not known until instantiation is not yet supported
    note @ Tests/Bugs/Triage/F3-generic-instance-lifecycle-facts-unknown.k:6
       4 | // Box<i32> is trivially copyable, but its facts are read off the pattern
       5 | // Box<T>, where they are Unknown.
       6 | enum W { Has { b: Box<i32> }, Empty }
         |                ^ 'b' of variant 'Has' has type 'Box<i32>', whose copy, move and destruction are not known until instantiation

Exit code 1.

Expected behavior

The program compiles and exits 0. A generic instance gets lifecycle facts computed from its substituted field, payload and base types: Box<i32> is trivially copyable and destructible, so W can be laid out. --print-sema should print a lifecycle row for the instance (Box<i32>: trivial) instead of only the pattern's all-? row.

Additional context

SC116E is a deliberate interim gate, not a regression: it is asserted today by Tests/Sema/Check/adt_unknown_facts.k, and it goes away with this work.

ClassLifecycle (Compiler/Sema/Check/ClassLifecycle.k) computes facts on the PATTERN only. A fact that depends on a generic parameter is Unknown, and every instance reads its pattern's facts, so Box<i32> reads all-Unknown. --print-sema on the repro prints only

  lifecycle Box: category=? trivial_copy=? trivial_dtor=? destructible=?
  lifecycle W: category=? trivial_copy=? trivial_dtor=? destructible=?

Every rule that reads facts skips Unknown, with a comment pointing at this work: SC056E (virtual destructor), SC061E (base/derived category), SC051E (movability). Those rules see nothing in generic code. The same goes for transfer checking in a generic body (see the transfer-sites ticket).

Suggested fix: when Mono fills an instance, compute its facts from the substituted types, memoize them on the instance decl, and re-run the skipped rules on the instance. Then remove the SC116E gate for non-generic ADTs (the Unknown case in EnumLayoutLowering's non-generic path), and flip Tests/Sema/Check/adt_unknown_facts.k to a codegen test.

Tests: --print-sema lifecycle rows for Opt<i32> (trivial) vs an Opt<Mv> with a MOVE payload (trivial_copy=0); SC056E on a class with a non-virtual base that holds Opt<Mv>, none for Opt<i32>.

Activity

  1. added theissue type on Oct 24, 2026
  2. Ze7111 commented on Nov 9, 2026

    @Ze7111
    CollaboratorAuthor

    a non-generic enum over a concrete generic instance (Box) reading its pattern's unknown lifecycle facts and failing with SC116E, fixed in commit f488671

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugIssues indicating incorrect or broken behavior.Memory ManagementIssues regarding allocation, tracking, and leaks.Sema - Check PassSema - Mono PassSemantic AnalysisPertaining to type checking, scopes, or analysis.

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions