Skip to content

Commit 5b8ce03

Browse files
Stevengredkcumming
andauthored
feat(rt): handle zero-sized locals (#809)
Co-authored-by: Daniel Cumming <124537596+dkcumming@users.noreply.github.com>
1 parent 63cd6a5 commit 5b8ce03

File tree

7 files changed

+63
-24
lines changed

7 files changed

+63
-24
lines changed

kmir/src/kmir/decoding.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
Single,
2525
StrT,
2626
StructT,
27+
TupleT,
2728
UintT,
2829
WrappingRange,
2930
)
@@ -190,6 +191,8 @@ def decode_value(data: bytes, type_info: TypeMetadata, types: Mapping[Ty, TypeMe
190191
return _decode_array(data, elem_ty, length, types)
191192
case StructT(fields=fields, layout=layout):
192193
return _decode_struct(data=data, fields=fields, layout=layout, types=types)
194+
case TupleT(components=components):
195+
return _decode_tuple(data=data, component_tys=components, types=types)
193196
case EnumT(
194197
discriminants=discriminants,
195198
fields=fields,
@@ -282,6 +285,20 @@ def _decode_struct(
282285
return AggregateValue(0, field_values)
283286

284287

288+
def _decode_tuple(
289+
*,
290+
data: bytes,
291+
component_tys: list[Ty],
292+
types: Mapping[Ty, TypeMetadata],
293+
) -> Value:
294+
if not component_tys:
295+
if data:
296+
raise ValueError(f'Zero-sized tuple expected empty data, got: {data!r}')
297+
return AggregateValue(0, [])
298+
299+
raise ValueError('Tuple decoding with components is not implemented yet')
300+
301+
285302
def _decode_enum(
286303
*,
287304
data: bytes,

kmir/src/kmir/kdist/mir-semantics/rt/data.md

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ A variant `#forceSetLocal` is provided for setting the local value without check
172172

173173
```k
174174
syntax KItem ::= #setLocalValue( Place, Evaluation ) [strict(2)]
175-
| #forceSetLocal ( Local , Value )
175+
| #forceSetLocal ( Local , Evaluation ) [strict(2)]
176176
177177
rule <k> #setLocalValue(place(local(I), .ProjectionElems), VAL) => .K ... </k>
178178
<locals>
@@ -203,7 +203,7 @@ A variant `#forceSetLocal` is provided for setting the local value without check
203203
andBool isTypedValue(LOCALS[I])
204204
[preserves-definedness] // valid list indexing and sort checked
205205
206-
rule <k> #forceSetLocal(local(I), MBVAL) => .K ... </k>
206+
rule <k> #forceSetLocal(local(I), MBVAL:Value) => .K ... </k>
207207
<locals> LOCALS => LOCALS[I <- typedValue(MBVAL, tyOfLocal(getLocal(LOCALS, I)), mutabilityOf(getLocal(LOCALS, I)))] </locals>
208208
requires 0 <=Int I andBool I <Int size(LOCALS)
209209
andBool isTypedLocal(LOCALS[I])
@@ -1064,6 +1064,25 @@ This eliminates any `Deref` projections from the place, and also resolves `Index
10641064
// rule #projectionsFor(CtxPointerOffset(OFFSET, ORIGIN_LENGTH) CTXS, PROJS) => #projectionsFor(CTXS, projectionElemSubslice(OFFSET, ORIGIN_LENGTH, false) PROJS)
10651065
rule #projectionsFor(CtxPointerOffset( _, OFFSET, ORIGIN_LENGTH) CTXS, PROJS) => #projectionsFor(CTXS, PointerOffset(OFFSET, ORIGIN_LENGTH) PROJS)
10661066
1067+
// Borrowing a zero-sized local that is still `NewLocal`: initialise it, then reuse the regular rule.
1068+
rule <k> rvalueRef(REGION, KIND, place(local(I), PROJS))
1069+
=> #forceSetLocal(
1070+
local(I),
1071+
#decodeConstant(
1072+
constantKindZeroSized,
1073+
tyOfLocal(getLocal(LOCALS, I)),
1074+
lookupTy(tyOfLocal(getLocal(LOCALS, I)))
1075+
)
1076+
)
1077+
~> rvalueRef(REGION, KIND, place(local(I), PROJS))
1078+
...
1079+
</k>
1080+
<locals> LOCALS </locals>
1081+
requires 0 <=Int I andBool I <Int size(LOCALS)
1082+
andBool isNewLocal(LOCALS[I])
1083+
andBool #zeroSizedType(lookupTy(tyOfLocal(getLocal(LOCALS, I))))
1084+
[preserves-definedness] // valid list indexing checked, zero-sized locals materialise trivially
1085+
10671086
rule <k> rvalueRef(_REGION, KIND, place(local(I), PROJS))
10681087
=> #traverseProjection(toLocal(I), getValue(LOCALS, I), PROJS, .Contexts)
10691088
~> #forRef(#mutabilityOf(KIND), metadata(#metadataSize(tyOfLocal({LOCALS[I]}:>TypedLocal), PROJS), 0, noMetadataSize)) // TODO: Sus on this rule

kmir/src/kmir/kdist/mir-semantics/rt/types.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,21 @@ Slices, `str`s and dynamic types require it, and any `Ty` that `is_sized` does
143143
[preserves-definedness]
144144
```
145145

146+
## Zero-sized types
147+
148+
```k
149+
syntax Bool ::= #zeroSizedType ( TypeInfo ) [function, total]
150+
151+
rule #zeroSizedType(typeInfoTupleType(.Tys)) => true
152+
rule #zeroSizedType(typeInfoStructType(_, _, .Tys, _)) => true
153+
rule #zeroSizedType(typeInfoVoidType) => true
154+
// FIXME: Only unit tuples, empty structs, and void are recognized here; other
155+
// zero-sized types (e.g. single-variant enums, function or closure items,
156+
// newtype wrappers around ZSTs) still fall through because we do not consult
157+
// the layout metadata yet. Update once we rely on machineSize(0).
158+
rule #zeroSizedType(_) => false [owise]
159+
```
160+
146161
```k
147162
endmodule
148163
```

kmir/src/tests/integration/data/exec-smir/call-with-args/closure-call.state

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,15 @@
3232
ListItem ( typedValue ( Integer ( 32 , 32 , false ) , ty ( 25 ) , mutabilityNot ) )
3333
ListItem ( typedValue ( Aggregate ( variantIdx ( 0 ) , ListItem ( Integer ( 32 , 32 , false ) ) ) , ty ( 26 ) , mutabilityNot ) )
3434
ListItem ( typedValue ( Integer ( 32 , 32 , false ) , ty ( 25 ) , mutabilityNot ) )
35-
ListItem ( newLocal ( ty ( 30 ) , mutabilityNot ) )
35+
ListItem ( typedValue ( thunk ( #decodeConstant ( constantKindZeroSized , ty ( 30 ) , typeInfoVoidType ) ) , ty ( 30 ) , mutabilityNot ) )
3636
ListItem ( typedValue ( Integer ( 32 , 32 , false ) , ty ( 25 ) , mutabilityNot ) )
37-
ListItem ( typedValue ( thunk ( rvalueRef ( region (... kind: regionKindReErased ) , borrowKindShared , place (... local: local ( 4 ) , projection: .ProjectionElems ) ) ) , ty ( 31 ) , mutabilityMut ) )
37+
ListItem ( typedValue ( Reference ( 0 , place (... local: local ( 4 ) , projection: .ProjectionElems ) , mutabilityNot , metadata ( noMetadataSize , 0 , noMetadataSize ) ) , ty ( 31 ) , mutabilityMut ) )
3838
ListItem ( typedValue ( Aggregate ( variantIdx ( 0 ) , ListItem ( Integer ( 32 , 32 , false ) ) ) , ty ( 26 ) , mutabilityMut ) )
3939
ListItem ( typedValue ( Aggregate ( variantIdx ( 0 ) , ListItem ( Integer ( 32 , 32 , false ) )
4040
ListItem ( Integer ( 32 , 32 , false ) ) ) , ty ( 32 ) , mutabilityNot ) )
41-
ListItem ( newLocal ( ty ( 33 ) , mutabilityNot ) )
41+
ListItem ( typedValue ( thunk ( #decodeConstant ( constantKindZeroSized , ty ( 33 ) , typeInfoVoidType ) ) , ty ( 33 ) , mutabilityNot ) )
4242
ListItem ( newLocal ( ty ( 1 ) , mutabilityNot ) )
43-
ListItem ( typedValue ( thunk ( rvalueRef ( region (... kind: regionKindReErased ) , borrowKindShared , place (... local: local ( 9 ) , projection: .ProjectionElems ) ) ) , ty ( 34 ) , mutabilityMut ) )
43+
ListItem ( typedValue ( Reference ( 0 , place (... local: local ( 9 ) , projection: .ProjectionElems ) , mutabilityNot , metadata ( noMetadataSize , 0 , noMetadataSize ) ) , ty ( 34 ) , mutabilityMut ) )
4444
ListItem ( typedValue ( Aggregate ( variantIdx ( 0 ) , ListItem ( Integer ( 32 , 32 , false ) )
4545
ListItem ( Integer ( 32 , 32 , false ) ) ) , ty ( 32 ) , mutabilityMut ) )
4646
</locals>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
const EMPTY: () = ();
2+
3+
fn main() {
4+
let e = ();
5+
assert!(e == EMPTY);
6+
}

kmir/src/tests/integration/data/prove-rs/show/closure_access_struct.main.expected

Lines changed: 0 additions & 17 deletions
This file was deleted.

kmir/src/tests/integration/test_integration.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@
5050
'checked_arithmetic-fail',
5151
'offset-u8-fail',
5252
'pointer-cast-length-test-fail',
53-
'closure_access_struct',
5453
'niche-enum',
5554
'assume-cheatcode-conflict-fail',
5655
]

0 commit comments

Comments
 (0)