Skip to content

Codegen: iterating a List of records (map/fold + field access) emits invalid LLVM IR (both flavors) #158

Description

@MelbourneDeveloper

Summary

Iterating a list of records with map/fold where the lambda accesses a record field emits invalid LLVM IR and fails to compile. Reproduces in both flavors (Default .osp and ML .ospml), native and wasm32.

The list element (a record pointer) is materialized as i64, then the field-access lowering bitcasts an i8* it never received — the SSA value is i64, not a pointer:

error: '%r20' defined with type 'i64' but expected 'ptr'
   %r23 = bitcast i8* %r20 to { i64, i64, i64 }*

Reproduction (Default flavor)

type Order = { qty: int, price: int }
fn mk(q, p) = Order { qty: q, price: p }
let orders = [mk(2, 5), mk(3, 4), mk(1, 9)]
let revenue = fold(orders, 0, fn(acc, o) => acc + (o.qty * o.price))
print("revenue ${revenue}")
$ osprey orders.osp --run
orders.ll:64:22: error: '%r20' defined with type 'i64' but expected 'ptr'
   %r23 = bitcast i8* %r20 to { i64, i64, i64 }*

Reproduction (ML flavor)

type Order =
    qty : int
    price : int

mk (q, p) =
    Order
        qty = q
        price = p

orders = [mk (2, 5), mk (3, 4), mk (1, 9)]
revenues = map orders (\o => o.qty * o.price)
print "first ${listLength orders}"

Same bitcast i8* %rN to { i64, i64, i64 }* IR error.

Expected

revenue = 2*5 + 3*4 + 1*9 = 31. The element handed to the reducer/mapper is a record value; field access must load through the record pointer, not bitcast an i64.

Notes / scope

  • Records as standalone values work (construct + field access). Lists of ints + fold/map/filter work. It is specifically List<record> + iteration with field access that miscompiles.
  • Likely lives in the list-literal element representation (boxing record pointers as i64) interacting with field-access codegen — plausibly related to Collections: rewire list/map literal codegen to runtime builders #65 (Collections: rewire list/map literal codegen to runtime builders).
  • Surfaced while building the examples/wasm analytics demo; worked around there by accumulating per-row data through an effect handler instead of folding a List<record>.

Environment

  • Branch: prototyping (ML-flavor frontend work)
  • Target: native + wasm32 (both)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions