fix: xx pack[i] to a protocol target heap-copies the element
Erasing a single comptime-pack element to a protocol value (`xx sources[0]` with a protocol target) tripped the pack-as-value error: buildProtocolErasure treated the index_expr as an lvalue and took its address via lowerExprAsPtr, whose .index_expr arm lowers the bare pack as a value (a pack is comptime-only with no runtime storage). isLvalueExpr now reports a comptime pack index as an rvalue, decided via the same packArgNodeAt predicate the value path uses — so the value and lvalue paths can't diverge on what counts as a pack element — and erasure heap-copies the already-materialized element instead. Resolves issue 0135. Regression tests: examples/0547, 0548.
This commit is contained in:
27
examples/0547-packs-xx-pack-index-to-protocol.sx
Normal file
27
examples/0547-packs-xx-pack-index-to-protocol.sx
Normal file
@@ -0,0 +1,27 @@
|
||||
// `xx <pack>[i]` erased to a protocol-typed local.
|
||||
//
|
||||
// Erasing a single comptime-pack element to a protocol scalar routes through
|
||||
// buildProtocolErasure. A pack index is a comptime rvalue (a pack has no
|
||||
// runtime storage — `sources[i]` resolves to the call-site arg, which only
|
||||
// gets storage when lowered as a value), so the erasure must heap-copy the
|
||||
// materialized element rather than take its address.
|
||||
//
|
||||
// Regression (issue 0135): `xx sources[0]` used to lower the bare pack as a
|
||||
// value and error with "pack 'sources' has no runtime value".
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
VL :: protocol(T: Type) { get :: () -> T; }
|
||||
IntCell :: struct { v: i64; }
|
||||
impl VL(i64) for IntCell { get :: (self: *IntCell) -> i64 => self.v; }
|
||||
|
||||
first :: (..sources: VL) -> i64 {
|
||||
x : VL(i64) = xx sources[0]; // erase element 0 to VL(i64)
|
||||
return x.get();
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
print("{}\n", first(IntCell.{ v = 7 })); // 7
|
||||
print("{}\n", first(IntCell.{ v = 42 }, IntCell.{ v = 99 })); // 42 (element 0)
|
||||
0
|
||||
}
|
||||
25
examples/0548-packs-xx-pack-index-two-elements.sx
Normal file
25
examples/0548-packs-xx-pack-index-two-elements.sx
Normal file
@@ -0,0 +1,25 @@
|
||||
// Erase two DISTINCT comptime-pack elements to protocol locals — each gets
|
||||
// its own heap copy and resolves to its OWN concrete type's method (IntCell.get
|
||||
// vs Doubler.get), proving the per-element erasure picks the right vtable.
|
||||
//
|
||||
// Regression (issue 0135): single-element `xx pack[i]` erasure to a protocol
|
||||
// scalar was unsupported (the bare pack lowered as a value and errored).
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
VL :: protocol(T: Type) { get :: () -> T; }
|
||||
IntCell :: struct { v: i64; }
|
||||
impl VL(i64) for IntCell { get :: (self: *IntCell) -> i64 => self.v; }
|
||||
Doubler :: struct { n: i64; }
|
||||
impl VL(i64) for Doubler { get :: (self: *Doubler) -> i64 => self.n * 2; }
|
||||
|
||||
sum_two :: (..sources: VL) -> i64 {
|
||||
a : VL(i64) = xx sources[0]; // erase element 0
|
||||
b : VL(i64) = xx sources[1]; // erase element 1
|
||||
return a.get() + b.get();
|
||||
}
|
||||
|
||||
main :: () -> i32 {
|
||||
print("{}\n", sum_two(IntCell.{ v = 10 }, Doubler.{ n = 16 })); // 10 + (16*2) = 42
|
||||
0
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
7
|
||||
42
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
42
|
||||
Reference in New Issue
Block a user