diff --git a/kmir/src/kmir/kdist/mir-semantics/kmir.md b/kmir/src/kmir/kdist/mir-semantics/kmir.md index 305bf7718..c80f91a76 100644 --- a/kmir/src/kmir/kdist/mir-semantics/kmir.md +++ b/kmir/src/kmir/kdist/mir-semantics/kmir.md @@ -565,7 +565,8 @@ Therefore a heuristics is used here: _SPAN ) => - #setTupleArgs(2, getValue(LOCALS, TUPLE)) ~> #execBlock(FIRST) + #setLocalValue(place(local(1), .ProjectionElems), #incrementRef(getValue(LOCALS, CLOSURE))) + ~> #setTupleArgs(2, getValue(LOCALS, TUPLE)) ~> #execBlock(FIRST) // arguments are tuple components, stored as _2 .. _n ... @@ -609,6 +610,11 @@ Therefore a heuristics is used here: // unpack tuple and set arguments individually rule #setTupleArgs(IDX, Aggregate(variantIdx(0), ARGS)) => #setTupleArgs(IDX, ARGS) ... + rule #setTupleArgs(IDX, VAL:Value) + => #setTupleArgs(IDX, ListItem(VAL)) + ... + [owise] + rule #setTupleArgs(_, .List ) => .K ... rule #setTupleArgs(IDX, ListItem(VAL) REST:List) diff --git a/kmir/src/kmir/kdist/mir-semantics/rt/data.md b/kmir/src/kmir/kdist/mir-semantics/rt/data.md index 840ae6095..f76620160 100644 --- a/kmir/src/kmir/kdist/mir-semantics/rt/data.md +++ b/kmir/src/kmir/kdist/mir-semantics/rt/data.md @@ -1051,6 +1051,12 @@ Literal arrays are also built using this RValue. ... + rule ARGS:List ~> #mkAggregate(aggregateKindClosure(_DEF, _TY_ARGS)) + => + Aggregate(variantIdx(0), ARGS) + ... + + // #readOperands accumulates a list of `TypedLocal` values from operands syntax KItem ::= #readOperands ( Operands ) @@ -1434,6 +1440,20 @@ which have the same representation `Value::Range`. Also, casts to and from _transparent wrappers_ (newtypes that just forward field `0`, i.e. `struct Wrapper(T)`) are allowed, and supported by a special projection `WrapStruct`. +When the source and target types are pointer types with the same pointee type (i.e., differing only in mutability), +the cast preserves the source pointer and its metadata unchanged. + +```k + rule #cast(PtrLocal(OFFSET, PLACE, MUT, META), castKindPtrToPtr, TY_SOURCE, TY_TARGET) + => PtrLocal(OFFSET, PLACE, MUT, META) + ... + + requires pointeeTy(lookupTy(TY_SOURCE)) ==K pointeeTy(lookupTy(TY_TARGET)) + [priority(45), preserves-definedness] // valid map lookups checked +``` + +Otherwise, compute the type projection and convert metadata accordingly. + ```k rule #cast(PtrLocal(OFFSET, place(LOCAL, PROJS), MUT, META), castKindPtrToPtr, TY_SOURCE, TY_TARGET) => diff --git a/kmir/src/kmir/kdist/mir-semantics/rt/decoding.md b/kmir/src/kmir/kdist/mir-semantics/rt/decoding.md index 0ac8cff08..98b522012 100644 --- a/kmir/src/kmir/kdist/mir-semantics/rt/decoding.md +++ b/kmir/src/kmir/kdist/mir-semantics/rt/decoding.md @@ -297,27 +297,26 @@ If there are no fields, the enum can be decoded by using their data as the discr requires TAG =/=Int DISCRIMINANT ``` -#### Enums with two variants +#### Enums with direct tag encoding and fields -Having two variants with possibly zero or one field each is a very common case, -it includes a number of standard library types such as `Option` and `Result`. - -The following rules are specialised to the case of encoding an `Option`. -An important distinction here is whether or not the tag is niche-encoded. -If the option holds data that has all-zero as a possible value, a separate tag is used, usually as the first field. -In both cases we expect the tag to be in the single shared field, and the discriminant to be just 0 and 1. +Decodes any enum with `tagEncodingDirect` and a `primitiveInt` tag, +with arbitrary variant counts, discriminant values, and field counts per variant. +The tag is read as an unsigned little-endian integer, matched against the discriminant +list to find the variant index, and then the variant's fields are decoded using the +per-variant layout offsets. ```k + // General entry rule: direct-tag enum with at least one field somewhere. rule #decodeValue( BYTES , typeInfoEnumType(... name: _ , adtDef: _ - , discriminants: discriminant(0) discriminant(1) .Discriminants - , fields: (.Tys : (FIELD_TYPE .Tys) : .Tyss) + , discriminants: DISCRIMINANTS + , fields: FIELD_TYPESS , layout: someLayoutShape(layoutShape(... - fields: fieldsShapeArbitrary(mk(... offsets: machineSize(0) .MachineSizes)) + fields: _FIELDS , variants: variantsShapeMultiple( mk(... @@ -329,7 +328,7 @@ In both cases we expect the tag to be in the single shared field, and the discri ) , tagEncoding: tagEncodingDirect , tagField: 0 - , variants: _VARIANTS + , variants: VARIANT_LAYOUTS ) ) , abi: _ABI @@ -338,22 +337,59 @@ In both cases we expect the tag to be in the single shared field, and the discri )) ) #as ENUM_TYPE ) - => #decodeOptionTag01(BYTES, TAG_WIDTH, FIELD_TYPE, ENUM_TYPE) - - syntax Evaluation ::= #decodeOptionTag01 ( Bytes , IntegerLength , Ty , TypeInfo ) [function, total] - // -------------------------------------------------------------------------------------- - rule #decodeOptionTag01(BYTES, _LEN, _TY, _ENUM_TYPE) - => Aggregate(variantIdx(0), .List) - requires 0 ==Int BYTES[0] // expect only 0 or 1 as tags, so higher bytes do not matter - [preserves-definedness] - rule #decodeOptionTag01(BYTES, LEN, TY, _ENUM_TYPE) - => Aggregate(variantIdx(1), ListItem(#decodeValue(substrBytes(BYTES, #byteLength(LEN), lengthBytes(BYTES)), lookupTy(TY)))) - requires 1 ==Int BYTES[0] // expect only 0 or 1 as tags, so higher bytes do not matter + => #decodeEnumDirectFields( + BYTES, + #findVariantIdx(#decodeEnumDirectTag(BYTES, TAG_WIDTH), DISCRIMINANTS), + FIELD_TYPESS, + VARIANT_LAYOUTS, + ENUM_TYPE + ) + requires notBool #noFields(FIELD_TYPESS) + + // --------------------------------------------------------------------------- + // #decodeEnumDirectFields: given the variant index, decode its fields + // --------------------------------------------------------------------------- + syntax Evaluation ::= #decodeEnumDirectFields ( Bytes , VariantIdx , Tyss , LayoutShapes , TypeInfo ) [function, total] + // -------------------------------------------------------------------------------------------------------------------------- + rule #decodeEnumDirectFields(BYTES, variantIdx(IDX), FIELD_TYPESS, VARIANT_LAYOUTS, _ENUM_TYPE) + => Aggregate( + variantIdx(IDX), + #decodeFieldsWithOffsets(BYTES, #nthTys(FIELD_TYPESS, IDX), #nthVariantOffsets(VARIANT_LAYOUTS, IDX)) + ) + requires 0 <=Int IDX [preserves-definedness] - rule #decodeOptionTag01(BYTES, _LEN, _TY, ENUM_TYPE) + + // Error cases: variant not found or other failure + rule #decodeEnumDirectFields(BYTES, _, _FIELD_TYPESS, _VARIANT_LAYOUTS, ENUM_TYPE) => UnableToDecode(BYTES, ENUM_TYPE) [owise] + // --------------------------------------------------------------------------- + // #decodeEnumDirectTag: read the tag bytes as an unsigned little-endian int + // --------------------------------------------------------------------------- + syntax Int ::= #decodeEnumDirectTag ( Bytes , IntegerLength ) [function, total] + rule #decodeEnumDirectTag(BYTES, TAG_WIDTH) + => Bytes2Int(substrBytes(BYTES, 0, #byteLength(TAG_WIDTH)), LE, Unsigned) + requires lengthBytes(BYTES) >=Int #byteLength(TAG_WIDTH) + [preserves-definedness] + rule #decodeEnumDirectTag(_, _) => -1 [owise] + + // --------------------------------------------------------------------------- + // List-indexing helpers + // --------------------------------------------------------------------------- + + // Index into a Tyss (list of per-variant field type lists) + syntax Tys ::= #nthTys ( Tyss , Int ) [function, total] + rule #nthTys(TYS : _REST, 0) => TYS + rule #nthTys(_TYS : REST, N) => #nthTys(REST, N -Int 1) requires N >Int 0 + rule #nthTys(_, _) => .Tys [owise] + + // Index into variant layouts and extract field offsets in one step (total) + syntax MachineSizes ::= #nthVariantOffsets ( LayoutShapes , Int ) [function, total] + rule #nthVariantOffsets(layoutShape(fieldsShapeArbitrary(mk(OFFSETS)), _, _, _, _) _REST, 0) => OFFSETS + rule #nthVariantOffsets(_L REST, N) => #nthVariantOffsets(REST, N -Int 1) requires N >Int 0 + rule #nthVariantOffsets(_, _) => .MachineSizes [owise] + syntax Int ::= #byteLength ( IntegerLength ) [function, total] // ----------------------------------------------------------- rule #byteLength(integerLengthI8 ) => 1 diff --git a/kmir/src/kmir/kompile.py b/kmir/src/kmir/kompile.py index 67878e05e..c48fef906 100644 --- a/kmir/src/kmir/kompile.py +++ b/kmir/src/kmir/kompile.py @@ -521,13 +521,25 @@ def _functions(kmir: KMIR, smir_info: SMIRInfo) -> dict[int, KInner]: for ty in smir_info.function_symbols_reverse[item_name]: functions[ty] = parsed_item_kinner.args[1] - # Add intrinsic functions + # Add intrinsic functions and linked normal symbols that have no local body in `items`. + # Normal symbols must still map to `monoItemFn(..., noBody)` instead of falling back to UNKNOWN FUNCTION. for ty, sym in smir_info.function_symbols.items(): - if 'IntrinsicSym' in sym and ty not in functions: + if ty in functions: + continue + if 'IntrinsicSym' in sym: functions[ty] = KApply( 'IntrinsicFunction', [KApply('symbol(_)_LIB_Symbol_String', [stringToken(sym['IntrinsicSym'])])], ) + elif isinstance(sym.get('NormalSym'), str): + functions[ty] = KApply( + 'MonoItemKind::MonoItemFn', + ( + KApply('symbol(_)_LIB_Symbol_String', (stringToken(sym['NormalSym']),)), + KApply('defId(_)_BODY_DefId_Int', (intToken(ty),)), + KApply('noBody_BODY_MaybeBody', ()), + ), + ) return functions diff --git a/kmir/src/kmir/testing/fixtures.py b/kmir/src/kmir/testing/fixtures.py index 4ade1e06d..d42bf606d 100644 --- a/kmir/src/kmir/testing/fixtures.py +++ b/kmir/src/kmir/testing/fixtures.py @@ -1,5 +1,7 @@ from __future__ import annotations +import re +import sys from difflib import unified_diff from typing import TYPE_CHECKING @@ -13,24 +15,36 @@ from pytest import FixtureRequest, Parser -import sys - def pytest_configure(config) -> None: sys.setrecursionlimit(1000000) +def _normalize_symbol_hashes(text: str) -> str: + """Normalize rustc symbol hash suffixes that drift across builds/environments.""" + # Normalize mangled symbol hashes, including generic names with `$` and `.`. + # Keep trailing `E` when present; truncated variants may omit it. + text = re.sub(r'(_ZN[0-9A-Za-z_$.]+17h)[0-9a-fA-F]+E', r'\1E', text) + text = re.sub(r'(_ZN[0-9A-Za-z_$.]+17h)[0-9a-fA-F]+', r'\1', text) + # Normalize demangled hash suffixes (`...::h`). + text = re.sub(r'(::h)[0-9a-fA-F]{8,}', r'\1', text) + return text + + def assert_or_update_show_output( actual_text: str, expected_file: Path, *, update: bool, path_replacements: dict[str, str] | None = None ) -> None: if path_replacements: for old, new in path_replacements.items(): actual_text = actual_text.replace(old, new) + # Normalize rustc symbol hash suffixes that can drift across builds/environments. + actual_text = _normalize_symbol_hashes(actual_text) if update: expected_file.write_text(actual_text) else: assert expected_file.is_file() expected_text = expected_file.read_text() + expected_text = _normalize_symbol_hashes(expected_text) if actual_text != expected_text: diff = '\n'.join( unified_diff( diff --git a/kmir/src/kmir/utils.py b/kmir/src/kmir/utils.py index 935d37656..8feb00ca5 100644 --- a/kmir/src/kmir/utils.py +++ b/kmir/src/kmir/utils.py @@ -288,8 +288,8 @@ def _extract_alloc_id(operands: KInner) -> int | None: return None -def _annotate_unknown_function(k_cell: KInner, smir_info: SMIRInfo) -> list[str]: - """If the k cell is `#setUpCalleeData` for `** UNKNOWN FUNCTION **`, return annotation lines with decoded info.""" +def _annotate_nobody_function(k_cell: KInner, smir_info: SMIRInfo) -> list[str]: + """If the k cell is `#setUpCalleeData` for a `noBody` callee, return annotation lines with decoded info.""" from .alloc import Allocation, AllocId, AllocInfo, Memory from .linker import _demangle @@ -307,16 +307,14 @@ def _annotate_unknown_function(k_cell: KInner, smir_info: SMIRInfo) -> list[str] KApply( label=KLabel(name='MonoItemKind::MonoItemFn'), args=[ - KApply(args=[KToken(token=symbol_name)]), + KApply(args=[KToken()]), KApply(label=KLabel(name='defId(_)_BODY_DefId_Int'), args=[KToken(token=def_id_str)]), _, ], ), operands, KApply(label=KLabel(name='span'), args=[KToken(token=span_str)]), - ] if ( - symbol_name == '\"** UNKNOWN FUNCTION **\"' - ): + ]: def_id = int(def_id_str) span = int(span_str) case _: @@ -379,7 +377,7 @@ def render_leaf_k_cells(proof: APRProof, cterm_show: CTermShow, smir_info: SMIRI lines.extend(f' {k_line}' for k_line in k_lines) if smir_info is not None and k_cell is not None: - annotations = _annotate_unknown_function(k_cell, smir_info) + annotations = _annotate_nobody_function(k_cell, smir_info) lines.extend(annotations) if idx != len(leaves) - 1: diff --git a/kmir/src/tests/integration/data/crate-tests/single-lib/small_test_lib::testing::test_add_in_range.expected b/kmir/src/tests/integration/data/crate-tests/single-lib/small_test_lib::testing::test_add_in_range.expected index 36e7fa6a7..3cb67eec2 100644 --- a/kmir/src/tests/integration/data/crate-tests/single-lib/small_test_lib::testing::test_add_in_range.expected +++ b/kmir/src/tests/integration/data/crate-tests/single-lib/small_test_lib::testing::test_add_in_range.expected @@ -16,7 +16,7 @@ ┃ │ ┃ │ (6 steps) ┃ └─ 6 (stuck, leaf) -┃ #setUpCalleeData ( monoItemFn ( ... name: symbol ( "** UNKNOWN FUNCTION **" ) , +┃ #setUpCalleeData ( monoItemFn ( ... name: symbol ( "_ZN3std7process4exit17h ┃ ┗━━┓ subst: .Subst ┃ constraint: diff --git a/kmir/src/tests/integration/data/exec-smir/intrinsic/blackbox_function_symbols.expected.json b/kmir/src/tests/integration/data/exec-smir/intrinsic/blackbox_function_symbols.expected.json index 88db28bbd..3058a6679 100644 --- a/kmir/src/tests/integration/data/exec-smir/intrinsic/blackbox_function_symbols.expected.json +++ b/kmir/src/tests/integration/data/exec-smir/intrinsic/blackbox_function_symbols.expected.json @@ -1,69 +1,69 @@ { "-6": { - "NormalSym": "_ZN4core3ptr85drop_in_place$LT$std..rt..lang_start$LT$$LP$$RP$$GT$..$u7b$$u7b$closure$u7d$$u7d$$GT$17hb524060ed0e83bbbE" + "NormalSym": "_ZN4core3ptr85drop_in_place$LT$std..rt..lang_start$LT$$LP$$RP$$GT$..$u7b$$u7b$closure$u7d$$u7d$$GT$17hE" }, "-5": { - "NormalSym": "_ZN4core3ptr28drop_in_place$LT$$RF$u32$GT$17hb92e31f0aaa3d322E" + "NormalSym": "_ZN4core3ptr28drop_in_place$LT$$RF$u32$GT$17hE" }, "-4": { - "NormalSym": "_ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17h526a5c5d4d9d3202E" + "NormalSym": "_ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17hE" }, "-3": { - "NormalSym": "_ZN42_$LT$$RF$T$u20$as$u20$core..fmt..Debug$GT$3fmt17h3a8781eea2f9ddb7E" + "NormalSym": "_ZN42_$LT$$RF$T$u20$as$u20$core..fmt..Debug$GT$3fmt17hE" }, "-2": { - "NormalSym": "_ZN3std2rt10lang_start17h17250425291430deE" + "NormalSym": "_ZN3std2rt10lang_start17hE" }, "-1": { - "NormalSym": "_ZN8blackbox4main17h56268fefa1135d9eE" + "NormalSym": "_ZN8blackbox4main17hE" }, "0": { - "NormalSym": "_ZN3std2rt19lang_start_internal17h018b8394ba015d86E" + "NormalSym": "_ZN3std2rt19lang_start_internal17hE" }, "13": { - "NormalSym": "_ZN3std3sys9backtrace28__rust_begin_short_backtrace17h3ac302c9481e885fE" + "NormalSym": "_ZN3std3sys9backtrace28__rust_begin_short_backtrace17hE" }, "14": { - "NormalSym": "_ZN54_$LT$$LP$$RP$$u20$as$u20$std..process..Termination$GT$6report17h8eaae5c69aab66e9E" + "NormalSym": "_ZN54_$LT$$LP$$RP$$u20$as$u20$std..process..Termination$GT$6report17hE" }, "19": { - "NormalSym": "_ZN4core3ops8function6FnOnce9call_once17haae505bd39892fd2E" + "NormalSym": "_ZN4core3ops8function6FnOnce9call_once17hE" }, "20": { "IntrinsicSym": "black_box" }, "21": { - "NormalSym": "_ZN4core3fmt3num50_$LT$impl$u20$core..fmt..Debug$u20$for$u20$u32$GT$3fmt17h99c61f0bde9a2afdE" + "NormalSym": "_ZN4core3fmt3num50_$LT$impl$u20$core..fmt..Debug$u20$for$u20$u32$GT$3fmt17hE" }, "27": { - "NormalSym": "_ZN4core3fmt3num53_$LT$impl$u20$core..fmt..LowerHex$u20$for$u20$u32$GT$3fmt17hb987357f13dc6cc8E" + "NormalSym": "_ZN4core3fmt3num53_$LT$impl$u20$core..fmt..LowerHex$u20$for$u20$u32$GT$3fmt17hE" }, "28": { - "NormalSym": "_ZN4core3fmt3num53_$LT$impl$u20$core..fmt..UpperHex$u20$for$u20$u32$GT$3fmt17h7baa47f3e5cbe44cE" + "NormalSym": "_ZN4core3fmt3num53_$LT$impl$u20$core..fmt..UpperHex$u20$for$u20$u32$GT$3fmt17hE" }, "29": { - "NormalSym": "_ZN4core3fmt3num3imp52_$LT$impl$u20$core..fmt..Display$u20$for$u20$u32$GT$3fmt17hec74c53b91325b16E" + "NormalSym": "_ZN4core3fmt3num3imp52_$LT$impl$u20$core..fmt..Display$u20$for$u20$u32$GT$3fmt17hE" }, "30": { - "NormalSym": "_ZN4core3ops8function6FnOnce9call_once17h2d8e0aae13049ae8E" + "NormalSym": "_ZN4core3ops8function6FnOnce9call_once17hE" }, "32": { - "NormalSym": "_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h5c121846c1652782E" + "NormalSym": "_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17hE" }, "35": { "IntrinsicSym": "black_box" }, "36": { - "NormalSym": "_ZN4core9panicking19assert_failed_inner17h1d286061ca0adfe7E" + "NormalSym": "_ZN4core9panicking19assert_failed_inner17hE" }, "43": { - "NormalSym": "_ZN8blackbox7add_one17h19d5f3b41fdf13daE" + "NormalSym": "_ZN8blackbox7add_one17hE" }, "44": { - "NormalSym": "_ZN4core4hint9black_box17h0bfc654765aa2ddfE" + "NormalSym": "_ZN4core4hint9black_box17hE" }, "45": { - "NormalSym": "_ZN4core9panicking13assert_failed17h9acd0d94a91ca0eaE" + "NormalSym": "_ZN4core9panicking13assert_failed17hE" }, "48": { "NoOpSym": "" diff --git a/kmir/src/tests/integration/data/exec-smir/intrinsic/blackbox_function_symbols_reverse.expected.json b/kmir/src/tests/integration/data/exec-smir/intrinsic/blackbox_function_symbols_reverse.expected.json index 4fcfd0647..05755f54f 100644 --- a/kmir/src/tests/integration/data/exec-smir/intrinsic/blackbox_function_symbols_reverse.expected.json +++ b/kmir/src/tests/integration/data/exec-smir/intrinsic/blackbox_function_symbols_reverse.expected.json @@ -1,62 +1,62 @@ { - "_ZN3std2rt10lang_start17h17250425291430deE": [ + "_ZN3std2rt10lang_start17hE": [ -2 ], - "_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h5c121846c1652782E": [ + "_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17hE": [ 32 ], - "_ZN3std2rt19lang_start_internal17h018b8394ba015d86E": [ + "_ZN3std2rt19lang_start_internal17hE": [ 0 ], - "_ZN3std3sys9backtrace28__rust_begin_short_backtrace17h3ac302c9481e885fE": [ + "_ZN3std3sys9backtrace28__rust_begin_short_backtrace17hE": [ 13 ], - "_ZN42_$LT$$RF$T$u20$as$u20$core..fmt..Debug$GT$3fmt17h3a8781eea2f9ddb7E": [ + "_ZN42_$LT$$RF$T$u20$as$u20$core..fmt..Debug$GT$3fmt17hE": [ -3 ], - "_ZN4core3fmt3num3imp52_$LT$impl$u20$core..fmt..Display$u20$for$u20$u32$GT$3fmt17hec74c53b91325b16E": [ + "_ZN4core3fmt3num3imp52_$LT$impl$u20$core..fmt..Display$u20$for$u20$u32$GT$3fmt17hE": [ 29 ], - "_ZN4core3fmt3num50_$LT$impl$u20$core..fmt..Debug$u20$for$u20$u32$GT$3fmt17h99c61f0bde9a2afdE": [ + "_ZN4core3fmt3num50_$LT$impl$u20$core..fmt..Debug$u20$for$u20$u32$GT$3fmt17hE": [ 21 ], - "_ZN4core3fmt3num53_$LT$impl$u20$core..fmt..LowerHex$u20$for$u20$u32$GT$3fmt17hb987357f13dc6cc8E": [ + "_ZN4core3fmt3num53_$LT$impl$u20$core..fmt..LowerHex$u20$for$u20$u32$GT$3fmt17hE": [ 27 ], - "_ZN4core3fmt3num53_$LT$impl$u20$core..fmt..UpperHex$u20$for$u20$u32$GT$3fmt17h7baa47f3e5cbe44cE": [ + "_ZN4core3fmt3num53_$LT$impl$u20$core..fmt..UpperHex$u20$for$u20$u32$GT$3fmt17hE": [ 28 ], - "_ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17h526a5c5d4d9d3202E": [ + "_ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17hE": [ -4 ], - "_ZN4core3ops8function6FnOnce9call_once17h2d8e0aae13049ae8E": [ + "_ZN4core3ops8function6FnOnce9call_once17hE": [ 30 ], - "_ZN4core3ops8function6FnOnce9call_once17haae505bd39892fd2E": [ + "_ZN4core3ops8function6FnOnce9call_once17hE": [ 19 ], - "_ZN4core3ptr28drop_in_place$LT$$RF$u32$GT$17hb92e31f0aaa3d322E": [ + "_ZN4core3ptr28drop_in_place$LT$$RF$u32$GT$17hE": [ -5 ], - "_ZN4core3ptr85drop_in_place$LT$std..rt..lang_start$LT$$LP$$RP$$GT$..$u7b$$u7b$closure$u7d$$u7d$$GT$17hb524060ed0e83bbbE": [ + "_ZN4core3ptr85drop_in_place$LT$std..rt..lang_start$LT$$LP$$RP$$GT$..$u7b$$u7b$closure$u7d$$u7d$$GT$17hE": [ -6 ], - "_ZN4core4hint9black_box17h0bfc654765aa2ddfE": [ + "_ZN4core4hint9black_box17hE": [ 44 ], - "_ZN4core9panicking13assert_failed17h9acd0d94a91ca0eaE": [ + "_ZN4core9panicking13assert_failed17hE": [ 45 ], - "_ZN4core9panicking19assert_failed_inner17h1d286061ca0adfe7E": [ + "_ZN4core9panicking19assert_failed_inner17hE": [ 36 ], - "_ZN54_$LT$$LP$$RP$$u20$as$u20$std..process..Termination$GT$6report17h8eaae5c69aab66e9E": [ + "_ZN54_$LT$$LP$$RP$$u20$as$u20$std..process..Termination$GT$6report17hE": [ 14 ], - "_ZN8blackbox4main17h56268fefa1135d9eE": [ + "_ZN8blackbox4main17hE": [ -1 ], - "_ZN8blackbox7add_one17h19d5f3b41fdf13daE": [ + "_ZN8blackbox7add_one17hE": [ 43 ], "black_box": [ diff --git a/kmir/src/tests/integration/data/exec-smir/intrinsic/blackbox_functions.expected.json b/kmir/src/tests/integration/data/exec-smir/intrinsic/blackbox_functions.expected.json index 8c767e34e..029619a88 100644 --- a/kmir/src/tests/integration/data/exec-smir/intrinsic/blackbox_functions.expected.json +++ b/kmir/src/tests/integration/data/exec-smir/intrinsic/blackbox_functions.expected.json @@ -13569,6 +13569,69 @@ "node": "KApply", "variable": false }, + "0": { + "args": [ + { + "args": [ + { + "node": "KToken", + "sort": { + "name": "String", + "node": "KSort" + }, + "token": "\"_ZN3std2rt19lang_start_internal17hE\"" + } + ], + "arity": 1, + "label": { + "name": "symbol(_)_LIB_Symbol_String", + "node": "KLabel", + "params": [] + }, + "node": "KApply", + "variable": false + }, + { + "args": [ + { + "node": "KToken", + "sort": { + "name": "Int", + "node": "KSort" + }, + "token": "0" + } + ], + "arity": 1, + "label": { + "name": "defId(_)_BODY_DefId_Int", + "node": "KLabel", + "params": [] + }, + "node": "KApply", + "variable": false + }, + { + "args": [], + "arity": 0, + "label": { + "name": "noBody_BODY_MaybeBody", + "node": "KLabel", + "params": [] + }, + "node": "KApply", + "variable": false + } + ], + "arity": 3, + "label": { + "name": "MonoItemKind::MonoItemFn", + "node": "KLabel", + "params": [] + }, + "node": "KApply", + "variable": false + }, "13": { "args": [ { @@ -22521,6 +22584,195 @@ "node": "KApply", "variable": false }, + "27": { + "args": [ + { + "args": [ + { + "node": "KToken", + "sort": { + "name": "String", + "node": "KSort" + }, + "token": "\"_ZN4core3fmt3num53_$LT$impl$u20$core..fmt..LowerHex$u20$for$u20$u32$GT$3fmt17hE\"" + } + ], + "arity": 1, + "label": { + "name": "symbol(_)_LIB_Symbol_String", + "node": "KLabel", + "params": [] + }, + "node": "KApply", + "variable": false + }, + { + "args": [ + { + "node": "KToken", + "sort": { + "name": "Int", + "node": "KSort" + }, + "token": "27" + } + ], + "arity": 1, + "label": { + "name": "defId(_)_BODY_DefId_Int", + "node": "KLabel", + "params": [] + }, + "node": "KApply", + "variable": false + }, + { + "args": [], + "arity": 0, + "label": { + "name": "noBody_BODY_MaybeBody", + "node": "KLabel", + "params": [] + }, + "node": "KApply", + "variable": false + } + ], + "arity": 3, + "label": { + "name": "MonoItemKind::MonoItemFn", + "node": "KLabel", + "params": [] + }, + "node": "KApply", + "variable": false + }, + "28": { + "args": [ + { + "args": [ + { + "node": "KToken", + "sort": { + "name": "String", + "node": "KSort" + }, + "token": "\"_ZN4core3fmt3num53_$LT$impl$u20$core..fmt..UpperHex$u20$for$u20$u32$GT$3fmt17hE\"" + } + ], + "arity": 1, + "label": { + "name": "symbol(_)_LIB_Symbol_String", + "node": "KLabel", + "params": [] + }, + "node": "KApply", + "variable": false + }, + { + "args": [ + { + "node": "KToken", + "sort": { + "name": "Int", + "node": "KSort" + }, + "token": "28" + } + ], + "arity": 1, + "label": { + "name": "defId(_)_BODY_DefId_Int", + "node": "KLabel", + "params": [] + }, + "node": "KApply", + "variable": false + }, + { + "args": [], + "arity": 0, + "label": { + "name": "noBody_BODY_MaybeBody", + "node": "KLabel", + "params": [] + }, + "node": "KApply", + "variable": false + } + ], + "arity": 3, + "label": { + "name": "MonoItemKind::MonoItemFn", + "node": "KLabel", + "params": [] + }, + "node": "KApply", + "variable": false + }, + "29": { + "args": [ + { + "args": [ + { + "node": "KToken", + "sort": { + "name": "String", + "node": "KSort" + }, + "token": "\"_ZN4core3fmt3num3imp52_$LT$impl$u20$core..fmt..Display$u20$for$u20$u32$GT$3fmt17hE\"" + } + ], + "arity": 1, + "label": { + "name": "symbol(_)_LIB_Symbol_String", + "node": "KLabel", + "params": [] + }, + "node": "KApply", + "variable": false + }, + { + "args": [ + { + "node": "KToken", + "sort": { + "name": "Int", + "node": "KSort" + }, + "token": "29" + } + ], + "arity": 1, + "label": { + "name": "defId(_)_BODY_DefId_Int", + "node": "KLabel", + "params": [] + }, + "node": "KApply", + "variable": false + }, + { + "args": [], + "arity": 0, + "label": { + "name": "noBody_BODY_MaybeBody", + "node": "KLabel", + "params": [] + }, + "node": "KApply", + "variable": false + } + ], + "arity": 3, + "label": { + "name": "MonoItemKind::MonoItemFn", + "node": "KLabel", + "params": [] + }, + "node": "KApply", + "variable": false + }, "30": { "args": [ { @@ -27986,6 +28238,69 @@ "node": "KApply", "variable": false }, + "36": { + "args": [ + { + "args": [ + { + "node": "KToken", + "sort": { + "name": "String", + "node": "KSort" + }, + "token": "\"_ZN4core9panicking19assert_failed_inner17hE\"" + } + ], + "arity": 1, + "label": { + "name": "symbol(_)_LIB_Symbol_String", + "node": "KLabel", + "params": [] + }, + "node": "KApply", + "variable": false + }, + { + "args": [ + { + "node": "KToken", + "sort": { + "name": "Int", + "node": "KSort" + }, + "token": "36" + } + ], + "arity": 1, + "label": { + "name": "defId(_)_BODY_DefId_Int", + "node": "KLabel", + "params": [] + }, + "node": "KApply", + "variable": false + }, + { + "args": [], + "arity": 0, + "label": { + "name": "noBody_BODY_MaybeBody", + "node": "KLabel", + "params": [] + }, + "node": "KApply", + "variable": false + } + ], + "arity": 3, + "label": { + "name": "MonoItemKind::MonoItemFn", + "node": "KLabel", + "params": [] + }, + "node": "KApply", + "variable": false + }, "43": { "args": [ { diff --git a/kmir/src/tests/integration/data/prove-rs/closure-staged.rs b/kmir/src/tests/integration/data/prove-rs/closure-staged.rs new file mode 100644 index 000000000..98e256256 --- /dev/null +++ b/kmir/src/tests/integration/data/prove-rs/closure-staged.rs @@ -0,0 +1,11 @@ +fn apply u8>(f: F, v: u8) -> u8 { + f(v) +} + +fn main() { + let delta: u8 = 1u8; + let _captured = |x: u8| x + delta; + + let f = |x: u8| x + 1u8; + assert_eq!(apply(f, 41u8), 42u8); +} diff --git a/kmir/src/tests/integration/data/prove-rs/enum-direct-tag-decode.rs b/kmir/src/tests/integration/data/prove-rs/enum-direct-tag-decode.rs new file mode 100644 index 000000000..30eef03d1 --- /dev/null +++ b/kmir/src/tests/integration/data/prove-rs/enum-direct-tag-decode.rs @@ -0,0 +1,72 @@ +/// Comprehensive test for direct-tag enum decoding. +/// +/// Covers: +/// - `#[repr(u8)]` with discriminants 0/1 (baseline, like Option) +/// - `#[repr(u8)]` with discriminants 2/5 (non-zero start) +/// - `#[repr(u16)]` with discriminants 0/256 (wide tag exceeding u8 range) +/// - `#[repr(u8)]` with 3 variants (beyond two-variant restriction) + +// --- Baseline: repr(u8), disc 0 / 1 ------------------------------------------- + +#[repr(u8)] +enum TwoU8 { + A(bool) = 0, + B(bool) = 1, +} + +const TWO_U8_A: TwoU8 = TwoU8::A(true); +const TWO_U8_B: TwoU8 = TwoU8::B(false); + +// --- Non-zero discriminants: repr(u8), disc 2 / 5 ----------------------------- + +#[repr(u8)] +enum NonZero { + X(bool) = 2, + Y(bool) = 5, +} + +const NZ_X: NonZero = NonZero::X(false); +const NZ_Y: NonZero = NonZero::Y(true); + +// --- Wide tag: repr(u16), disc 0 / 256 ---------------------------------------- + +#[repr(u16)] +enum WideTag { + Lo(bool) = 0, + Hi(bool) = 256, +} + +const WIDE_LO: WideTag = WideTag::Lo(true); +const WIDE_HI: WideTag = WideTag::Hi(false); + +// --- Three variants: repr(u8), disc 0 / 1 / 2 --------------------------------- + +#[repr(u8)] +enum Three { + First(bool) = 0, + Second(bool) = 1, + Third(bool) = 2, +} + +const THREE_A: Three = Three::First(true); +const THREE_B: Three = Three::Second(false); +const THREE_C: Three = Three::Third(true); + +fn main() { + // Baseline + assert!(matches!(TWO_U8_A, TwoU8::A(true))); + assert!(matches!(TWO_U8_B, TwoU8::B(false))); + + // Non-zero discriminants + assert!(matches!(NZ_X, NonZero::X(false))); + assert!(matches!(NZ_Y, NonZero::Y(true))); + + // Wide tag + assert!(matches!(WIDE_LO, WideTag::Lo(true))); + assert!(matches!(WIDE_HI, WideTag::Hi(false))); + + // Three variants + assert!(matches!(THREE_A, Three::First(true))); + assert!(matches!(THREE_B, Three::Second(false))); + assert!(matches!(THREE_C, Three::Third(true))); +} diff --git a/kmir/src/tests/integration/data/prove-rs/iter-eq-copied-take-dereftruncate.rs b/kmir/src/tests/integration/data/prove-rs/iter-eq-copied-take-dereftruncate.rs new file mode 100644 index 000000000..75e7c1b9e --- /dev/null +++ b/kmir/src/tests/integration/data/prove-rs/iter-eq-copied-take-dereftruncate.rs @@ -0,0 +1,32 @@ +fn main() { + let _keep: fn() -> bool = repro; +} + +#[inline(never)] +#[no_mangle] +pub fn repro() -> bool { + let k0 = Pubkey([1; 32]); + let k1 = Pubkey([2; 32]); + let k2 = Pubkey([3; 32]); + let n = 2usize; + + let accounts = [ + AccountInfo { key: &k0 }, + AccountInfo { key: &k1 }, + AccountInfo { key: &k2 }, + ]; + let signers = [k1, k2, k0]; + + accounts[1..] + .iter() + .map(|signer| *signer.key) + .eq(signers.iter().take(n).copied()) +} + +#[derive(Clone)] +struct AccountInfo<'a> { + key: &'a Pubkey, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +struct Pubkey([u8; 32]); diff --git a/kmir/src/tests/integration/data/prove-rs/iter_next_3.rs b/kmir/src/tests/integration/data/prove-rs/iter_next_3.rs new file mode 100644 index 000000000..260b11cae --- /dev/null +++ b/kmir/src/tests/integration/data/prove-rs/iter_next_3.rs @@ -0,0 +1,19 @@ +struct Wrapper { + tag: u8, + a: [[u8; 32]; 3], +} + +fn foo(c: &Wrapper) { + for elem in c.a.iter() { + assert!(elem[0] != 0); + } +} + +fn main() { + let c = Wrapper { + tag: 42, + a: [[1u8; 32], [2u8; 32], [3u8; 32]], + }; + + foo(&c); +} diff --git a/kmir/src/tests/integration/data/prove-rs/show/assume-cheatcode-conflict-fail.check_assume_conflict.expected b/kmir/src/tests/integration/data/prove-rs/show/assume-cheatcode-conflict-fail.check_assume_conflict.expected index 700446f6e..470f41c25 100644 --- a/kmir/src/tests/integration/data/prove-rs/show/assume-cheatcode-conflict-fail.check_assume_conflict.expected +++ b/kmir/src/tests/integration/data/prove-rs/show/assume-cheatcode-conflict-fail.check_assume_conflict.expected @@ -5,7 +5,7 @@ │ │ (61 steps) └─ 3 (stuck, leaf) - #setUpCalleeData ( monoItemFn ( ... name: symbol ( "** UNKNOWN FUNCTION **" ) , + #setUpCalleeData ( monoItemFn ( ... name: symbol ( "_ZN4core9panicking5panic17h span: 32 diff --git a/kmir/src/tests/integration/data/prove-rs/show/interior-mut-fail.main.expected b/kmir/src/tests/integration/data/prove-rs/show/interior-mut-fail.main.expected index 44581b4f2..4c165cf72 100644 --- a/kmir/src/tests/integration/data/prove-rs/show/interior-mut-fail.main.expected +++ b/kmir/src/tests/integration/data/prove-rs/show/interior-mut-fail.main.expected @@ -5,7 +5,7 @@ │ │ (877 steps) └─ 3 (stuck, leaf) - #setUpCalleeData ( monoItemFn ( ... name: symbol ( "** UNKNOWN FUNCTION **" ) , + #setUpCalleeData ( monoItemFn ( ... name: symbol ( "_ZN4core4cell22panic_already span: 32 diff --git a/kmir/src/tests/integration/data/prove-rs/show/iter_next_3.main.expected b/kmir/src/tests/integration/data/prove-rs/show/iter_next_3.main.expected new file mode 100644 index 000000000..a4c5bdc3d --- /dev/null +++ b/kmir/src/tests/integration/data/prove-rs/show/iter_next_3.main.expected @@ -0,0 +1,17 @@ + +┌─ 1 (root, init) +│ #execTerminator ( terminator ( ... kind: terminatorKindCall ( ... func: operandC +│ span: 0 +│ +│ (2028 steps) +├─ 3 (terminal) +│ #EndProgram ~> .K +│ function: main +│ +┊ constraint: true +┊ subst: ... +└─ 2 (leaf, target, terminal) + #EndProgram ~> .K + + + diff --git a/kmir/src/tests/integration/data/prove-rs/show/pointer-cast-length-test-fail.array_cast_test.expected b/kmir/src/tests/integration/data/prove-rs/show/pointer-cast-length-test-fail.array_cast_test.expected index 1a3c758c5..9198552ba 100644 --- a/kmir/src/tests/integration/data/prove-rs/show/pointer-cast-length-test-fail.array_cast_test.expected +++ b/kmir/src/tests/integration/data/prove-rs/show/pointer-cast-length-test-fail.array_cast_test.expected @@ -17,7 +17,7 @@ ┃ │ ┃ │ (6 steps) ┃ └─ 6 (stuck, leaf) -┃ #setUpCalleeData ( monoItemFn ( ... name: symbol ( "** UNKNOWN FUNCTION **" ) , +┃ #setUpCalleeData ( monoItemFn ( ... name: symbol ( "_ZN4core9panicking5panic17h ┃ span: 32 ┃ ┗━━┓ subst: .Subst diff --git a/kmir/src/tests/integration/data/prove-rs/show/spl-multisig-iter-eq-copied-next-fail.repro.expected b/kmir/src/tests/integration/data/prove-rs/show/spl-multisig-iter-eq-copied-next-fail.repro.expected index 378034e6e..645835cf8 100644 --- a/kmir/src/tests/integration/data/prove-rs/show/spl-multisig-iter-eq-copied-next-fail.repro.expected +++ b/kmir/src/tests/integration/data/prove-rs/show/spl-multisig-iter-eq-copied-next-fail.repro.expected @@ -3,10 +3,10 @@ │ #execTerminator ( terminator ( ... kind: terminatorKindCall ( ... func: operandC │ span: 0 │ -│ (1077 steps) +│ (1837 steps) └─ 3 (stuck, leaf) - ListItem ( thunk ( #decodeConstant ( constantKindZeroSized , ty ( 89 ) , typeInf - span: 274 + #execTerminator ( terminator ( ... kind: terminatorKindCall ( ... func: operandM + span: 149 ┌─ 2 (root, leaf, target, terminal) diff --git a/kmir/src/tests/integration/data/prove-rs/show/symbolic-args-fail.main.cli-stats-leaves.expected b/kmir/src/tests/integration/data/prove-rs/show/symbolic-args-fail.main.cli-stats-leaves.expected index 84737597a..e4e10b74c 100644 --- a/kmir/src/tests/integration/data/prove-rs/show/symbolic-args-fail.main.cli-stats-leaves.expected +++ b/kmir/src/tests/integration/data/prove-rs/show/symbolic-args-fail.main.cli-stats-leaves.expected @@ -5,7 +5,7 @@ │ │ (566 steps) └─ 3 (stuck, leaf) - #setUpCalleeData ( monoItemFn ( ... name: symbol ( "** UNKNOWN FUNCTION **" ) , + #setUpCalleeData ( monoItemFn ( ... name: symbol ( "_ZN4core9panicking5panic17h span: no-location:0 @@ -32,7 +32,7 @@ Leaf paths from init: LEAF CELLS --------------- Node 3: - #setUpCalleeData ( monoItemFn ( ... name: symbol ( "** UNKNOWN FUNCTION **" ) , id: defId ( 38 ) , body: noBody ) , operandConstant ( constOperand ( ... span: span ( 32 ) , userTy: noUserTypeAnnotationIndex , const: mirConst ( ... kind: constantKindAllocated ( allocation ( ... bytes: b"\x00\x00\x00\x00\x00\x00\x00\x00\x17\x00\x00\x00\x00\x00\x00\x00" , provenance: provenanceMap ( ... ptrs: provenanceMapEntry ( ... offset: 0 , allocId: allocId ( 1 ) ) .ProvenanceMapEntries ) , align: align ( 8 ) , mutability: mutabilityMut ) ) , ty: ty ( 39 ) , id: mirConstId ( 25 ) ) ) ) .Operands , span ( 117 ) ) ~> .K - >> function: core::panicking::panic::h941160ead03e2d54 + #setUpCalleeData ( monoItemFn ( ... name: symbol ( "_ZN4core9panicking5panic17hE" ) , id: defId ( 38 ) , body: noBody ) , operandConstant ( constOperand ( ... span: span ( 32 ) , userTy: noUserTypeAnnotationIndex , const: mirConst ( ... kind: constantKindAllocated ( allocation ( ... bytes: b"\x00\x00\x00\x00\x00\x00\x00\x00\x17\x00\x00\x00\x00\x00\x00\x00" , provenance: provenanceMap ( ... ptrs: provenanceMapEntry ( ... offset: 0 , allocId: allocId ( 1 ) ) .ProvenanceMapEntries ) , align: align ( 8 ) , mutability: mutabilityMut ) ) , ty: ty ( 39 ) , id: mirConstId ( 25 ) ) ) ) .Operands , span ( 117 ) ) ~> .K + >> function: core::panicking::panic::h >> call span: /kmir/src/tests/integration/data/prove-rs/symbolic-args-fail.rs:53:5 >> message: 'assertion failed: false' \ No newline at end of file diff --git a/kmir/src/tests/integration/data/prove-rs/show/symbolic-args-fail.main.expected b/kmir/src/tests/integration/data/prove-rs/show/symbolic-args-fail.main.expected index ef7740af7..e5b630195 100644 --- a/kmir/src/tests/integration/data/prove-rs/show/symbolic-args-fail.main.expected +++ b/kmir/src/tests/integration/data/prove-rs/show/symbolic-args-fail.main.expected @@ -5,7 +5,7 @@ │ │ (566 steps) └─ 3 (stuck, leaf) - #setUpCalleeData ( monoItemFn ( ... name: symbol ( "** UNKNOWN FUNCTION **" ) , + #setUpCalleeData ( monoItemFn ( ... name: symbol ( "_ZN4core9panicking5panic17h span: 32 diff --git a/kmir/src/tests/integration/data/prove-rs/show/symbolic-structs-fail.eats_struct_args.expected b/kmir/src/tests/integration/data/prove-rs/show/symbolic-structs-fail.eats_struct_args.expected index a3abc238d..673eb0193 100644 --- a/kmir/src/tests/integration/data/prove-rs/show/symbolic-structs-fail.eats_struct_args.expected +++ b/kmir/src/tests/integration/data/prove-rs/show/symbolic-structs-fail.eats_struct_args.expected @@ -29,7 +29,7 @@ ┃ ┃ │ ┃ ┃ │ (6 steps) ┃ ┃ └─ 10 (stuck, leaf) -┃ ┃ #setUpCalleeData ( monoItemFn ( ... name: symbol ( "** UNKNOWN FUNCTION **" ) , +┃ ┃ #setUpCalleeData ( monoItemFn ( ... name: symbol ( "_ZN4core9panicking5panic17h ┃ ┃ span: 32 ┃ ┃ ┃ ┗━━┓ subst: .Subst diff --git a/kmir/src/tests/integration/data/prove-rs/show/test_offset_from-fail.testing.expected b/kmir/src/tests/integration/data/prove-rs/show/test_offset_from-fail.testing.expected index a0ac24cae..8fd816dd8 100644 --- a/kmir/src/tests/integration/data/prove-rs/show/test_offset_from-fail.testing.expected +++ b/kmir/src/tests/integration/data/prove-rs/show/test_offset_from-fail.testing.expected @@ -114,7 +114,7 @@ ┃ │ ┃ │ (70 steps) ┃ └─ 22 (stuck, leaf) - ┃ #setUpCalleeData ( monoItemFn ( ... name: symbol ( "** UNKNOWN FUNCTION **" ) , + ┃ #setUpCalleeData ( monoItemFn ( ... name: symbol ( "_ZN4core9panicking5panic17h ┃ span: 32 ┃ ┗━━┓ subst: .Subst diff --git a/kmir/src/tests/integration/test_integration.py b/kmir/src/tests/integration/test_integration.py index 101f9141e..d9ddc37ae 100644 --- a/kmir/src/tests/integration/test_integration.py +++ b/kmir/src/tests/integration/test_integration.py @@ -38,6 +38,7 @@ 'assume-cheatcode-conflict-fail': ['check_assume_conflict'], 'transmute-bytes': ['bytes_to_u64', 'u64_to_bytes'], 'test_offset_from-fail': ['testing'], + 'iter-eq-copied-take-dereftruncate': ['repro'], 'spl-multisig-iter-eq-copied-next-fail': ['repro'], 'spl-multisig-signer-index': ['repro'], } @@ -45,6 +46,7 @@ 'local-raw-fail', 'interior-mut-fail', 'interior-mut3-fail', + 'iter_next_3', 'assert_eq_exp', 'bitwise-not-shift', 'symbolic-args-fail', diff --git a/kmir/src/tests/unit/test_fixtures.py b/kmir/src/tests/unit/test_fixtures.py new file mode 100644 index 000000000..b9a3de5b5 --- /dev/null +++ b/kmir/src/tests/unit/test_fixtures.py @@ -0,0 +1,27 @@ +from __future__ import annotations + +import pytest + +from kmir.testing.fixtures import _normalize_symbol_hashes + + +@pytest.mark.parametrize( + ('raw', 'expected'), + [ + ( + '_ZN4core3fmt3num53_$LT$impl$u20$core..fmt..LowerHex$u20$for$u20$u32$GT$3fmt17hb987357f13dc6cc8E', + '_ZN4core3fmt3num53_$LT$impl$u20$core..fmt..LowerHex$u20$for$u20$u32$GT$3fmt17hE', + ), + ( + '_ZN4core3fmt3num53_$LT$impl$u20$core..fmt..LowerHex$u20$for$u20$u32$GT$3fmt17hb987357f13dc6cc8', + '_ZN4core3fmt3num53_$LT$impl$u20$core..fmt..LowerHex$u20$for$u20$u32$GT$3fmt17h', + ), + ( + 'core::panicking::panic::h941160ead03e2d54', + 'core::panicking::panic::h', + ), + ], + ids=['generic-mangled-full', 'generic-mangled-truncated', 'demangled'], +) +def test_normalize_symbol_hashes(raw: str, expected: str) -> None: + assert _normalize_symbol_hashes(raw) == expected