@@ -331,7 +331,8 @@ These helpers mark down, as we traverse the projection, what `Place` we are curr
331331 syntax ProjectionElem ::= PointerOffset( Int, Int ) // Same as subslice but coming from BinopOffset injected by us
332332
333333 // PointerOffset operates on a canonical range view. Bare values are treated as a
334- // singleton range instead of bouncing between `VAL` and `Range(ListItem(VAL))`.
334+ // singleton range, and later scalar projections transparently descend into the
335+ // head element through CtxRangeHead instead of materializing a fake index-0 step.
335336 syntax Value ::= #rangeView ( Value ) [function, total]
336337 rule #rangeView(Range(ELEMS)) => Range(ELEMS)
337338 rule #rangeView(VAL) => Range(ListItem(VAL)) requires notBool isRange(VAL)
@@ -409,6 +410,14 @@ These helpers mark down, as we traverse the projection, what `Place` we are curr
409410 rule consP(projectionElemToZST, projectionElemFromZST PS:ProjectionElems) => PS [priority(40)]
410411 rule consP(projectionElemFromZST, projectionElemToZST PS:ProjectionElems) => PS [priority(40)]
411412
413+ syntax Bool ::= #projectsHead ( ProjectionElem ) [function, total]
414+ // ---------------------------------------------------------------
415+ rule #projectsHead(projectionElemDeref) => true
416+ rule #projectsHead(projectionElemField(_, _)) => true
417+ rule #projectsHead(projectionElemDowncast(_)) => true
418+ rule #projectsHead(projectionElemWrapStruct) => true
419+ rule #projectsHead(_OTHER) => false [owise]
420+
412421 syntax Value ::= #localFromFrame ( StackFrame, Local, Int ) [function]
413422
414423 rule #localFromFrame(StackFrame(... locals: LOCALS), local(I:Int), OFFSET) => #adjustRef(getValue(LOCALS, I), OFFSET)
@@ -526,49 +535,30 @@ The situation typically arises when the stored value is a pointer (`NonNull`) bu
526535
527536A somewhat dual case to this rule can occur when a pointer into an array of data elements has been offset and is then dereferenced.
528537The dereferenced pointer may either point to a subslice or to a single element (depending on context).
529- Therefore, a field projection may be found which has to be applied to the head element of an array.
530- The following rules resolve this situation by using the head element while
531- retaining an internal ` CtxRangeHead(...) ` context, so writes still rebuild the
532- enclosing range without leaking a synthetic ` ConstantIndex(0) ` into later place
533- or reference reconstruction .
538+ Subsequent scalar projections such as ` Field ` , ` Downcast ` , ` Deref ` , or ` WrapStruct `
539+ should act on that single pointed-at element, but the enclosing range still has to be
540+ available for write-back. Instead of re-encoding every scalar projection against
541+ ` Range(ListItem(...)) ` , we first descend into the head element and remember that
542+ implicit step via ` CtxRangeHead(...) ` , leaving the forward ` PATH ` unchanged .
534543
535544``` k
536545 rule <k> #traverseProjection(
537546 DEST,
538- Range(ListItem(Aggregate(V_IDX, ARGS) ) REST:List),
539- projectionElemField(fieldIdx(I), TY) PROJS,
547+ Range(ListItem(HEAD ) REST:List),
548+ (PROJ:ProjectionElem PROJS) ,
540549 CTXTS,
541550 PATH
542551 )
543552 => #traverseProjection(
544553 DEST,
545- getValue(ARGS, I),
546- PROJS,
547- CtxField(V_IDX, ARGS, I, TY) CtxRangeHead(ListItem(Aggregate(V_IDX, ARGS)) REST) CTXTS,
548- #pushProjection(PATH, projectionElemField(fieldIdx(I), TY))
549- )
550- ...
551- </k>
552- requires 0 <=Int I andBool I <Int size(ARGS)
553- andBool isValue(ARGS[I])
554- [preserves-definedness] // valid list indexing checked
555-
556- rule <k> #traverseProjection(
557- DEST,
558- Range(ListItem(Union(FIELD_IDX, ARG)) REST:List),
559- projectionElemField(FIELD_IDX, TY) PROJS,
560- CTXTS,
554+ HEAD,
555+ PROJ PROJS,
556+ CtxRangeHead(ListItem(HEAD) REST) CTXTS,
561557 PATH
562558 )
563- => #traverseProjection(
564- DEST,
565- ARG,
566- PROJS,
567- CtxFieldUnion(FIELD_IDX, ARG, TY) CtxRangeHead(ListItem(Union(FIELD_IDX, ARG)) REST) CTXTS,
568- #pushProjection(PATH, projectionElemField(FIELD_IDX, TY))
569- )
570559 ...
571560 </k>
561+ requires #projectsHead(PROJ)
572562 [preserves-definedness]
573563```
574564
@@ -657,7 +647,7 @@ In case of a `ConstantIndex`, the index is provided as an immediate value, toget
657647 )
658648 => #traverseProjection(
659649 DEST,
660- getValue(ELEMENTS, OFFSET),
650+ getValue(ELEMENTS, MINLEN -Int OFFSET),
661651 PROJS,
662652 CtxIndex(ELEMENTS, MINLEN -Int OFFSET) CTXTS,
663653 #pushProjection(PATH, projectionElemConstantIndex(MINLEN -Int OFFSET, 0, false))
0 commit comments