@@ -1265,15 +1265,78 @@ the `Value` sort.
12651265Conversion is especially possible for the case of _ Slices_ (of dynamic length) and _ Arrays_ (of static length),
12661266which have the same representation ` Value::Range ` .
12671267
1268+ When the cast crosses transparent wrappers (newtypes that just forward field ` 0 ` e.g. ` struct Wrapper<T>(T) ` ), the pointer's
1269+ ` Place ` must be realigned. ` #alignTransparentPlace ` rewrites the projection list until the source and target
1270+ expose the same inner value:
1271+ - if the source unwraps more than the target, append an explicit ` field(0) ` so the target still sees that field;
1272+ - if the target unwraps more, strip any redundant tail projections with ` #popTransparentTailTo ` , leaving the
1273+ canonical prefix shared by both sides.
1274+
12681275``` k
12691276 rule <k> #cast(PtrLocal(OFFSET, PLACE, MUT, META), castKindPtrToPtr, TY_SOURCE, TY_TARGET)
12701277 =>
1271- PtrLocal(OFFSET, PLACE, MUT, #convertMetadata(META, lookupTy(TY_TARGET)))
1278+ PtrLocal(
1279+ OFFSET,
1280+ #alignTransparentPlace(
1281+ PLACE,
1282+ #lookupMaybeTy(pointeeTy(lookupTy(TY_SOURCE))),
1283+ #lookupMaybeTy(pointeeTy(lookupTy(TY_TARGET)))
1284+ ),
1285+ MUT,
1286+ #convertMetadata(META, lookupTy(TY_TARGET))
1287+ )
12721288 ...
12731289 </k>
12741290 requires #typesCompatible(lookupTy(TY_SOURCE), lookupTy(TY_TARGET))
12751291 [preserves-definedness] // valid map lookups checked
12761292
1293+ syntax Place ::= #alignTransparentPlace ( Place , TypeInfo , TypeInfo ) [function, total]
1294+ syntax ProjectionElems ::= #popTransparentTailTo ( ProjectionElems , TypeInfo ) [function, total]
1295+
1296+ rule #alignTransparentPlace(place(LOCAL, PROJS), typeInfoStructType(_, _, FIELD_TY .Tys, LAYOUT) #as SOURCE, TARGET)
1297+ => #alignTransparentPlace(
1298+ place(
1299+ LOCAL,
1300+ appendP(PROJS, projectionElemField(fieldIdx(0), FIELD_TY) .ProjectionElems)
1301+ ),
1302+ lookupTy(FIELD_TY),
1303+ TARGET
1304+ )
1305+ requires #transparentDepth(SOURCE) >Int #transparentDepth(TARGET)
1306+ andBool #zeroFieldOffset(LAYOUT)
1307+
1308+ rule #alignTransparentPlace(
1309+ place(LOCAL, PROJS),
1310+ SOURCE,
1311+ typeInfoStructType(_, _, FIELD_TY .Tys, LAYOUT) #as TARGET
1312+ )
1313+ => #alignTransparentPlace(
1314+ place(LOCAL, #popTransparentTailTo(PROJS, lookupTy(FIELD_TY))),
1315+ SOURCE,
1316+ lookupTy(FIELD_TY)
1317+ )
1318+ requires #transparentDepth(SOURCE) <Int #transparentDepth(TARGET)
1319+ andBool #zeroFieldOffset(LAYOUT)
1320+ andBool PROJS =/=K #popTransparentTailTo(PROJS, lookupTy(FIELD_TY))
1321+
1322+ rule #alignTransparentPlace(PLACE, _, _) => PLACE [owise]
1323+
1324+ rule #popTransparentTailTo(
1325+ projectionElemField(fieldIdx(0), FIELD_TY) .ProjectionElems,
1326+ TARGET
1327+ )
1328+ => .ProjectionElems
1329+ requires lookupTy(FIELD_TY) ==K TARGET
1330+
1331+ rule #popTransparentTailTo(
1332+ X:ProjectionElem REST:ProjectionElems,
1333+ TARGET
1334+ )
1335+ => X #popTransparentTailTo(REST, TARGET)
1336+ requires REST =/=K .ProjectionElems
1337+
1338+ rule #popTransparentTailTo(PROJS, _) => PROJS [owise]
1339+
12771340 syntax Metadata ::= #convertMetadata ( Metadata , TypeInfo ) [function, total]
12781341 // -------------------------------------------------------------------------------------
12791342```
@@ -1497,23 +1560,58 @@ Casting an integer to a `[u8; N]` array materialises its little-endian bytes.
14971560 rule #staticArrayLenBits(_OTHER) => 0 [owise]
14981561```
14991562
1500- Another specialisation is getting the discriminant of ` enum ` s without fields after converting some integer data to it
1501- (see ` #discriminant ` and ` rvalueDiscriminant ` ).
1502- If none of the ` enum ` variants has any fields, the ` Transmute ` of a number to the ` enum ` data is necessarily just the discriminant itself., and can be returned as the integer value afgter adjusting to the byte length of the discriminant:
1563+ A transmutation from an integer to an enum is wellformed if:
1564+ - The bit width of the incoming integer is the same as the discriminant type of the enum
1565+ (e.g. ` u8 -> i8 ` fine, ` u8 -> u16 ` not fine) - this is guaranteed by the compiler;
1566+ - The incoming integer has a bit pattern that matches a discriminant of the enum
1567+ (e.g. ` 255_u8 ` and ` -1_i8 ` fine iff ` 0b1111_1111 ` is a discriminant of the enum);
15031568
1504- ``` k
1505- rule <k> #discriminant(
1506- thunk(#cast (Integer(DATA, _, false), castKindTransmute, _, TY)),
1507- TY
1508- ) => Integer(DATA, 0, false) // HACK: bit width 0 means "flexible"
1509- ...
1510- </k>
1511- requires #isEnumWithoutFields(lookupTy(TY))
1569+ Note that discriminants are stored as ` u128 ` in the type data even if they are signed
1570+ or unsigned at the source level. This means that our approach to soundly transmute an
1571+ integer into a enum is to treat the incoming integer as unsigned (converting if signed),
1572+ and check if the value is in the discriminants. If yes, find the corresponding variant
1573+ index; if not, return ` #UBErrorInvalidDiscriminantsInEnumCast ` .
15121574
1575+ ``` k
15131576 syntax Bool ::= #isEnumWithoutFields ( TypeInfo ) [function, total]
15141577 // ----------------------------------------------------------------
15151578 rule #isEnumWithoutFields(typeInfoEnumType(_, _, _, FIELDSS, _)) => #noFields(FIELDSS)
15161579 rule #isEnumWithoutFields(_OTHER) => false [owise]
1580+
1581+ // TODO: Connect this with MirError
1582+ syntax Evaulation ::= "#UBErrorInvalidDiscriminantsInEnumCast"
1583+ rule <k>
1584+ #cast( Integer ( VAL , WIDTH , _SIGNED ) , castKindTransmute , _TY_FROM , TY_TO ) ~> _REST
1585+ =>
1586+ #UBErrorInvalidDiscriminantsInEnumCast
1587+ </k>
1588+ requires #isEnumWithoutFields(lookupTy(TY_TO))
1589+ andBool notBool #validDiscriminant( truncate(VAL, WIDTH, Unsigned) , lookupTy(TY_TO) )
1590+
1591+ rule <k>
1592+ #cast( Integer ( VAL , WIDTH , _SIGNED ) , castKindTransmute , _TY_FROM , TY_TO )
1593+ =>
1594+ Aggregate( #findVariantIdxFromTy( truncate(VAL, WIDTH, Unsigned), lookupTy(TY_TO) ) , .List )
1595+ ...
1596+ </k>
1597+ requires #isEnumWithoutFields(lookupTy(TY_TO))
1598+ andBool #validDiscriminant( truncate(VAL, WIDTH, Unsigned) , lookupTy(TY_TO))
1599+
1600+ syntax VariantIdx ::= #findVariantIdxFromTy ( Int , TypeInfo ) [function, total]
1601+ //------------------------------------------------------------------------------
1602+ rule #findVariantIdxFromTy( VAL , typeInfoEnumType(_, _, DISCRIMINANTS, _, _) ) => #findVariantIdx( VAL, DISCRIMINANTS)
1603+ rule #findVariantIdxFromTy( _ , _ ) => err("NotAnEnum") [owise]
1604+
1605+ syntax Bool ::= #validDiscriminant ( Int , TypeInfo ) [function, total]
1606+ // ----------------------------------------------------------------------------
1607+ rule #validDiscriminant( VAL , typeInfoEnumType(_, _, DISCRIMINANTS, _, _) ) => #validDiscriminantAux( VAL , DISCRIMINANTS )
1608+ rule #validDiscriminant( _ , _ ) => false [owise]
1609+
1610+ syntax Bool ::= #validDiscriminantAux ( Int , Discriminants ) [function, total]
1611+ // ----------------------------------------------------------------------------
1612+ rule #validDiscriminantAux( VAL, discriminant(mirInt(DISCRIMINANT)) REST ) => VAL ==Int DISCRIMINANT orBool #validDiscriminantAux( VAL, REST )
1613+ rule #validDiscriminantAux( VAL, discriminant( DISCRIMINANT ) REST ) => VAL ==Int DISCRIMINANT orBool #validDiscriminantAux( VAL, REST )
1614+ rule #validDiscriminantAux( _VAL, .Discriminants ) => false
15171615```
15181616
15191617
0 commit comments