@@ -384,6 +384,9 @@ These helpers mark down, as we traverse the projection, what `Place` we are curr
384384 rule consP(projectionElemWrapStruct, projectionElemField(fieldIdx(0), _) PS:ProjectionElems) => PS [priority(40)]
385385 // this rule is not valid if the original pointee has more than one field
386386 // rule consP(projectionElemField(fieldIdx(0), _), projectionElemWrapStruct PS:ProjectionElems) => PS [priority(40)]
387+ // HACK: special rule which munges together constant-indexing and offset projections
388+ rule consP( projectionElemConstantIndex(I, 0, false), PointerOffset(OFF, _SIZE) PS) => projectionElemConstantIndex(I +Int OFF, 0, false) PS [priority(40)]
389+ // requires I +Int OFF < _SIZE // _SIZE is metadataSize, needs a < operation for this to work
387390 rule consP(projectionElemToZST, projectionElemFromZST PS:ProjectionElems) => PS [priority(40)]
388391 rule consP(projectionElemFromZST, projectionElemToZST PS:ProjectionElems) => PS [priority(40)]
389392
@@ -506,6 +509,16 @@ The following rule resolves this situation by using the head element.
506509 => #traverseProjection(DEST, VALUE, projectionElemField(IDX, TY) PROJS, CTXTS) ... </k> // TODO mark context?
507510 [preserves-definedness, priority(100)]
508511
512+ // Temporary bridge rule: after PointerOffset lifts a single value to Range(ListItem(...)),
513+ // unwrap a Union head element so the existing Union + Field rules below can keep running.
514+ rule <k> #traverseProjection(
515+ DEST,
516+ Range(ListItem(Union(_, _) #as VALUE) _REST:List),
517+ projectionElemField(IDX, TY) PROJS,
518+ CTXTS
519+ )
520+ => #traverseProjection(DEST, VALUE, projectionElemField(IDX, TY) PROJS, CTXTS) ... </k> // TODO mark context?
521+ [preserves-definedness, priority(100)]
509522```
510523
511524#### Unions
@@ -647,6 +660,24 @@ Similar to `ConstantIndex`, the slice _end_ index may count from the _end_ or t
647660 andBool START <=Int size(ELEMENTS) -Int END
648661 [preserves-definedness] // Indexes checked to be in range for ELEMENTS
649662
663+ // Temporary bridge rule: PointerOffset is implemented below in terms of Range slicing, so
664+ // lift a single non-Range value to Range(ListItem(...)) to reuse that shared path.
665+ rule <k> #traverseProjection(
666+ DEST,
667+ VAL,
668+ PointerOffset(OFFSET, ORIGIN_LENGTH) PROJS,
669+ CTXTS
670+ )
671+ => #traverseProjection(
672+ DEST,
673+ Range(ListItem(VAL)),
674+ PointerOffset(OFFSET, ORIGIN_LENGTH) PROJS,
675+ CTXTS
676+ )
677+ ...
678+ </k>
679+ requires notBool isRange(VAL)
680+ [preserves-definedness, priority(100)]
650681
651682 rule <k> #traverseProjection(
652683 DEST,
@@ -1110,7 +1141,7 @@ and an array of the indeicated size gets reconstructed if the provided metadata
11101141 rule <k> ListItem(PtrLocal(OFFSET, place(LOCAL, PROJS), _, metadata(_SIZE, PTR_OFFSET, ORIGIN_SIZE)))
11111142 ListItem(Integer(LENGTH, 64, false))
11121143 ~> #mkAggregate(aggregateKindRawPtr(_TY, MUT))
1113- => PtrLocal(OFFSET, place(LOCAL, PROJS), MUT, metadata(dynamicSize(LENGTH), PTR_OFFSET, ORIGIN_SIZE))
1144+ => PtrLocal(OFFSET, place(LOCAL, removeIndexTail( PROJS) ), MUT, metadata(dynamicSize(LENGTH), PTR_OFFSET, ORIGIN_SIZE))
11141145 ...
11151146 </k>
11161147 // requires LENGTH +Int PTR_OFFSET <=Int ORIGIN_SIZE // refuse to create an invalid fat pointer
0 commit comments