)]}'
{
  "log": [
    {
      "commit": "50092ba823778427c4cef09ed66b84b7f9e689fa",
      "tree": "cf914709d8ce7bc874f897024ab9fa6981129b31",
      "parents": [
        "4210572d0e83f8bfb160a19457ef3369c3fe0bae"
      ],
      "author": {
        "name": "Shushi Hong",
        "email": "820958424@qq.com",
        "time": "Mon Sep 14 22:37:36 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 14 22:37:36 2026 -0400"
      },
      "message": "[Fix][Rust] Align structural mutation remapping policy (#792)\n\nRust structural map currently caches complete callback results for\nFreeVar and DAG identities, skipping callbacks at subsequent\noccurrences. Align it with the C++ policy from #771: run callbacks at\nevery occurrence and handle identity substitutions only in default\nreflected descent or registered type hooks.\n\nShare the default remapping path with structural mutate. Unbound FreeVar\nuses retain their identity without field descent; unchanged Simple\ndefinitions stay absent, while Pattern definitions and DAG nodes can\ncache Unchanged. Preserve owned remap keys and update the Rust guide."
    },
    {
      "commit": "4210572d0e83f8bfb160a19457ef3369c3fe0bae",
      "tree": "fbd55aef9585c133e77621ea2e57e6ff0a2fc555",
      "parents": [
        "6118c1febc8eba8c486ce2f639d4c95e118e8bba"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Mon Sep 14 20:19:11 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 14 20:19:11 2026 -0400"
      },
      "message": "[FEAT] Add consuming casts and raw adoption to UnchangedOr (#791)\n\nAdd rvalue-qualified `UnchangedOr\u003cT\u003e::as\u003cU\u003e()` and `as_or_throw\u003cU\u003e()`\nfor strict casts to an exact target type. Forwarding to `Any` preserves\nits supported types, mismatch behavior and ownership transfer, including\nsuccessful unchanged results when the target is another `UnchangedOr`.\n\nAdd the symmetric raw-storage adoption helper for ABI callers that\nalready guarantee an unchanged marker or a valid replacement."
    },
    {
      "commit": "6118c1febc8eba8c486ce2f639d4c95e118e8bba",
      "tree": "df12c7feae80714ade15c7f1e68a6a3fcc7cfd0f",
      "parents": [
        "f34b3889f6ca3372cb18efc6d48924b067ed835c"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Mon Sep 14 19:54:47 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 14 19:54:47 2026 -0400"
      },
      "message": "[FEAT] Support optional structural visit early returns (#790)\n\nAllow exception-first structural visitors to use\n`TVM_FFI_S_VISIT_MAYBE_EARLY_RETURN` with `Optional\u003cVisitInterrupt\u003e`.\n`VisitReturnHelper` forwards optional interrupts directly and preserves\nthe existing Expected return proxy for typed helpers and raw hooks.\n\nIncludes a focused regression for optional continuation and interrupt\npropagation."
    },
    {
      "commit": "f34b3889f6ca3372cb18efc6d48924b067ed835c",
      "tree": "e22dcbbdf3bc93a67358faaffc80e23538da18fe",
      "parents": [
        "cab37f41c6c1472605a07fb4d4ce4600334572b9"
      ],
      "author": {
        "name": "Shushi Hong",
        "email": "820958424@qq.com",
        "time": "Mon Sep 14 19:39:35 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 14 19:39:35 2026 -0400"
      },
      "message": "[FEAT][Rust] Preserve unchanged structural mutation results (#785)\n\nAdd `Unchanged` and `UnchangedOr\u003cT\u003e` to Rust and preserve unchanged\nresults through recursive mutation, native hooks, and reflected field\nupdates. Fix pre-order structural mapping so callbacks returning\n`Unchanged` still traverse the original value\u0027s children.\n\nAdd `mutate_result` and `default_mutate_result` helpers, with typed\nconversion and original-value recovery support. Existing callbacks and\nowning-value APIs remain compatible."
    },
    {
      "commit": "cab37f41c6c1472605a07fb4d4ce4600334572b9",
      "tree": "7c8229e1078c15a025774e55bc9907d6acf3f321",
      "parents": [
        "4ffc1f35f3c9853b53f2e854768a9acc6cbf3b85"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Mon Sep 14 15:52:48 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 14 15:52:48 2026 -0400"
      },
      "message": "feat: add Expected error-return checks (#789)\n\nAdd streamed source-located errors and return-check helpers for Expected\nfunctions. Consolidate the caller-guaranteed unsafe structural\nassignment helper while preserving existing safe structural macro names."
    },
    {
      "commit": "4ffc1f35f3c9853b53f2e854768a9acc6cbf3b85",
      "tree": "00805adca699ba873a60a60ec20d00ccf3f2e345",
      "parents": [
        "2dea07f3a9399ddbbc580572f7e6ad68820eabb5"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Mon Sep 14 13:16:09 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 14 13:16:09 2026 -0400"
      },
      "message": "[FEAT] Add strict narrowing for Expected values (#787)\n\nAdd `const \u0026` and `\u0026\u0026` overloads of `Expected\u003cT\u003e::as_or_error\u003cU\u003e()` for\nstrict narrowing while preserving existing errors. Accepted values reuse\ntheir FFI storage; mismatches return `TypeError` without fallback\nconversion.\n\nThe lvalue overload copies storage and preserves its source, while the\nrvalue overload moves storage. Targets follow owning FFI storage\nconstraints."
    },
    {
      "commit": "2dea07f3a9399ddbbc580572f7e6ad68820eabb5",
      "tree": "339094f991809ee04e846956573a38b68be82f91",
      "parents": [
        "0f8e4a429b3278dde0f41fe0ca088f9db418473a"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Mon Sep 14 13:16:01 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 14 13:16:01 2026 -0400"
      },
      "message": "[REFACTOR] Remove redundant BigInt structural-kind metadata (#788)\n\nRemove BigIntObj\u0027s explicit structural equality/hash kind, matching\nStringObj and BytesObj. BigInt continues to use its dedicated numeric\nequality, hashing, and immutable-leaf behavior."
    },
    {
      "commit": "0f8e4a429b3278dde0f41fe0ca088f9db418473a",
      "tree": "aa9f87788ab3a250861b9b08832dd8fe5d3695bc",
      "parents": [
        "48248b06585515d63fb80eb20cab371e29d8e5e6"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Mon Sep 14 12:26:46 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 14 12:26:46 2026 -0400"
      },
      "message": "[API] Consolidate structural mutation entrypoints and borrowed fallback (#786)\n\nConsolidate structural mutation into `MutateExpected(AnyView,\nInplaceMode)` and `DefaultMutateExpected(AnyView, InplaceMode)`, with a\nmatching throwing `Mutate` entrypoint. All three default to\n`InplaceMode::kDisallow`. `kAllow` permits in-place dispatch only along\nan owned path with a unique current value; default descent trusts the\ncallback\u0027s validated mode without rechecking uniqueness. Remove the\nsuperseded entrypoints and migrate recursive callers while preserving\nthe raw FFI hooks, vtable layout, and copy-on-write behavior.\n\nC++ mutation callbacks receive the explicit mode. Python exposes\n`InplaceMode.DISALLOW` and `InplaceMode.ALLOW`; optional callback modes\nuse their corresponding integer values through the existing FFI enum\nconversion.\n\nAdd `ValueOrUnchanged(const T\u0026) \u0026\u0026` to copy a borrowed fallback only\nwhen unchanged and move replacements otherwise.\n\n## Migration\n\nThis intentionally changes the C++ convenience API. Consumers, including\nApache TVM, must migrate these calls together with their tvm-ffi\ndependency update.\n\n| Removed call | Replacement |\n| --- | --- |\n| `Mutate\u003cT\u003e` / `MutateExpected\u003cT\u003e` | Use `MutateExpected(value,\nInplaceMode::kDisallow)` with checked typed unwrapping below, or\n`Mutate` at a throwing boundary. |\n| `MaybeInplaceMutateIfUniqueExpected`, `MaybeInplaceMutate\u003cT\u003e` /\n`MaybeInplaceMutateExpected\u003cT\u003e` | Use `MutateExpected(value,\ninplace_mode)`, or `Mutate(value, inplace_mode)` at a throwing boundary.\n|\n| `DefaultMaybeInplaceMutateExpected` | Use\n`DefaultMutateExpected(value, inplace_mode)` for the current node\u0027s\ndefault descent with its already-validated mode. |\n\nChange a typed callback\u0027s optional third argument to `InplaceMode` and\nforward it explicitly during recursion. `kAllow` requires permission\nalong the entire ownership path, established by an owned root or a valid\nin-place hook; a unique borrowed child alone does not grant that\npermission. Otherwise use `kDisallow`. `MutateExpected` checks the\ncurrent value\u0027s uniqueness before callback arguments acquire ownership.\nDefault descent bypasses the current callback and trusts the established\nmode without rechecking uniqueness.\n\nFor `Expected` helpers and raw hooks,\n`TVM_FFI_S_MUTATE_ASSIGN_OR_RETURN` preserves the fixed typed-mutation\n`TypeError` diagnostic. For example, with `Expr` as the required result\ntype:\n\n```cpp\nExpected\u003cExpr\u003e MutateExpr(const Expr\u0026 original, StructuralMutatorObj* mutator,\n                          InplaceMode inplace_mode) {\n  TVM_FFI_S_MUTATE_ASSIGN_OR_RETURN(\n      UnchangedOr\u003cExpr\u003e, result, mutator-\u003eMutateExpected(original, inplace_mode));\n  return std::move(result).ValueOrUnchanged(original);\n}\n```\n\nCall `.value()` only at a throwing boundary. An explicit\n`.ValueOrUnchanged(...).cast\u003cT\u003e()` there is also possible when its\nseparate runtime cast diagnostic is acceptable; it is not a replacement\nfor checked narrowing in an `Expected` helper or raw hook."
    },
    {
      "commit": "48248b06585515d63fb80eb20cab371e29d8e5e6",
      "tree": "1087452ee018c89dedfc3fea75eae9569cf46aff",
      "parents": [
        "c8e513d5525189bcf06afdc30aac33e862b9e5fd"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Mon Sep 14 07:33:00 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 14 07:33:00 2026 -0400"
      },
      "message": "[FEAT] BigInt support for arbitrary-precision integer value (#783)\n\nThis PR adds a canonical arbitrary-precision integer value with an\ninline\nint64 fast path and one variable-length object for larger values. BigInt\nis a tagged union that stores either an int64_t or a BigIntObj\ncontaining\na dynamically sized array of 64-bit words.\n\nKey design details include:\n\n- Arithmetic automatically promotes to higher precision when needed,\n  preserving integer results without overflow.\n- Storage is canonical: values that fit in int64_t are always stored\n  inline, and BigIntObj never contains redundant sign-extension words.\n- Full integer operator coverage includes arithmetic, bitwise\noperations,\n  shifts, comparisons, and compound assignments, with int64 fast paths\n  and arbitrary-precision fallbacks.\n- The Python interface automatically exchanges BigInt values as native\n  Python integers, preserving arbitrary precision in both directions.\n- Graph serialization uses the existing data hooks to store heap BigInt\nvalues\n  as decimal strings under `ffi.BigInt`, preserving arbitrary precision.\n\n## Notes\n\nSeveral common int64 workloads are around 3–4× slower with BigInt than\nwith raw int64_t. We recommend using BigInt when stored values may\nexceed\nthe int64 range.\n\n## ABI\n\n- BigIntObj stores a word count followed by native int64_t words\nencoding a\nsigned two\u0027s-complement integer, least-significant word first. Each word\n  uses native byte order.\n- The signed-word representation MUST be minimal, with no redundant\nsign-extension words and a sign guard retained when necessary. Every\nvalue\n  fitting int64_t MUST use the inline kTVMFFIInt representation.\n- Canonical inline and object representations cannot be numerically\nequal.\nEquality between heap values compares their normalized word counts and\nwords.\n- Arithmetic fallbacks consume normalized operand views without\nredundant\nsign words. Result normalization prunes sign extension and demotes\nfitting\n  values to the inline representation."
    },
    {
      "commit": "c8e513d5525189bcf06afdc30aac33e862b9e5fd",
      "tree": "5db278421c038b22a1951693dba64495ae03e8d2",
      "parents": [
        "20f0df6a38c1489cd035cf9702d533304c81bf96"
      ],
      "author": {
        "name": "Shushi Hong",
        "email": "820958424@qq.com",
        "time": "Sun Sep 13 22:31:03 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 13 22:31:03 2026 -0400"
      },
      "message": "[Fix][Rust] Map children of inline pre-order replacements (#784)\n\nWhen a pre-order callback replaces an inline value with an object, map\nthe replacement children through the existing default-root path. Keep\ninline results and post-order replacements on the direct return path."
    },
    {
      "commit": "20f0df6a38c1489cd035cf9702d533304c81bf96",
      "tree": "ddb4730902fb9a17697624aeaa68e84a4c729d5c",
      "parents": [
        "a54d3f67fb1f9dd640c0c6f34bb4e513a9637459"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Sun Sep 13 13:10:48 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 13 13:10:48 2026 -0400"
      },
      "message": "[FEAT] Add optional in-place permission to default structural descent (#781)\n\nAdd optional `bool allow_inplace \u003d true` to\n`StructuralMutatorObj::DefaultMaybeInplaceMutateExpected` so callbacks\ncan forward their permission directly. False delegates to\n`DefaultMutateExpected`; true and omission preserve the existing\nbehavior and ownership preconditions. Document the helper and simplify\nan existing callback.\n\nValidation: Debug C++ build, 69 existing structural tests, and\nchanged-file checks passed."
    },
    {
      "commit": "a54d3f67fb1f9dd640c0c6f34bb4e513a9637459",
      "tree": "b8faa36d985176852f8814154d97a1492d2b3798",
      "parents": [
        "be35ec1297d6ddf388b7feb4f2e89d2cf030dda8"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Sun Sep 13 11:54:36 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 13 11:54:36 2026 -0400"
      },
      "message": "[FIX] Forward implicitly convertible values into UnchangedOr (#782)\n\nAllow values implicitly convertible to the replacement type to\ninitialize UnchangedOr directly, enabling bare object returns through\nExpected\u003cUnchangedOr\u003cAny\u003e\u003e. The constrained C++17 forwarding constructor\nmaterializes the replacement type and preserves dedicated unchanged,\nerror, and wrapper conversions."
    },
    {
      "commit": "be35ec1297d6ddf388b7feb4f2e89d2cf030dda8",
      "tree": "784c5f2d6a58783f035885f7da35b907509dc7d5",
      "parents": [
        "3b0e30b1f425c554168ab5cd91b497a0b5ecaaf4"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Sat Sep 12 11:00:51 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 12 11:00:51 2026 -0400"
      },
      "message": "[PERF] Reduce structural traversal result overhead (#780)\n\nKeep compiled structural visit hooks on the raw TVMFFIAny path through\ndefault descent and callback selection to avoid repeated result\nmaterialization. Keep error-context decoration off the success path,\ninline WalkResult lifecycle operations, and retain typed Parent\ncustomization while preserving callback order, descent control, errors\nand interrupt ownership."
    },
    {
      "commit": "3b0e30b1f425c554168ab5cd91b497a0b5ecaaf4",
      "tree": "65025e060a98161afa331175867824fe227c961f",
      "parents": [
        "7fb9aecf7780f815fd1d38b8d801d4020dd579e5"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Sat Sep 12 09:26:52 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 12 09:26:52 2026 -0400"
      },
      "message": "[IR] Expose protected remap state and skip empty lookups (#779)\n\nExpose `var_remap_` as protected state so derived structural map engines\ncan inspect the remap environment. Skip the identity-map lookup when the\nenvironment is empty, after validating the key."
    },
    {
      "commit": "7fb9aecf7780f815fd1d38b8d801d4020dd579e5",
      "tree": "0efc9b40658616ef40449f7242d4f692c2b23752",
      "parents": [
        "bb786912ad60af2335d82a60c3a7224a3eb0269a"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Fri Sep 11 18:10:10 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Sep 11 18:10:10 2026 -0400"
      },
      "message": "[EXTRA] Enable typed mutation result conversions and subsumption (#777)\n\nTyped structural mutation helpers need to convert compatible\n`UnchangedOr` results and propagate child errors across different\nsuccess types. The assignment macro also repeats checks for already\ncompatible typed results.\n\nAdd implicit `UnchangedOr` conversions and storage-subsumption rules for\n`UnchangedOr` and `Expected`. Initialize subsumed conversions directly\nfrom their stored carrier, avoiding an intermediate assignment. Use\nsubsumption to omit redundant assignment checks while retaining checks\nfor erased or narrower sources, and propagate child errors through the\nexisting error-only return helper. Correct the borrowed `AnyView`\nadapter for wrapper values."
    },
    {
      "commit": "bb786912ad60af2335d82a60c3a7224a3eb0269a",
      "tree": "a21f828ac6b045502f943e7da3ca9b8152f3e682",
      "parents": [
        "70e5af34b162096340695c583b11c197f3a89595"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Fri Sep 11 12:57:40 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Sep 11 12:57:40 2026 -0400"
      },
      "message": "[EXTRA] Allow callers to disable unique in-place mutation (#776)\n\nNative handlers can pass their in-place permission directly to\nMaybeInplaceMutateIfUniqueExpected. Add an optional allow_inplace flag,\ndefaulting to true; false dispatches ordinary mutation without checking\nuniqueness."
    },
    {
      "commit": "70e5af34b162096340695c583b11c197f3a89595",
      "tree": "8289726a645ba104d5135868a2cc384aa8eb9cdb",
      "parents": [
        "fb8e102418e8219ca351e3213904f22721e91f69"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Thu Sep 10 17:37:36 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 10 17:37:36 2026 -0400"
      },
      "message": "[PERF] Forward single StructuralMutate callbacks directly (#774)\n\nForward single StructuralMutate callback results directly and use\nbool-match/result-output dispatch for multiple callbacks. Preserve\nowning conversions, typed fallback, first-match behavior, and cold\nerror-context attachment."
    },
    {
      "commit": "fb8e102418e8219ca351e3213904f22721e91f69",
      "tree": "3446b3cbdb07f8f24c19f18f42db7979107b93ba",
      "parents": [
        "c5e636bbfb097cca610acee841e26d751d47a63b"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Thu Sep 10 11:34:48 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 10 11:34:48 2026 -0400"
      },
      "message": "[REFACTOR] Type default structural mutation results as UnchangedOr\u003cAny\u003e (#773)\n\nType the default structural mutation helpers as\nExpected\u003cUnchangedOr\u003cAny\u003e\u003e, matching the protocol already exposed by the\npublic mutation entry points.\n\nThe raw TVMFFIAny hook and vtable ABI remain unchanged. The registered\nwrapper now returns the strong unchanged-or-replacement type directly,\nwith focused compile-time and runtime coverage.\n\nValidation:\n- 20 focused UnchangedOr/StructuralMutate/StructuralMap tests\n- 497 enabled CTest tests\n- formatting and repository lint checks\n- identical normalized hot/cold instruction and relocation listings for\nboth default helpers under GCC 11.4.0 at -O3 before and after the change"
    },
    {
      "commit": "c5e636bbfb097cca610acee841e26d751d47a63b",
      "tree": "6f10f106de4c1e0b7dc92b2b74a718ca7cdde945",
      "parents": [
        "b02536e4f3804e2e41dacf2ad2d52da805f46d90"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Wed Sep 09 18:33:57 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 09 18:33:57 2026 -0400"
      },
      "message": "[EXTRA] Simplify StructuralMap engine policy (#771)\n\nStructuralMap needs identity state only to keep variables consistent\nwhen\ndescent rewrites a definition. Callback results are separate: callbacks\nrun\nat every occurrence in their selected pre- or post-descent position.\n\nMake default C++ descent the sole owner of FreeVar and DAG remapping,\nwith\ndefinitions binding rewritten results and unchanged simple definitions\nleft\nabsent. Keep the remap ABI stable and use an owned raw-pointer-keyed\nstore for\nefficient identity lookups.\n\nAdopt whole raw TVMFFIAny results by value while leaving\ndestructor-visible\nslot moves pointer-based. Initialize owning Any storage member-wise so\nGCC\nretains scalar state and avoids an overlapping narrow-store/wide-reload\nstall.\n\nUpdate existing C++ and Python expectations in place and document\nStructuralMap as post(D(pre)) alongside StructuralWalk\u0027s stateless tree\ntraversal. Rust remains unchanged for a follow-up."
    },
    {
      "commit": "b02536e4f3804e2e41dacf2ad2d52da805f46d90",
      "tree": "4ec86a3483ef0b83a2ae0e333be966ee56bb5998",
      "parents": [
        "39d593e716a5b437a57ea3241aff8850112caf2e"
      ],
      "author": {
        "name": "Shushi Hong",
        "email": "820958424@qq.com",
        "time": "Wed Sep 09 16:51:47 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 09 16:51:47 2026 -0400"
      },
      "message": "Revert \"[Rust][Fix] Preserve object lifetime and thread-safety contracts\" (#772)\n\nReverts apache/tvm-ffi#766"
    },
    {
      "commit": "39d593e716a5b437a57ea3241aff8850112caf2e",
      "tree": "03549c98d7578506db9bae893030e6802b6f19bf",
      "parents": [
        "40c6c744c2aabf0bc46f8fee529f5da6ec68d478"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Tue Sep 08 18:22:59 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Sep 08 18:22:59 2026 -0400"
      },
      "message": "[FFI][REFACTOR] Introduce UnchangedOr for StructuralMutate (#768)\n\nThis change refactors StructuralMutate to introduce `UnchangedOr\u003cT\u003e`,\nwhich can indicate that a mutation did not change the input value; if a\nvalue is changed, it is held in the container. Previously, Mutate simply\nreturned a fresh copy of the original value when unchanged.\nPerformance-wise, this results in a refcount bump and decref for every\nnode examined, even when there is no change. Depending on the hardware\nplatform, the overhead can be visible. This change introduces a special\n`UnchangedOr\u003cT\u003e`, which holds the `kTVMFFIUnchanged` tag to indicate\nthat a mutation did not result in a change, while a changed value is\npropagated through the container. The canonical mutation hook pattern\nstill works well, in a cleaner form:\n\n```c++\nTVMFFIAny FooMutate(StructuralMutatorObj* mutator, AnyView value) noexcept {\n  const FooNode* self \u003d\n      details::AnyUnsafe::RawObjectPtrFromAnyViewAfterCheck\u003cconst FooNode\u003e(value);\n  TVM_FFI_S_MUTATE_ASSIGN_OR_RETURN(UnchangedOr\u003cExpr\u003e, a,\n                                    mutator-\u003eMutateExpected(self-\u003ea));\n  TVM_FFI_S_MUTATE_ASSIGN_OR_RETURN(UnchangedOr\u003cExpr\u003e, b,\n                                    mutator-\u003eMutateExpected(self-\u003eb));\n  if (a.UnchangedOrSameAs(self-\u003ea) \u0026\u0026 b.UnchangedOrSameAs(self-\u003eb)) {\n    TVM_FFI_S_MUTATE_RETURN_UNCHANGED();\n  }\n  ObjectPtr\u003cFooNode\u003e copy \u003d make_object\u003cFooNode\u003e(*self);\n  copy-\u003ea \u003d std::move(a).ValueOrUnchanged(std::move(copy-\u003ea));\n  copy-\u003eb \u003d std::move(b).ValueOrUnchanged(std::move(copy-\u003eb));\n  return details::AnyUnsafe::MoveAnyToTVMFFIAny(Any(std::move(copy)));\n}\n```\n\nThe engine is updated to be aware of the new convention."
    },
    {
      "commit": "40c6c744c2aabf0bc46f8fee529f5da6ec68d478",
      "tree": "5235aeba68d5d21847cf2b9cb06c525f41df0efb",
      "parents": [
        "1a2976896412110327500467977bcb112f426627"
      ],
      "author": {
        "name": "Shushi Hong",
        "email": "820958424@qq.com",
        "time": "Tue Sep 08 17:02:52 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Sep 08 17:02:52 2026 -0400"
      },
      "message": "[Rust][Fix] Preserve object lifetime and thread-safety contracts (#766)\n\nThis PR addresses object construction and lifetime issues in Rust\nbindings without changing the C ABI.\n- Add a no-alloc stubgen directive to preserve readable fields while\nsuppressing generated allocators for registry-owned types and their\ndescendants.\n- Reuse the existing nullable and custom-new directives for fields that\nnative code may move out, without introducing a separate\nnullable-storage mechanism.\n- Make objects non-Send/non-Sync by default, including erased and\nborrowed views. Keep Function shareable by requiring thread-safe\ncallback captures.\n- Require unique ownership for mutable ObjectArc access, align\nreference-count ordering with C++, and preserve allocation metadata when\nweak references outlive objects with trailing storage.\n\nThese changes tighten Rust source-level contracts. Downstream code\nrelying on cross-thread object sharing or non-thread-safe callback\ncaptures may require adaptation."
    },
    {
      "commit": "1a2976896412110327500467977bcb112f426627",
      "tree": "9c4f78ebd6c8a2be67a0a939dd1e8402c4507092",
      "parents": [
        "786a9b22434b83c00dc5c68df4e66aee599496a5"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Tue Sep 08 13:38:03 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Sep 08 13:38:03 2026 -0400"
      },
      "message": "[FFI][REFACTOR] Clarify DefRegionKind (#769)\n\nRename the two def-region kinds from Recursive / NonRecursive to Pattern\n/\nSimple, with the matching field-flag bits and the Python, Rust and doc\nmirrors: a pattern def region matches the value\u0027s type as a pattern,\nbinding\nits free variables; a simple def region defines the variable alone and\nwalks\nits type as uses. The comments now state the binding rule and the clamp\nthat\ncustom hooks on FreeVar types must apply.\n\nA pattern region propagates: entering any kind inside it has no effect,\nso a\nsimple def nested under a pattern (a pattern field, or map_free_vars at\nthe\ntop level) still binds the free variables in its type. Applied in the\nequal,\nhash, visit and mutate engines and in the Rust visitor and mutator, with\na\ntest for the nested case.\n\nPython keeps \"def\" as the only alias of \"def-pattern\".\n\nNo ABI changes involved: enum values and flag bit positions are\nunchanged."
    },
    {
      "commit": "786a9b22434b83c00dc5c68df4e66aee599496a5",
      "tree": "f96149b11f964334f858642dc92a3438a9b30602",
      "parents": [
        "5481551c2cab3073db218dbbef1b785c5f810734"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Mon Sep 07 23:21:39 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 07 23:21:39 2026 -0400"
      },
      "message": "[FFI][PERF] AnyUnsafe::CheckAnyViewStrict for a borrowed AnyView (#767)\n\n`AnyUnsafe::CheckAnyStrict\u003cT\u003e` takes only `const Any\u0026`, so a caller\nchecking an `ObjectRef` field it does not own (TVM\u0027s `TypedExpr` /\n`TypedVar` traits checking `ty`) builds a temporary owning `Any`: a\nrefcount pair and ~40 instructions per check. Add\n`CheckAnyViewStrict\u003cT\u003e(const AnyView\u0026)` with the same body; a distinct\nname rather than an overload, so an `ObjectRef` argument never has two\nconversions to choose from and existing callers are untouched. Callers\npass `AnyView(field)`. Checking an `ObjectRef` through the view: 8\ninstructions, no atomics, against 50 and 3 for the owning form."
    },
    {
      "commit": "5481551c2cab3073db218dbbef1b785c5f810734",
      "tree": "55a36cc8afa86cb2a16348a01585f57c156caa90",
      "parents": [
        "469d71f50c280f707bd4079af93f64f8dd9dfce8"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Mon Sep 07 22:01:56 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 07 22:01:56 2026 -0400"
      },
      "message": "[FFI][FIX] Use int64_t for the parsed TVM_TRACEBACK_LIMIT (#765)\n\nclang-tidy `google-runtime-int` rejects the `long` introduced in #763 at\n`backtrace_utils.h:47`. Store the `strtol` result in `int64_t`; the\nrange check is unchanged."
    },
    {
      "commit": "469d71f50c280f707bd4079af93f64f8dd9dfce8",
      "tree": "68468732fff220004de76577734908ed0e410915",
      "parents": [
        "d063f470b4973bda02da85b7d7e61b8de927acd0"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Mon Sep 07 21:05:26 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 07 21:05:26 2026 -0400"
      },
      "message": "[FFI][PERF] Force-inline ObjectPtr::reset and WeakObjectPtr::reset (#764)\n\n`~ObjectPtr()` is `TVM_FFI_INLINE` and delegates to `reset()`, which was\na plain function, so in a large hook every `ObjectPtr` destruction still\ncompiled to an out-of-line `call ObjectPtr\u003cObject\u003e::reset` Mark both\n`reset()` methods the same way as the special members in #761. No\nbehaviour change."
    },
    {
      "commit": "d063f470b4973bda02da85b7d7e61b8de927acd0",
      "tree": "b3bea6913a55b0b0201ff1c251dedbc63f0d778b",
      "parents": [
        "f0d5bf5148dcce669edc3c34d9c004a5126051b9"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Mon Sep 07 20:54:22 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 07 20:54:22 2026 -0400"
      },
      "message": "[FFI][FIX] Backtrace: refresh DbgHelp modules, tolerate bad TVM_TRACEBACK_LIMIT, match object_is_not_callable exactly (#763)\n\nFour small fixes from the follow-up report on #727:\n\n- `backtrace_win.cc`: `SymRefreshModuleList` before `StackWalk64`. The\nsession is created once, so a DLL loaded after the first backtrace was\nunknown to DbgHelp; `StackWalk64` needs its unwind tables, so the trace\ntruncated at that frame.\n- `backtrace_win.cc`: the explicit caller frame goes through\n`ShouldExcludeFrame`, as `backtrace.cc` already does.\n- `backtrace_utils.h`: `TVM_TRACEBACK_LIMIT` parsed with `strtol`,\ndefault on invalid input. `std::stoi` threw inside the error reporter\nand terminated the process.\n- `backtrace_utils.h`: full-identifier match for\n`object_is_not_callable`; the 11-character prefix also matched other\n`object_is_n...` symbols.\n\nNo behaviour change for valid inputs."
    },
    {
      "commit": "f0d5bf5148dcce669edc3c34d9c004a5126051b9",
      "tree": "f0c0a14e5b24fdac17b7116fe6b6b9d74a525618",
      "parents": [
        "e74e58f9d8a6fb1ece5722d0715f68187a8e0385"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Mon Sep 07 20:01:23 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 07 20:01:23 2026 -0400"
      },
      "message": "[FFI][REFACTOR] Remove TVM_FFI_S_VISIT_RETURN_NONE (#762)\n\nThe macro only spelled\n`Expected\u003cOptional\u003cVisitInterrupt\u003e\u003e(std::nullopt)` through\n`MaybeReturnHelper`. A raw hook returns\n`AnyView(nullptr).CopyToTVMFFIAny()` and a typed helper returns\n`std::nullopt` directly, so the macro added a name and nothing else.\n`TVM_FFI_S_VISIT_MAYBE_EARLY_RETURN` stays; it is the one that needs the\nhelper.\n\nTwo uses in `structural_visit.cc` and the doc example updated. No\nbehaviour change."
    },
    {
      "commit": "e74e58f9d8a6fb1ece5722d0715f68187a8e0385",
      "tree": "0e8d93d495c78da3b3815eb30603f56d45b88976",
      "parents": [
        "286c65bbde9e62d7d1d94a5289a3b7a8d0176fee"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Mon Sep 07 17:24:05 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 07 17:24:05 2026 -0400"
      },
      "message": "[FFI][PERF] Force-inline ObjectPtr wrapper special members (#761)\n\nForce-inline all five special members of the single-payload wrappers\nthat transitively own `ObjectPtr` storage.\n\nThis keeps moved-from destructor cleanup within hot callers even after\nthe compiler exhausts its ordinary inlining budget, while explicitly\nretaining noexcept move construction and assignment."
    },
    {
      "commit": "286c65bbde9e62d7d1d94a5289a3b7a8d0176fee",
      "tree": "0035c6bebc3d60c5e534a9e78ab6d4f38e77514d",
      "parents": [
        "0909bb4bdefa07b885b3750ea08a3b099c3c4674"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Mon Sep 07 17:13:07 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 07 17:13:07 2026 -0400"
      },
      "message": "[FFI][PERF] Strip cv in IsObjectInstance so as\u003cObject\u003e() folds to true (#760)\n\n`AnyView::as\u003cObject\u003e()` is `as\u003cconst T*\u003e()`, so it instantiates\n`IsObjectInstance\u003cconst Object\u003e` and the `std::is_same_v\u003cTargetType,\nObject\u003e` short-circuit misses on the `const`. Every derived object then\nfalls through to a `TVMFFIGetTypeInfo` call and an ancestor walk to\nanswer a question that is always yes.\n\nOne line: strip cv on the check. Zero runtime cost; `as\u003cObject\u003e()` on a\nderived type now compiles to a plain pointer read with no call."
    },
    {
      "commit": "0909bb4bdefa07b885b3750ea08a3b099c3c4674",
      "tree": "3966aea7421cdcd52a251ea1ddac6548861e5cef",
      "parents": [
        "897ece64d6ad0857f803e68221375021867e81a5"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Sun Sep 06 22:45:36 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 06 22:45:36 2026 -0400"
      },
      "message": "[FFI][PERF] Mark non-trivial special members TVM_FFI_INLINE (#759)\n\nSometimes clang forgets to inline some constructors, which prevents\nuseful optimization."
    },
    {
      "commit": "897ece64d6ad0857f803e68221375021867e81a5",
      "tree": "c5f866a109e751e702ba4ea5021b31abda117810",
      "parents": [
        "85e72e7853e2fec081f427aa42c10e262ead1145"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Sun Sep 06 14:38:26 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 06 14:38:26 2026 -0400"
      },
      "message": "[PERF][EXTRA] Split lazy structural mutation loops (#756)\n\nThe ordinary sequence and map structural mutation paths currently keep\ntheir lazy-output null check inside the per-element loop, even after the\nfirst changed child has allocated the output. Split each path into an\nunchanged-prefix scan and a post-allocation suffix loop so the suffix\ndoes strictly less bookkeeping.\n\nThe no-change return, prefix copy, stable map iterator alignment,\ncopy-on-write behavior, and error propagation remain unchanged. A\nfocused regression covers retained arrays and maps with unchanged and\nchanged suffix elements, plus an error after allocation."
    },
    {
      "commit": "85e72e7853e2fec081f427aa42c10e262ead1145",
      "tree": "169c4960f0204ff2a21e7e000a1e1d8c2848c69b",
      "parents": [
        "9d784c4da74ff7360d76c79a89fe60a63516f880"
      ],
      "author": {
        "name": "Linzhang Li",
        "email": "yuchuan.7streams@gmail.com",
        "time": "Sun Sep 06 12:03:44 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 06 12:03:44 2026 -0400"
      },
      "message": "[STUBGEN][RUST] Skip crate-provided types and add a custom constructor example (#755)\n\n## Summary\n\n`prefix: ffi` could generate a non-generic `Array` that shadowed the\ncrate\u0027s\n`Array\u003cT\u003e`, causing E0107. Prefix expansion and `--init` now use\n`Generator.is_builtin` to skip runtime-provided types. Rust shares\n`_provider`\u0027s\ntype-key rule; Python continues to use `BUILTIN_TYPE_KEYS`.\n\n`examples/rust_stubgen` combines the demand-driven layout from #752 with\na\nhand-written `IntPair::new(a, b)` that derives `kind` from its operands.\n`custom-new` renames the generated allocator to `from_complete_fields`,\nand\n`STUB_INIT OFF` keeps regeneration in place. Linux CI builds and runs\nthe example\nand checks for stale generated bindings.\n\n## Testing\n\n- Stubgen tests: **109 passed**, including `ffi.Array` regression\ncoverage.\n- `ruff`, `ty`, and `yamllint`: passed.\n- Example builds and runs; regeneration leaves bindings unchanged and\n`--check` passes.\n- Verified duplicate-`new` errors, restoration of deleted blocks, and\ngeneration\n  of blocks for new types.\n\n---------\n\nSigned-off-by: yuchuan \u003cyuchuan.7streams@gmail.com\u003e"
    },
    {
      "commit": "9d784c4da74ff7360d76c79a89fe60a63516f880",
      "tree": "a43ade32895282b1af2d58157b8468f7b8bc3209",
      "parents": [
        "1279f6346e97a3c68ded753ce9819635efe19418"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Sun Sep 06 10:45:09 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 06 10:45:09 2026 -0400"
      },
      "message": "[WIN] Enhance threadsafety of DbgHelp (#754)\n\n`src/ffi/backtrace_win.cc` called DbgHelp unguarded, though DbgHelp is\nsingle-threaded and requires the caller to serialize it. The process\ndied while\nformatting a backtrace for another thread\u0027s exception, so the original\nerror was\nnever printed.\n\n- One mutex around every DbgHelp call made by tvm_ffi.\n- A duplicated process handle as the session key. `GetCurrentProcess()`\nhas\nthe same value in every component, so another DbgHelp user in the\nprocess could\n  close our symbols. A fresh key also makes `SymInitialize`\u0027s failure\n  unambiguous, so its result can be checked.\n- Initialize once and keep the session, dropping the per-call\n`SymInitialize`/`SymCleanup` and with it module enumeration inside the\nlock.\n\nThere is deliberately no destructor: `SymCleanup` at static-destruction\ntime\nwould reintroduce teardown at an unpredictable point relative to DLL\nunload.\n\nA failed initialization now returns a backtrace with only the caller\u0027s\nown frame.\n`StackWalk64` resolves through the session, so without one there is no\nunwinding\nat all."
    },
    {
      "commit": "1279f6346e97a3c68ded753ce9819635efe19418",
      "tree": "c97b2fe19e02e98ccab9bfdf25fb309553cb3ea7",
      "parents": [
        "4e754f9f647e16ffe0aee860531f55d62e33138b"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Sun Sep 06 10:28:08 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 06 10:28:08 2026 -0400"
      },
      "message": "[REFACTOR][EXTRA] Add TVM_FFI_S_VISIT_RETURN_NONE for visit hook tails (#753)\n\nA visit hook ends by returning \"no interrupt\", which every hook\ncurrently spells\nout by hand:\n\n```cpp\nreturn ExpectedUnsafe::MoveToTVMFFIAny(Expected\u003cOptional\u003cVisitInterrupt\u003e\u003e(std::nullopt));\n```\n\nThat puts the `Expected` storage representation into every hook body,\nincluding\ndownstream ones outside this repository, where it would keep compiling\nif the\nrepresentation ever changed.\n\n`TVM_FFI_S_VISIT_MAYBE_EARLY_RETURN` already owns the other half of this\nABI\nboundary; the tail was the only part still written by hand. This adds\nthe\nterminal counterpart, going through the same `MaybeReturnHelper` proxy\nso it\nworks from a raw `TVMFFIAny` hook and a typed helper alike, adopts it in\nthe\ncontainer hooks, and documents the canonical hook shape once beside the\nmacro\npair."
    },
    {
      "commit": "4e754f9f647e16ffe0aee860531f55d62e33138b",
      "tree": "81f79cc5f0b26bfa999a13707369bbc7ccb9db73",
      "parents": [
        "6b1b19d9f4d9f10acc87af63c7dd0cf1ab75e9e9"
      ],
      "author": {
        "name": "Linzhang Li",
        "email": "yuchuan.7streams@gmail.com",
        "time": "Sun Sep 06 08:06:42 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 06 08:06:42 2026 -0400"
      },
      "message": "[STUBGEN] Let a file declare a namespace with a `prefix` directive (#752)\n\n## Summary\n\nA file that starts with\n\n```rust\n// tvm-ffi-stubgen(prefix): tirx\n// tvm-ffi-stubgen(skip): tirx.DispatchContext\n```\n\nowns every object registered directly under `tirx` (`tirx.transform.*`\nis another file). On each run the tool appends an empty `object/\u003ckey\u003e`\nblock for every such object that no file of the run defines yet, parents\nfirst, after the file\u0027s last block, and fills it as usual; an\n`import-section` is added after the `prefix` line when the file has\nnone. `skip` leaves one object out, and a skipped object counts as not\nasked for, so the dependency error from #748 names it if something else\nneeds it. Code outside the blocks is untouched, so a one-line skeleton\nis a valid starting point. Rust target only: a Python `object/` block\nneeds a class around it.\n\nThe roll-out happens in memory before stage 3, so the new blocks join\n`declared` and `--check` (#746) reports a file with pending blocks as\nstale. It runs after `--init`, which rewrites files on disk; `--init`\nhonours `skip` as well. Builtin `ffi.*` keys are never rolled out. Two\n`prefix` lines in one file, or one prefix declared by two files, fail\nthe run (exit 2); an unknown prefix is only a warning.\n\n## Changes\n\n- `stub/cli.py`: `_roll_out_prefixes` and `_new_blocks`, called once\nafter `--init`, returning a failure count; `_stage_2` subtracts the\nrun\u0027s `skip` keys.\n- `stub/consts.py`: `prefix` and `skip` join the pipeline directive\nkinds.\n- `docs/packaging/stubgen.rst`: the directive in the reference.\n- `tests/python/test_stubgen_rust.py`: the `testing` namespace rolled\nout around an existing block, a skip, and a hand-written tail (`--check`\n1, in place 0, `--check` 0); the same skeleton under `--init` (blocks\nwritten, skip honoured, `--check` 0); a prefix declared twice; exact\nmatching, insertion order, and the builtin exclusion with a stubbed\nregistry.\n\n## Testing\n\n`test_stubgen_rust.py` + `test_stubgen.py`: 109 passed; pre-commit lint\nclean. Against `libtvm_compiler.so`, a `tirx.rs` with the two lines\nabove, one more `skip`, and thirteen `ty-map` lines for the `ir` types\nrolls out 63 blocks in one run, leaves no `super::` reference, keeps the\ntrailing `mod tail {}`, and passes `--check` on the next run.\n\n---------\n\nSigned-off-by: yuchuan \u003cyuchuan.7streams@gmail.com\u003e"
    },
    {
      "commit": "6b1b19d9f4d9f10acc87af63c7dd0cf1ab75e9e9",
      "tree": "f5ff4ef3440a63d47ac38e3cf97519804a33bce2",
      "parents": [
        "e3831a0378819136c7e71ac233e5ca3a5f5f6b46"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Sun Sep 06 08:06:19 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 06 08:06:19 2026 -0400"
      },
      "message": "[REFACTOR][EXTRA] Add StructuralMutate, a callback-driven mutation primitive (#751)\n\nStructural mutation needs a callback-owned form where a matched callback\ndecides whether and how to recurse, and its replacement remains final.\n\nThis adds StructuralMutate and StructuralMutateExpected with\ndeclaration-ordered typed and runtime dispatch. Both engines preserve\ndistinct ordinary and maybe-in-place fallbacks, use the exact\nParent::MutatorObjType callback view, and let matched variable callbacks\nown remap consistency.\n\nMap and mutate entry points now take the root as Any by value, so\nin-place reuse requires explicit ownership transfer with std::move or\nPython _move(). Existing StructuralMap callers therefore lose\nopportunistic in-place reuse until they move an owned root.\nStructuralMutate callbacks may optionally take allow_inplace as a third\nargument; two-argument callbacks retain the copy-on-write default.\n\nObject metadata can now promise that subclasses retain one structural\nequality/hash kind. Registration rejects violations, and mutation skips\nruntime remap metadata lookup for final or kind-fixed non-remappable\ncallback types.\n\nThe runtime and Python interfaces expose callback dispatch and\ndefault_mutate but intentionally omit a direct Python maybe-in-place\nmutator method. Shared-subvalue, moved-root identity, nested-hook\nownership, callback-path, and paired visit/mutate recursion tests keep\nthe interfaces aligned.\n\nValidation: all 493 C++ tests and all 2,495 Python tests pass; the\ngenerated FFI stub and full pre-commit suite, including ty,\nclang-format, and CMake lint/format, are clean."
    },
    {
      "commit": "e3831a0378819136c7e71ac233e5ca3a5f5f6b46",
      "tree": "f5f00b346a4438046c52a518c0c4521ecd59bc50",
      "parents": [
        "214ea3c4e25c685ff7e05d4a7997ca9f5a4d89ac"
      ],
      "author": {
        "name": "Linzhang Li",
        "email": "yuchuan.7streams@gmail.com",
        "time": "Sat Sep 05 21:18:30 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 05 21:18:30 2026 -0400"
      },
      "message": "[STUBGEN][RUST] Error on dependencies a partial run does not ask for (#748)\n\n[STUBGEN][RUST] Error on dependencies a partial stubgen\n\n## Summary\n\nA binding refers to other type keys: its parent (`base`), its ancestors\n(upcasts), and its field types. The generator spelled every non-`ffi.*`\nkey by module path (`super::ir::ExprObj`) whether or not anything\nprovided it, so a partial run silently referenced modules that did not\nexist. Now a referenced key must come from the crate (`ffi.*`), a\n`ty-map` in the file (hand-written), or an `object/\u003ckey\u003e` block in any\nfile of the run; otherwise the object fails with every missing key\nlisted:\n\n```text\n`tirx.Add` (line 3) depends on `ir.Expr`, `ir.Span`, `ir.Type`, which this run does not ask for:\nadd an `object/\u003ckey\u003e` block or a `ty-map` directive for each\n```\n\n`ty-map` now covers the parent too: with `ir.Expr -\u003e crate::ir::Expr`\nthe child embeds `crate::ir::ExprObj` as `base`, derefs and upcasts to\nit, and its allocator calls `ExprObj::new(...)` with the parent\u0027s\nfields, which is the contract a hand-written parent must honour. Before,\nonly field types were mapped and `base` still pointed at\n`super::ir::ExprObj`. Dependencies are not closed over automatically, as\ndiscussed: the error is the to-do list.\n\n## Changes\n\n- `rust_generator/codegen.py`: `_generated()` becomes `_provider()`\n(crate / mapped / generated / missing) and the base slot, upcasts,\nallocator recursion, classification, and field resolution branch on it;\n`generate_rust_object` takes `declared` and raises once per object.\n- `stub/cli.py`: computes `declared` (every `object/` key of the run)\nbefore stage 3 and passes it through `_stage_3`; `generate_object_block`\ngains the parameter in the protocol and both backends (Python ignores\nit).\n- `examples/rust_stubgen/README.md`: \"Partial generation\" section.\n- `tests/python/test_stubgen_rust.py`: missing keys reported together, a\nkey declared in another file resolves, a `ty-map`\u0027d parent redirects\nbase / `Deref` / upcast, the registry case through `_stage_3`.\n\n## Testing\n\n`test_stubgen_rust.py` + `test_stubgen.py`: 105 passed; pre-commit lint\nclean. Against `libtvm_compiler.so`, a skeleton with only\n`object/tirx.Add` fails with the message above (exit 2); with three\n`ty-map` lines it generates `base: ExprObj` from `crate::ir`.\n\nSigned-off-by: yuchuan \u003cyuchuan.7streams@gmail.com\u003e"
    },
    {
      "commit": "214ea3c4e25c685ff7e05d4a7997ca9f5a4d89ac",
      "tree": "e1c98fcabb975ad21340b94c8921ebe0eeae6596",
      "parents": [
        "1cb982feab6708db86d4ae821a032d8fd27ee7a0"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Sat Sep 05 19:43:56 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 05 19:43:56 2026 -0400"
      },
      "message": "[REFACTOR][EXTRA] Add StructuralVisit, a callback-driven traversal primitive (#750)\n\n`StructuralWalk` owns descent, so callbacks cannot choose individual\nchildren or control traversal order. Context-carrying passes need a\nlower-level primitive where the callback owns the subtree.\n\nThis adds a separate public `StructuralVisitEngine\u003cParent,\nCallbacks...\u003e` with declaration-ordered typed dispatch. A matched\ncallback receives the active `Parent::VisitorObjType*`, owns descent,\nand returns the final result for that value; an unmatched value follows\nregistered or reflected default traversal from the parent layer.\n\nHigh-level changes:\n\n- add `StructuralVisitExpected` and `StructuralVisit` with exact\n`(value, visitor)` callbacks;\n- expose callback-owned visiting and default descent through the dynamic\nand Python APIs;\n- attach visit error context once at each walk/visit engine boundary,\nincluding reflected fallback;\n- support raw and typed `Expected` early-return contexts;\n- document and test pruning, interruption, errors, and composed visitor\nlayers."
    },
    {
      "commit": "1cb982feab6708db86d4ae821a032d8fd27ee7a0",
      "tree": "704c698afd3198d5f07d4b71332558021c605936",
      "parents": [
        "4205a643fa8d861d08f8aa7dc3dedbf1c7bda5f2"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Sat Sep 05 16:09:55 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 05 16:09:55 2026 -0400"
      },
      "message": "[REFACTOR][EXTRA] Allow StructuralMapMutator to carry state via Parent (#749)\n\nDownstream mutators sometimes need to carry state alongside traversal,\nscoped around the subtree they descend into. StructuralMapMutator cannot\nexpress that today: there is no base slot a caller can supply, and its\ndynamic counterpart is confined to a source file, so downstream cannot\nlayer over it either.\n\nThis change parameterizes StructuralMapEngine and StructuralMapDynEngine\non a Parent layer. The named StructuralMap and StructuralMapExpected\nentry points remain unchanged and continue to use\nStructuralMapEngineBase.\n\nA Parent declares StateTupleType and a protected StateTuple() returning\nit by value, declares paired raw and Expected descents when overriding\ntraversal, and accepts the concrete engine vtable in its constructor.\nTyped callbacks receive (value, state...) with an optional trailing\ndef-region kind. Descent uses dependent this-\u003e lookup, matching\nStructuralWalkEngine, so composed deeper-layer declarations remain\neligible; explicit Parent qualification would pin the call at that\nlayer. Shared variable remapping remains owned by\nStructuralMapEngineBase.\n\nThe dynamic engine moves into the public header with the same Parent\nprotocol. Compile-time remap classification removes the remap machinery\nonly for final, statically non-remappable object types. Positive,\nnullable, non-final, and erased cases retain the runtime metadata query\nso typed callbacks preserve dynamic-engine behavior for None, redeclared\nkinds, and missing metadata."
    },
    {
      "commit": "4205a643fa8d861d08f8aa7dc3dedbf1c7bda5f2",
      "tree": "62fbfab69d7571a4dfd481563f2fcb434ca7be51",
      "parents": [
        "62df2f579567802cef3cba0126ac2aea299169ef"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Sat Sep 05 13:51:17 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 05 13:51:17 2026 -0400"
      },
      "message": "[REFACTOR][EXTRA] Allow StructuralWalkVisitor to carry state via Parent (#747)\n\nDownstream walks sometimes need to carry state alongside traversal,\nscoped around the subtree they descend into. `StructuralWalkVisitor`\ncould not express that because its callback chain was composed before\nthe visitor existed, so callbacks could not see visitor-layer state.\n\nThis change moves callback matching into a public walk engine and adds a\n`Parent` layer protocol:\n\n- Preserve the exact Parent-free `StructuralWalkExpected\u003corder\u003e` and\n`StructuralWalk\u003corder\u003e` entry points; no additional `WithState` free\nfunction ships.\n- Expose `tvm::ffi::StructuralWalkEngine\u003cParent, order, Callbacks...\u003e`\nfor layered users and document the complete Parent protocol, including\ndependent unqualified descent lookup rather than virtual dispatch.\n- Preserve protected raw ABI descent and public expected descent; layers\noverriding expected descent provide the paired raw redirect in their own\nclass body.\n- Unpack the Parent\u0027s const state tuple positionally into every callback\nafter the value, supporting multiple and duplicate state types without\nlookup rules.\n- Allow `TVMFFIDefRegionKind` only as an optional trailing argument and\nread it lazily only when requested.\n- Cover public engine construction, state observation, raw descent,\nskip/interrupt behavior, combined state/region dispatch, and\npre/post-order placement in focused tests."
    },
    {
      "commit": "62df2f579567802cef3cba0126ac2aea299169ef",
      "tree": "9982efdcbf354d09c7c3c09be9c3cf15a0a9c330",
      "parents": [
        "556514c76225cb35a55e0649098b07be3fba2991"
      ],
      "author": {
        "name": "Linzhang Li",
        "email": "yuchuan.7streams@gmail.com",
        "time": "Sat Sep 05 12:33:30 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 05 12:33:30 2026 -0400"
      },
      "message": "[STUBGEN] Add a `--check` mode that reports stale stub files (#746)\n\n## Summary\n\n`tvm-ffi-stubgen` updates generated blocks in place, but always exited\n0, so CI could not tell whether a tree was up to date. `--check` writes\nnothing, prints `[Stale] \u003cfile\u003e` for every file whose blocks would\nchange, and exits 1 if there is any; a file that fails to process exits\n2 (in every mode; it used to exit 0). This is the CI half of the\nin-place / `--check` pair, like `ruff format --check`.\n\n`--check` is `--dry-run` plus the report: it sets `dry_run` at parse\ntime, and `_stage_3` returns the changed flag `FileInfo.update` already\ncomputes. It refuses `--init-*`, since `--init` scaffolds files on disk\nregardless of `dry_run`.\n\n## Changes\n\n- `stub/cli.py`: `--check` flag, `_stage_3` returns changed, `__main__`\nreturns `2 if failed else 1 if stale else 0`.\n- `stub/utils.py`: `Options.check`.\n- `docs/packaging/stubgen.rst`: the option and its exit codes.\n- `tests/python/test_stubgen_rust.py`: stale round trip, failure exits\n2, `--check` + `--init-*` rejected.\n\n## Testing\n\n`test_stubgen_rust.py` + `test_stubgen.py`: 102 passed; pre-commit lint\nclean.\n\nSigned-off-by: yuchuan \u003cyuchuan.7streams@gmail.com\u003e"
    },
    {
      "commit": "556514c76225cb35a55e0649098b07be3fba2991",
      "tree": "9eac7cc2ee6a462a3dec3b577663fd7e074fc3a7",
      "parents": [
        "0292ae8419c630ffdf2a6a40492598388eb27f13"
      ],
      "author": {
        "name": "Shushi Hong",
        "email": "820958424@qq.com",
        "time": "Sat Sep 05 08:33:10 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 05 08:33:10 2026 -0400"
      },
      "message": "[Test][Rust] Use existing C++ registrations for structural walk and map (#745)\n\nRust walk/map tests currently register custom types and hooks while the\ntest harness runs tests concurrently. Registering these hooks can\nrelocate the shared type-attribute columns read by other tests; #743\naddressed the visit-test race with a per-test initialization barrier.\n\nUse the existing C++ container hooks and the startup-registered\n`testing.TestObjectBase` and `testing.TestNonCopyable` types instead.\nRemove the Rust-only test objects, type/field/hook registration helpers,\nand initialization barriers from both structural test files. Treat\n`DLDataType` as a primitive leaf without registering a traversal hook.\nKeep tests in their original integration-test files, with no C++ or Rust\nimplementation changes.\n\nThis narrows the test scope to traversal through existing C++\nregistrations. Ordinary walk/map dispatch, recursion, copy-on-write,\ninterrupts, errors, and panic recovery remain covered. Reflection checks\nnow use the existing C++ objects. Remove 16 specialized tests that\ndepend on custom hook handles, DAG/FreeVar metadata, or injected\ngetter/setter failures; the rewritten tests also stop asserting special\nfield flags and exact shallow-copy callback counts. These checks are\nremoved, not relocated or claimed to be equivalently covered.\n\nValidation on Linux x86_64:\n\n- Rust workspace: 238 tests passed, including 45 visit/walk and 35\nmutate/map tests; no compiler warnings.\n- Both structural test suites passed 100 concurrent rounds, each\nexecutable using 8 test threads.\n- Neither executable imports `TVMFFITypeRegister*` or\n`TVMFFITypeGetOrAllocIndex`; both link the existing C++ testing library.\n- Rust formatting, ASF headers, file-type checks, and `git diff --check`\npassed.\n\nWindows/MSVC validation remains pending CI for this change."
    },
    {
      "commit": "0292ae8419c630ffdf2a6a40492598388eb27f13",
      "tree": "a77052b17df5bae26e27eebfd94b5c8ebbcd6ed0",
      "parents": [
        "6387967418b6db36dd19292f720989108f36281d"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Fri Sep 04 22:03:02 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Sep 04 22:03:02 2026 -0400"
      },
      "message": "[REFACTOR][EXTRA] Move structural-mutate error construction out of the hot path (#744)\n\n`TryLink` inlines into the per-node dispatch function, so two error\nconstructions that only the matched path can reach put their string and\n`Error` construction into a stack frame every node pays for.\n\nThis follows `BadStructuralMutateHookError`, which is already\n`TVM_FFI_COLD_CODE static` for exactly this reason — its doc comment\nsays *\"Inlined, its three string literals and Error construction land in\nthe traversal\u0027s hot path for no reason.\"* These were the two sites it\nmissed.\n\nNo semantic change: both checks still fire identically, only the\nlocation of their error construction moves.\n\n\nPer-node dispatch function: stack frame 216 → 120 bytes, 358 → 318\ninstructions. Both helpers land in `.text.unlikely.*`."
    },
    {
      "commit": "6387967418b6db36dd19292f720989108f36281d",
      "tree": "7e8641109585338b9c2016ff7573f642104c23a2",
      "parents": [
        "a35b3eab56e577dd5414f8a53b941111cd3cc08e"
      ],
      "author": {
        "name": "Shushi Hong",
        "email": "820958424@qq.com",
        "time": "Fri Sep 04 21:54:41 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Sep 04 21:54:41 2026 -0400"
      },
      "message": "[FIX][RUST] Wait for fixture registration in structural visit tests (#743)\n\nComplete the registration synchronization from #710 by making every\nstructural-visit test wait for fixture initialization before reading\nreflection data. This prevents hook-column relocation from racing with\nbuilt-in Array and Map traversal.\n\nAlso check that the panicking callback was entered and distinguish an\nerror return from normal completion."
    },
    {
      "commit": "a35b3eab56e577dd5414f8a53b941111cd3cc08e",
      "tree": "87c9f3f38550a5af99f6bae4337dae76383a6239",
      "parents": [
        "42d4be739fc452651b808f3cc6f2c87c17847b27"
      ],
      "author": {
        "name": "Linzhang Li",
        "email": "yuchuan.7streams@gmail.com",
        "time": "Fri Sep 04 21:54:17 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Sep 04 21:54:17 2026 -0400"
      },
      "message": "[STUBGEN][RUST] Rename the wrapper slot to `base` and tighten `rust_ident` (#742)\n\n## Summary\n\nFor every reflected object the Rust target emits two structs: `XObj`,\nthe `#[repr(C)]` mirror whose first field `base` holds the parent, and\n`X`, the reference wrapper that owns an `ObjectArc\u003cXObj\u003e`. That wrapper\nfield was named `data`, which made `base` and `data` the two names a\nreflected field could not use; `rust_ident` spelled such fields `base_`\n/ `data_`, and TVM has both (`tirx.Ramp.base`, `tirx.DeclBuffer.data`).\nThis PR names the wrapper field `base` too, so `base` is the only\nreserved name and a reflected `data` stays `data`. `derive(ObjectRef)`\nnow takes the slot name from the struct\u0027s first field instead of\nrequiring `data`, so the crate\u0027s own wrappers and the generated ones\nboth derive. `rust_ident` also becomes exact: it unwraps a single\ntrailing underscore (`imports_` -\u003e `imports`) and a dunder name\n(`__dict__` -\u003e `dict`) and leaves every other spelling alone, instead of\nstripping all trailing underscores.\n\n## Changes\n\n- `rust/tvm-ffi-macros/src/object_macros.rs`: `derive_object_ref` reads\nthe first field\u0027s identifier and emits it in `data` / `into_data` /\n`from_data` and the `Any` conversions, instead of hard-coding `data`.\n- `rust_generator/codegen.py`: the wrapper struct, its `Deref`, and the\nallocator body use `base`.\n- `rust_generator/consts.py`: `RUST_RESERVED_MEMBERS \u003d {\"base\"}`.\n- `rust_generator/utils.py`: `rust_ident` maps `name_` and `__name__` to\n`name`; `__name`, `_name`, `name__`, `_` stay verbatim.\n- `examples/rust_stubgen/`: regenerated `mod.rs`; `test_rust_ident` and\nthe goldens updated.\n\n## Testing\n\n`test_stubgen_rust.py`, `test_stubgen.py`, `test_stub_layout.py`: 121\npassed; ruff clean. `cargo test` in `rust/` passes with the macro\nchange. The example regenerates an identical `mod.rs` and `cargo run`\nprints `a\u003d1 b\u003d2 kind\u003dPairKind(1)` and `sum\u003d3`.\n\nSigned-off-by: yuchuan \u003cyuchuan.7streams@gmail.com\u003e"
    },
    {
      "commit": "42d4be739fc452651b808f3cc6f2c87c17847b27",
      "tree": "4be9930331ad45db390ce9b1709ba3d6a96da044",
      "parents": [
        "24cfa44ca425ece2f2547ae87b81fea2835ddebd"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Fri Sep 04 20:48:27 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Sep 04 20:48:27 2026 -0400"
      },
      "message": "[REFACTOR][EXTRA] Optimize StructuralMap engine (#741)\n\nThis PR improves the `StructuralMap` engine by bringing lambda callback\nstyle to direct calling style. We also internally used the raw\n`TVMFFIAny` ABI path so engine overhead is minimized in the default\npath.\n\nMain changes:\n\n- **Direct calling style.** The callback chain was continuation-passing,\na lambda nested per link. The mutator now owns its callbacks and tests\nthem with a `(... || ...)` fold; selection, identity remap, descent, and\ninvocation are one straight-line function.\n- **Raw `TVMFFIAny` on the ABI boundary.** Hooks are C-ABI function\npointers returning `TVMFFIAny`, a 16-byte POD that passes in registers,\nwhile `Expected\u003cAny\u003e` is classified MEMORY and forces the result to the\nstack. Descent through an unmatched node is that boundary, so it now\nstays raw end to end. Hook bodies are unchanged:\n`TVM_FFI_S_MUTATE_ASSIGN_OR_RETURN` still takes a typed `Expected\u003cAny\u003e`\nand moves out only on return.\n- **Split static and dynamic selection.** `StructuralMapMutatorObj`\n(header) and `StructuralMapDynMutatorObj` (`.cc`) now share only the\nidentity remap. This also removes a hazard: the dynamic form kept its\nselected `Function` in mutable state, where a post-order walk could\ndescend into a matching child and overwrite the parent\u0027s selection.\n- **Error context is attached by the engine, not by hooks.** The engine\nnames a node where it dispatches into that node, giving one frame per\nnode instead of two on some paths. Both `MAYBE_EARLY_RETURN` macros lose\ntheir node argument, and the visit engine no longer routes its own walk\nthrough the hook-facing macro.\n- **API.** Removes `TVM_FFI_S_MUTATE_ASSIGN_FROM`,\n`SMutateResultUnchanged`, `AssignOrReturnHelper`, and\n`MutateWithIdentityRemapExpected`. Adds\n`TVM_FFI_UNSAFE_S_MUTATE_ASSIGN_OR_RETURN_SKIP_CHECK` for hooks that\nhave measured the type check to matter; it is UB on a wrong-typed result\nand has no call sites here. Also fixes `AnyUnsafe::CheckAnyStrict`,\nwhich was missing the `Any` special case both of its siblings had.\n- **Behavior change.** When descent hands back a node whose type no\nlonger matches the link that selected it, the engine reports a\n`TypeError` instead of passing the node through. Default mutation must\npreserve a node\u0027s type, so this only fires when a hook has broken that\ninvariant. Match-before-descent ordering, identity-remap entry and exit,\nand the pre-order in-place rules are unchanged."
    },
    {
      "commit": "24cfa44ca425ece2f2547ae87b81fea2835ddebd",
      "tree": "255bad4c41767a4c01403d3ca98cdac55518a676",
      "parents": [
        "35f4f3a0143e51b2ff8a55a885100fd28020c1ce"
      ],
      "author": {
        "name": "Linzhang Li",
        "email": "yuchuan.7streams@gmail.com",
        "time": "Fri Sep 04 17:58:14 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Sep 04 17:58:14 2026 -0400"
      },
      "message": "[STUBGEN][RUST] Generate complete object mirrors and allocators (#740)\n\n## Summary\n\nAttach the layout classifier (#730) to the Rust backend. A type whose\nlayout the registry proves is now bound *complete*: a `#[repr(C)]`\nstruct with every physical field at its reflected offset and width, a\n`const` size/alignment assertion, and a lossless allocator\n(`\u003cLeaf\u003eObj::new` crate-private, `\u003cLeaf\u003e::new` public). Everything else\nkeeps the opaque form of #738. Three new directives: `opaque` vetoes a\nreproducible layout, `upcast` adds a hand-written typed view,\n`custom-new` renames the generated allocator to `from_complete_fields`\nso a hand-written `new` can own the name.\n\n## Motivation\n\nThis is what tvm-rust-ext\u0027s `STUBGEN_FEEDBACK.md` asks for: ordinary\ndata nodes allocated in Rust from their complete fields, polymorphic and\nunreflected-byte types kept opaque. Generating `ir.` / `tirx.` /\n`arith.` / `target.` from tvm-rust-ext\u0027s `libtvm_compiler.so` gives 131\ntypes (98 complete, 33 opaque) that compile against the crate without\nedits; the differences from the hand-written bindings are exactly what\nthe directives cover.\n\n## Changes\n\n- `stub/layout.py`: `classify(..., unmirrored\u003d...)` and the `no-mirror`\nreason, so types under a builtin parent (`ffi.Enum`, ...) stay opaque:\ntheir base is only a header-only stand-in.\n- `rust_generator/codegen.py`: classify each object with its ancestors;\nmirror fields (scalars by reflected width, `Optional\u003cT\u003e` as `Option\u003cT\u003e`\nor `tvm_ffi::Optional\u003cT\u003e` by payload, directive widths checked against\nthe field size); render the complete struct and its allocators; `upcast`\nand `custom-new` handling.\n- `rust_generator/directives.py`, `consts.py`: the three directives and\nthe width tables.\n- `rust_generator/utils.py`: a reflected field named `base` or `data` is\nspelled `base_` / `data_`, since those are the generated struct\u0027s own\nmembers (TVM has `tirx.Ramp.base`, `tirx.DeclBuffer.data`).\n- `examples/rust_stubgen/`: `IntPair` is now a plain data object,\nallocated from Rust with the generated `IntPair::new` and read back by\nC++.\n\n## Testing\n\n`test_stubgen_rust.py` (36 cases), `test_stubgen.py`,\n`test_stub_layout.py`: 121 passed; ruff clean. The example regenerates\nan identical `mod.rs` and `cargo run` prints `a\u003d1 b\u003d2 kind\u003dPairKind(1)`\nand `sum\u003d3`.\n\n---------\n\nSigned-off-by: yuchuan \u003cyuchuan.7streams@gmail.com\u003e"
    },
    {
      "commit": "35f4f3a0143e51b2ff8a55a885100fd28020c1ce",
      "tree": "cb3acf36d668db1f869af63f9f9b989b8eba45c2",
      "parents": [
        "94133a5976008c155028ae06f10cba57dc4bd6de"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Fri Sep 04 14:37:07 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Sep 04 14:37:07 2026 -0400"
      },
      "message": "[REFACTOR][EXTRA] Streamline container mutation hooks (#739)\n\nMove structural container mutation onto the same exception-free contract\nas structural visiting: child failures remain explicit `Expected`\nvalues, while allocation and invariant failures stay fatal.\n\n- share prefix range initialization between Array and List\n- avoid throwing dispatch casts and repeated bounds checks after\ninvariants are established\n- cover raised and returned callback errors across Array, List, Map, and\nDict"
    },
    {
      "commit": "94133a5976008c155028ae06f10cba57dc4bd6de",
      "tree": "fa738b78c2f30beaff157630d0304ff9b0f09617",
      "parents": [
        "eed79b047b56afaccad87a5d29b2ead2f5aad188"
      ],
      "author": {
        "name": "Linzhang Li",
        "email": "yuchuan.7streams@gmail.com",
        "time": "Fri Sep 04 01:01:26 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Sep 04 01:01:26 2026 -0400"
      },
      "message": "[STUBGEN][RUST] Add the Rust backend with opaque object bindings (#738)\n\n## Summary\n\nRegister `--target rust` in `tvm-ffi-stubgen`. Every reflected object\nbecomes an *opaque* Rust binding: a `#[repr(C)]` struct that embeds only\nits parent, a reference wrapper, read-only `Deref`,\n`impl_object_upcast!` along the ancestor chain, and one accessor per\nreflected field that reads through the C ABI getter (`FieldGetter`). The\nobject\u0027s bytes are never reproduced, so the binding is correct for every\nregistered type. Three directives (`field`, `nullable`, `enum`) shape\nthe accessor types. A CMake `STUB_TARGET` option and an example project\nwith its generated module checked in round it out.\n\nRebased on `main` after #736; depends on nothing else.\n\n## Motivation\n\nThis is the first Rust step of the series that replaces #609 (after the\nlayout classifier in #730 and the directive channel in #736). Starting\nwith the opaque form keeps \"never generate a wrong layout\" true from the\nfirst Rust PR. The follow-ups attach the classifier and upgrade the\ntypes whose layout the registry can prove to full field mirrors, then\nadd allocators.\n\nThe opaque form is not a stopgap. Polymorphic types, types with\nunreflected bytes, and types the registry has no layout for stay opaque\nforever, and reading their fields through the reflected getter is the\nonly correct option. It is exactly what tvm-rust-ext hand-writes today\nfor `IterVar`, `Axis`, `TileLayout`, `BufferRegion`, `SourceName`, and\n`Source`; this PR generates that shape from directives alone.\n\n## Changes\n\n- `python/tvm_ffi/stub/rust_generator/` (new)\n- `consts.py`: FFI-origin to Rust-type map, `ffi.*` to crate-root\nrewrite, declared directive names, keyword table.\n- `utils.py`: `RustUse` / `RustImports` (per-file `use` collector plus\ndirectives), `render_rust_type` (returns `None` where the crate has no\nmirror), `rust_ident`.\n- `directives.py`: grammar of `field: K.f -\u003e T`, `nullable: K.f`, `enum:\nK.f -\u003e Name(i32) { A\u003d0, ... }`; malformed payloads are rejected with the\nline number.\n- `codegen.py`: `_ObjectRenderer` (module-tree name resolution,\naccessors, the `#[repr(transparent)]` enum newtype with `TryFrom\u003ci64\u003e`,\n`Deref`, upcasts), plus the import section, `--init` scaffold and `pub\nmod` stitching carried over from #609.\n- `generator.py`: the `Generator` protocol adapter, declaring\n`{import-object, field, nullable, enum}`.\n- `stub/generator.py`: registers `\"rust\"`.\n- `cmake/Utils/Library.cmake`: `STUB_TARGET`, passed as `--target`.\n- `examples/rust_stubgen/`: a polymorphic C++ object with two registered\nglobal functions, a Rust program that constructs it through the FFI and\nreads it through the generated accessors, and the generated `mod.rs`\nwith an `enum` directive.\n\nDecisions worth a look:\n\n- A field without a Rust mirror (`Union`, `Dict`, `List`, `tuple`,\n`void*`, an unmapped bare origin) gets an accessor returning `Any`.\nNothing is skipped; there is no `UnsupportedTypeError`.\n- A builtin `ffi.*` parent has no generated `\u003cLeaf\u003eObj`, so such a type\nembeds the object header and upcasts only to generated ancestors.\n- A `use` whose leaf is already taken is spelled in full at the use site\ninstead of failing.\n- No allocator is generated: construction goes through the registered\nglobal functions, as in the example.\n\nNot carried over from #609: the builder, `DerefMut`, `same_as` /\n`downcast`, method generation, the offset warnings, and every Rust\nruntime change.\n\n## Testing\n\n`tests/python/test_stubgen_rust.py` (31 cases): `use` modelling and\ncollisions; value-type rendering including origins without a mirror; the\nthree directive grammars and their rejections; goldens for a root object\n(header base, `Any` fallback, `r#type`), same-module and cross-module\nderived objects, a builtin-parent object, and the hand-written `IterVar`\nof tvm-rust-ext reproduced from directives; import section, `--init`\nscaffold and module-tree stitching; `_stage_3` over a registered type\nwith an `enum` directive; the CLI in `--init` mode over the `testing.`\nprefix, run twice to confirm idempotence. Full Python suite passes on\nthe rebased branch.\n\nThe example builds end to end: `cmake --build` regenerates\n`rust/src/generated/rust_stubgen/mod.rs`, and `cargo run` prints `a\u003d1\nb\u003d2 kind\u003dPairKind(1)` and `sum\u003d3` against the C++ library.\n\n---------\n\nSigned-off-by: yuchuan \u003cyuchuan.7streams@gmail.com\u003e"
    },
    {
      "commit": "eed79b047b56afaccad87a5d29b2ead2f5aad188",
      "tree": "8815f46364e5c293218460a628a2f5724c660cdf",
      "parents": [
        "c7a8cead2523c8a26bdd99f3a2aa8db7ca98919e"
      ],
      "author": {
        "name": "Linzhang Li",
        "email": "yuchuan.7streams@gmail.com",
        "time": "Thu Sep 03 19:50:43 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 03 19:50:43 2026 -0400"
      },
      "message": "[STUBGEN] Classify native layouts from reflected byte facts (#730)\n\n# [STUBGEN] Classify native layouts from reflected byte facts\n\n## Summary\n\nAdd a language-neutral classifier that decides, for every registered\nobject type, whether its native layout can be reproduced from reflection\n(`complete`) or not (`opaque`), with the byte evidence behind each\nverdict. `tvm-ffi-stubgen --coverage-out \u003cjson\u003e` writes the verdicts as\na report. No generator is attached.\n\n## Motivation\n\nA native-struct backend can hold an object by value only when it can\nreproduce the C++ layout byte for byte. The registry already publishes\nwhat that needs: each type\u0027s own `sizeof` (#720) and every field\u0027s size,\nalignment and offset. A wrong `complete` is a struct with the wrong\nlayout, a wrong `opaque` only costs a C ABI call per field, so the\nclassifier deserves a review of its own before any generator builds on\nit.\n\n## Changes\n\n- `stub/layout.py` (new). One criterion: the reflected fields must fill\n`[parent.total_size, total_size)` exactly, allowing only the gaps\nalignment forces. Two prerequisites: the type has metadata of its own\n(`layout-unknown`) and its parent is complete (`parent-opaque`).\nUnexplained bytes are `uncovered-bytes`; a field starting before the\ncursor is `field-overlap`. Polymorphism is not a rule: a vptr makes the\nfields fall short of `sizeof` on its own. Two target-language rules are\ninjection points: `field_renderable` and `forced_opaque`, the latter\nonly demoting a type that would otherwise be complete.\n- `stub/cli.py`, `stub/utils.py`: `--coverage-out \u003cjson\u003e`, usable\nwithout PATH arguments. The report fixes the language-neutral keys; a\ngenerator adds its own under a per-type `\"target\"` key.\n- `testing.cc`: `TestCxxClassHiddenField` (an unreflected member) and\n`TestCxxClassPolymorphic` (a vptr), so both failure paths run in CI.\n\n## Testing\n\n`tests/python/test_stub_layout.py`: every verdict path on synthetic byte\nfacts, then the real registry. The `TestCxxClass*` chain is complete\nwith padding `[36, 40)`, `[52, 56)`, `[73, 80)`;\n`TestCxxClassHiddenField` reports `[32, 40)` uncovered;\n`TestCxxClassPolymorphic` reports `sizeof` 40 against fields ending at\n32; `ffi.Function` is `layout-unknown`; `ffi.Module` is opaque like the\npolymorphic fixture. The CLI writes the report with `--coverage-out`\nalone.\n\n---------\n\nSigned-off-by: yuchuan \u003cyuchuan.7streams@gmail.com\u003e"
    },
    {
      "commit": "c7a8cead2523c8a26bdd99f3a2aa8db7ca98919e",
      "tree": "910c4a46ec11014d3e59c7a0d78df5bd646257e3",
      "parents": [
        "ef5ce4e0c1700e028545d49a010b1689ed808234"
      ],
      "author": {
        "name": "Shushi Hong",
        "email": "820958424@qq.com",
        "time": "Thu Sep 03 16:16:14 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 03 16:16:14 2026 -0400"
      },
      "message": "[RUST] Add borrowed object node cast (#734)\n\nThis PR adds ObjectRefCore::as_node\u003cN\u003e() for zero-copy borrowed\nobject-node casts.\n\nChecks such as is_zero currently clone an owning object handle before\ncalling try_cast. This performs an atomic reference-count increment and\ndecrement even though the caller only needs to inspect the node\ntemporarily.\n\nThe new API checks the runtime type directly from the existing object\nheader and returns a reference tied to the source handle. It does not\nclone the handle, construct an owning cast result, or update the\nreference count. Final node types, such as IntImmObj, use a fast exact\ntype-index comparison."
    },
    {
      "commit": "ef5ce4e0c1700e028545d49a010b1689ed808234",
      "tree": "46eb7e9c32d78c93363cf36c34129870b8791a92",
      "parents": [
        "bdd4989f9c9ad4a5e8fd61db01c185577570dc51"
      ],
      "author": {
        "name": "Linzhang Li",
        "email": "yuchuan.7streams@gmail.com",
        "time": "Thu Sep 03 14:39:02 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 03 14:39:02 2026 -0400"
      },
      "message": "[STUBGEN] Generalize one-line directive handling (#736)\n\n## Summary\n\nGeneralize parsing and dispatch for standalone one-line\n`tvm-ffi-stubgen`\ndirectives. Pipeline-owned and generator-owned directives now share one\n`CodeBlock` representation, while each layer remains responsible for its\nown\npayload grammar. This lets a target generator add directives without\nextending\nthe language-neutral file parser.\n\n## Changes\n\n- Add `MarkerSyntax.directive(name)` for constructing standalone\ndirective\n  markers with either Python or Rust comment syntax.\n- Parse standalone directives uniformly as\n`CodeBlock(kind\u003d\"directive\", param\u003d(name, payload))` and preserve their\nsource\n  lines when rewriting files.\n- Add `PIPELINE_DIRECTIVE_KINDS` for directives consumed by the common\npipeline.\n`ty-map` remains pipeline-owned and is processed before init-mode\ngeneration.\n- Add `Generator.directive_kinds` and `Generator.add_directive` so each\ntarget\ndeclares and handles its own directive names. Undeclared names fail with\ntheir\n  source line number.\n- Route the existing Python `import-object` support through\n`add_directive`, and\nmove its semicolon-delimited payload parsing from the common parser into\nthe\n  Python generator.\n\n## Compatibility\n\nThe undocumented `tvm-ffi-stubgen(begin): ty-map/...` block form is no\nlonger\naccepted; `ty-map` is a standalone one-line directive. Out-of-tree\n`Generator`\nimplementations must provide `directive_kinds` and `add_directive`;\n`add_imported_object` is no longer called by the pipeline.\n\n## Tests\n\n- `uv run pytest -q tests/python/test_stubgen.py` (43 passed)\n- `uv run ruff check` on all changed Python files\n- `git diff --check`\n\n---------\n\nSigned-off-by: yuchuan \u003cyuchuan.7streams@gmail.com\u003e"
    },
    {
      "commit": "bdd4989f9c9ad4a5e8fd61db01c185577570dc51",
      "tree": "5792babf024909a6837b8e988420d9edb038a02f",
      "parents": [
        "0cfb9a945b0a76be870bbda6d0bb41cf4cde11c7"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Thu Sep 03 04:58:17 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 03 16:58:17 2026 +0800"
      },
      "message": "[REFACTOR][EXTRA] Optimize StructuralMap (#733)\n\nThis PR refactor optimizes `StructuralMap`.\n\n- Move successful `Expected` payloads through structural-mutation hooks\nwithout redundant reference-count traffic, while returning conversion\nfailures through `Expected`/`Unexpected`.\n- Require structural visit and mutation early returns to carry node\ncontext, and document the public mutation-unwrapping macro.\n- Match callbacks before recursive descent so unmatched nodes skip\nidentity-remap lookup, error-frame setup, and callback-chain work.\n- Keep remap lookup and callback invocation inside each matched\ncontinuation, preserving callback ordering and post-order target\nrevalidation.\n- Add registered-hook and error-context coverage for successful,\nnullable, failing, and wrong-type mutation results."
    },
    {
      "commit": "0cfb9a945b0a76be870bbda6d0bb41cf4cde11c7",
      "tree": "59ca5664458dbf8069c59d7a41a4400d5ecd00a9",
      "parents": [
        "347d71fef17ad77dc9810424113a92e560b4f643"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Wed Sep 02 15:00:35 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 02 15:00:35 2026 -0400"
      },
      "message": "[FFI] Make Object::unique() require no weak references (#731)\n\n## Summary\n\n- Make `Object::unique()` require one strong reference and no external\nweak references by comparing the packed count with\n`kCombinedRefCountBothOne`.\n- Delegate `ObjectPtr\u003cT\u003e::unique()` to the object-level implementation\nwhile leaving strong-only `use_count()` semantics unchanged.\n- Add focused coverage for uniqueness while a `WeakObjectPtr` is live.\n\n## Rationale\n\n`unique()` gates copy-on-write and in-place mutation. A live weak\npointer can still upgrade while the object has a strong owner, so\nstrong-only uniqueness is insufficient for safely choosing in-place\nmutation. Comparing the combined counter also observes both halves in\none atomic load.\n\n## Compatibility\n\nOut-of-tree users that retain weak references may now copy instead of\nmutating in place. Current production call sites without weak references\nretain their existing behavior."
    },
    {
      "commit": "347d71fef17ad77dc9810424113a92e560b4f643",
      "tree": "9f9549f82faa65ab5e2389ed3902e9c386852842",
      "parents": [
        "c62b07c2b27ec09a2616eb314a0ef2acc006d55d"
      ],
      "author": {
        "name": "Alfredo Luque",
        "email": "me@aluque.io",
        "time": "Wed Sep 02 14:16:24 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 02 14:16:24 2026 -0400"
      },
      "message": "[FIX] Support free-threaded Python cross-builds (#706)\n\n## Summary\n\nThe conda-forge Python 3.14 free-threading migration is blocked for TVM\nFFI on platforms that rely on cross-compilation. Linux PPC64LE and macOS\nARM64 builds fail during CMake\u0027s Python development lookup even though\nthe target 3.14t headers are installed, while native 3.14t builds and\nGIL-enabled Python 3.14 cross-builds succeed.\n\nThis PR makes Python discovery distinguish the host interpreter used to\nrun Cython from the target development artifacts used to build the\nextension. That lets downstream packagers build Python 3.14t wheels for\nthose architectures without changing native builds or GIL-enabled\ncross-build behavior.\n\n## Background\n\nCross-compiling against Python 3.14t currently finds the host\ninterpreter and detects\n`Py_GIL_DISABLED`, but the second `FindPython` call combines that host\ninterpreter with target\n`Development.Module` artifacts. CMake 4.4 also enforces the\n`gil_disabled` ABI default of `OFF`,\nso it rejects the installed `python3.14t` target headers and reports\n`missing: Development.Module`.\n\nThe failing configurations are visible in\n\n[conda-forge/apache-tvm-ffi-feedstock#20](https://github.com/conda-forge/apache-tvm-ffi-feedstock/pull/20):\nLinux x86_64 to PPC64LE and macOS x86_64 to ARM64. Native Python 3.14t\nand cross-built GIL-enabled\nPython 3.14 already pass.\n\nThis change keeps the first interpreter for free-thread detection and\nCython, performs a\ndevelopment-only target lookup when cross-compiling, and uses\n`SKBUILD_SOABI` for the target\nextension suffix when available. Native discovery remains unchanged.\n\nFixes #705.\n\n## Testing\n\n- configured with CMake 4.4.2 against the exact PPC64LE Python 3.14t\ntarget headers; generated\n  `core.cpython-314t-powerpc64le-linux-gnu.so`\n- configured with CMake 4.4.2 against the exact macOS ARM64 Python 3.14t\ntarget headers; generated\n  `core.cpython-314t-darwin.so`\n- verified the cross path on CMake 3.26.4 and 3.30.5 with developer\nwarnings treated as errors\n- built and imported an editable native Python 3.14t package; verified\nthe extension retained its\n  `cpython-314t` suffix\n- `pytest -n0 -vvs tests/python/test_free_threaded_python_helpers.py\ntests/python/test_build.py::test_build_cpp`\n- `cmake-format --check CMakeLists.txt`\n- `cmake-lint CMakeLists.txt`\n- ASF header, file-type, and whitespace checks\n\n## AI Disclosure\n\nWas AI used in the creation of this PR?\n\n- [ ] No. This was fully written by a human.\n- [ ] Limited (uses other than code generation, such as ideation or\ndebugging, or very limited code generation)\n- [ ] Moderate (code generated by an LLM with continuous human review\nand intervention)\n- [x] High (key decisions made by a human with active steering and\nfeedback; final code reviewed by the human)\n- [ ] Vibe Coded (generated largely autonomously from an initial prompt\nwith limited human steering or review)\n\nThe human identified the failing downstream migration, set the upstream\nissue and PR scope, and\nmade the key workflow decisions. OpenAI Codex (GPT-5), including\ndelegated Codex agents,\ninvestigated the CMake behavior, implemented the change, ran the native\nand cross-build validation\nmatrix, reviewed the final diff, and prepared this PR. The human\nreviewed and approved the final\ndiff; agent review did not replace that review.\n\n---------\n\nCo-authored-by: tqchen \u003ctianqic@nvidia.com\u003e"
    },
    {
      "commit": "c62b07c2b27ec09a2616eb314a0ef2acc006d55d",
      "tree": "e732a5ac3e152ce1ffb03afeaa918653894c4dd4",
      "parents": [
        "17ea4d7ba2d4153aa991f1c581cecd2a06f17e26"
      ],
      "author": {
        "name": "Linzhang Li",
        "email": "yuchuan.7streams@gmail.com",
        "time": "Wed Sep 02 13:33:02 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 02 13:33:02 2026 -0400"
      },
      "message": "[CORE] Publish native layout traits from ObjectDef (#721)\n\nClass::_type_final never reaches the runtime. TVMFFITypeInfo exposes the\ntype index, depth, ancestors, fields and methods; TVMFFITypeMetadata\nadds the creator, total_size and the structural-eq kind. Neither carries\nnum_child_slots / child_slots_can_overflow — those are arguments to the\nregistration call and stay inside the registry. So nothing downstream\ncan ask whether a class admits subtypes, and a binding generator that\nwants to store an object by value has no way to find out.\n\nEvery ObjectDef\u003cClass\u003e now registers __ffi_type_final__ as a bool type\nattribute, reusing the existing RegisterTypeAttrValue mechanism (one\nbool Any per type, no C ABI change). ObjectInfo.is_final surfaces it to\nthe stub generator.\n\nis_final stays None for a type registered without an ObjectDef (e.g.\nffi.Object), so a registered False remains distinguishable from \"never\npublished\" — the distinction matters because a consumer must not treat\n\"not final\" and \"unknown\" alike.\n\nTesting — tests/cpp/test_reflection.cc: a non-final type, a final one,\nand ffi.Module. tests/python/test_stubgen.py: the same three cases\nthrough ObjectInfo, including the None case.\n\nSigned-off-by: yuchuan \u003cyuchuan.7streams@gmail.com\u003e"
    },
    {
      "commit": "17ea4d7ba2d4153aa991f1c581cecd2a06f17e26",
      "tree": "e4877184dd7e6fbde54f0b90d55262d38814c45f",
      "parents": [
        "b33463a2b1be9ee19a296e51f7571395960ae890"
      ],
      "author": {
        "name": "Linzhang Li",
        "email": "yuchuan.7streams@gmail.com",
        "time": "Wed Sep 02 10:32:11 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 02 10:32:11 2026 -0400"
      },
      "message": "[STUBGEN] Carry native layout facts through the language-neutral data. (#720)\n\n`NamedTypeSchema` now records the byte facts the C++ registry already\npublishes for every reflected field (size/alignment/offset, static\ndefault or factory value, structural-eq flag, frozen-ness), and\n`ObjectInfo` records the ancestor chain plus the type\u0027s own `sizeof`\n(`None` for a type without its own metadata entry, whose inherited size\nsays nothing about the type). This gives non-Python backends the\nmemory-layout inputs they need without a second reflection pass.\n\nLanguage-neutral infrastructure for such backends:\n\n- `//` marker syntax for `.rs` files (the block parser was already\nsyntax-driven);\n- directory scans visit only the active generator\u0027s `source_exts`, so\none tree can hold stub files for several languages without one target\nrewriting another\u0027s files;\n- `--target` choices follow the generator registry instead of a\nhard-coded list;\n- drop the unused `generate_helpers_block` protocol method.\n\nNo generator other than `python` is registered yet."
    },
    {
      "commit": "b33463a2b1be9ee19a296e51f7571395960ae890",
      "tree": "4e2f80bc2e89beb512493ee8c05ec79f4dc43e19",
      "parents": [
        "796979744f8ec4dc7c72238f493be7acd00f89e9"
      ],
      "author": {
        "name": "Shushi Hong",
        "email": "820958424@qq.com",
        "time": "Wed Sep 02 10:29:46 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 02 10:29:46 2026 -0400"
      },
      "message": "[REFACTOR][RUST] Keep mutate dispatch state on the dispatcher (#728)\n\nThis PR makes typed structural mutation dispatch own its pass state\ndirectly.\n\nPreviously, `#[dispatch(mutate)]` separated the dispatch object from a\n`State` stored inside `MutateCallbacks`, requiring handlers to access\nstate through `mutator.state()` or `mutator.state_mut()`.\n\nNow the state lives naturally on the dispatch object:\n\n```rust\nstruct MyMutator {\n    analyzer: Analyzer,\n    // Other pass state.\n}\n\n#[tvm_ffi::dispatch(mutate)]\nimpl MyMutator {\n    fn mutate_node(\n        \u0026mut self,\n        value: Node,\n        mutator: \u0026mut Mutator,\n    ) -\u003e Result\u003cNode\u003e {\n        let child \u003d mutator.mutate(self, \u0026value.child)?;\n        // Rewrite or reuse the node.\n    }\n}\n```\n\nThe responsibilities are now separated as follows:\n\n- The dispatch object owns pass-specific state.\n- `#[dispatch(mutate)]` selects the matching typed handler.\n- `Mutator` provides recursion, default mutation, variable remapping,\nand the current definition region.\n- Explicitly passing `self` during recursion creates a normal Rust\nmutable reborrow and avoids hidden aliasing through raw pointers.\n- Stateful closure callback chains continue to be supported through\n`CallbackMutator\u003cState\u003e` and `MutateCallbacks`.\n\nThe Rust guide and structural-mutation tests have been updated to use\nthe new API. All relevant Rust tests, including the 47\nstructural-mutation tests, pass."
    },
    {
      "commit": "796979744f8ec4dc7c72238f493be7acd00f89e9",
      "tree": "1d8775af1c0fc135f6973bfdde5ee38f99d333b7",
      "parents": [
        "b1936099423fb9199e3691e59a7c558a3cb05716"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Tue Sep 01 15:28:22 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Sep 01 15:28:22 2026 -0400"
      },
      "message": "[FEAT][FFI] Accept flexible callback return types in C++ StructuralMap (#725)\n\nAdd flexible callback-return support to C++ `StructuralMap` through two\nadditive `Expected\u003cT\u003e` conversions.\n\n- Preserve the existing `Expected(T)`, `Expected(Error)`, and\n`Expected(Unexpected\u003cE\u003e)` constructors unchanged.\n- Accept a bare `U` when `U` is implicitly convertible to `T`, using the\nC++17-compatible implicit subset of `std::expected`\u0027s value-constructor\nrules.\n- Convert `Expected\u003cU\u003e` to `Expected\u003cT\u003e`; when `T` subsumes `U`, move\nthe shared `Any data_` representation directly, and otherwise convert\nsuccess values while propagating errors.\n- Document that StructuralMap callbacks may return a replacement value,\n`Expected\u003cT\u003e`, `Error`/`Unexpected`, or throw `Error`, while retaining\nthe diagnostic for unsupported return types.\n\nStructuralWalk and the Rust bindings are unchanged."
    },
    {
      "commit": "b1936099423fb9199e3691e59a7c558a3cb05716",
      "tree": "20dd95307357f0d5d11f4cb86ee20c725c16bba5",
      "parents": [
        "f4c947e806bc0749debf3794bb397ad6635d87c6"
      ],
      "author": {
        "name": "Shushi Hong",
        "email": "820958424@qq.com",
        "time": "Tue Sep 01 08:13:31 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Sep 01 08:13:31 2026 -0400"
      },
      "message": "[Rust] Decouple structural mutation dispatch from recursion control (#723)\n\nThis PR separates typed mutation dispatch from structural-mutation\nrecursion control.\n\n`#[dispatch(mutate)]` now implements `MutateDispatch` and passes a\n`MutateContext` to each typed handler. Dispatch is responsible only for\nselecting the matching handler, while `MutateContext` provides\nrecursion, default mutation, state access, variable remapping, and the\ncurrent definition region.\n\nThis enables callbacks such as:\n\n```rust\nfn mutate_add(\n    \u0026mut self,\n    value: Add,\n    mutator: \u0026mut MutateContext\u003c\u0027_, State\u003e,\n) -\u003e Result\u003cAny\u003e {\n    let a \u003d mutator.mutate(\u0026value.a)?;\n    let b \u003d mutator.mutate(\u0026value.b)?;\n    // Build or reuse the result.\n}"
    },
    {
      "commit": "f4c947e806bc0749debf3794bb397ad6635d87c6",
      "tree": "d7534516af54620a9797a799c1daf0be4dc94aef",
      "parents": [
        "a23adc53b24092278007c23636b3156f097bee6b"
      ],
      "author": {
        "name": "Linzhang Li",
        "email": "yuchuan.7streams@gmail.com",
        "time": "Tue Sep 01 00:03:48 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Sep 01 00:03:48 2026 -0400"
      },
      "message": "[FIX][RUST] Seal structural callback result traits and update return-value docs (#724)\n\n## Summary\n\n- Seal the structural map/mutate callback-result conversion traits so\ntheir\nblanket implementations do not define an open downstream extension\npoint.\n- Update the Rust language guide to document and demonstrate callbacks\nthat\n  return `T: Into\u003cAny\u003e` or `Result\u003cT\u003e`.\n\n## Trait sealing\n\n`IntoMapResult` and `IntoMutateResult` now share a private\n`callback_result_sealed::Sealed` supertrait. `IntoMapResult` is also\nhidden from\nthe generated API documentation and explicitly documented as a\nnon-extension\npoint.\n\nThe traits remain public because `#[dispatch(map)]` and\n`#[dispatch(mutate)]`\nexpansions in downstream crates need to reference their paths. Their\nimplementations remain owned by `tvm-ffi`.\n\n## Rust guide\n\nThe structural mapping and mutation guide now describes callback return\nvalues\nas any value convertible into `Any`, either directly or wrapped in\n`Result`.\nThe examples cover both forms:\n\n- a `#[dispatch(map)]` handler returning `Result\u003ci64\u003e`;\n- callback-based mutation returning `i64` directly;\n- a `#[dispatch(mutate)]` handler returning `i64` directly.\n\nThe error-handling section now uses `Result\u003cT\u003e` and `Result\u003ci64\u003e`.\nExisting\n`Result\u003cAny\u003e` examples for packed functions and the low-level\n`StructuralMutator` interface remain unchanged because those signatures\nare\nfixed.\n\n## Testing\n\n- `cargo fmt --all -- --check`\n- `uv run cargo test --workspace`\n- `uv run cargo doc -p tvm-ffi --no-deps`\n- `uv run --group docs sphinx-build -M html docs docs/_build`\n- `git diff --check`\n\nSigned-off-by: yuchuan \u003cyuchuan.7streams@gmail.com\u003e"
    },
    {
      "commit": "a23adc53b24092278007c23636b3156f097bee6b",
      "tree": "58cda1492ecba501437893fd7b920f6ee6036358",
      "parents": [
        "5c213498a72e003657a0522f29a538f9c5a5d346"
      ],
      "author": {
        "name": "Linzhang Li",
        "email": "yuchuan.7streams@gmail.com",
        "time": "Mon Aug 31 18:31:40 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Aug 31 18:31:40 2026 -0400"
      },
      "message": "[FEAT][RUST] Accept any Into\u003cAny\u003e return value in structural map/mutate callbacks (#722)\n\nPreviously, structural_map / structural_mutate callbacks (closures,\ntuple chains, and #[dispatch(map)] / #[dispatch(mutate)] handlers) had\nto return Any or Result\u003cAny\u003e, forcing Any::from(...) wrapping at every\nreturn site.\n\nThis PR relaxes IntoMapResult / IntoMutateResult into blanket impls over\nT: Into\u003cAny\u003e:\n\nimpl\u003cT: Into\u003cAny\u003e\u003e IntoMapResult for T         { /* Ok(self.into()) */ }\nimpl\u003cT: Into\u003cAny\u003e\u003e IntoMapResult for Result\u003cT\u003e { /* self.map(Into::into)\n*/ }\n\nA callback can now return any FFI-compatible value directly (i64,\nString, Array\u003cT\u003e, …) or Result\u003cT\u003e to use ?; the conversion to Any\nhappens inside\n\n- Backward compatible: Any: Into\u003cAny\u003e holds reflexively, so existing\ncallbacks are unchanged; the two blanket impls are disjoint (Result\u003cT\u003e\n- Tests: new callbacks_return_values_convertible_into_any covers bare\ni64, Result\u003ci64\u003e, and a mutate-context callback; several existing\ncallbacks switched to explicit return types (Result\u003ci64\u003e,\nResult\u003cArray\u003ci64\u003e\u003e) to exercise the new path. visit / walk are untouched\n— their ca flow (WalkResult / VisitInterrupt), not values.\n\nSigned-off-by: yuchuan \u003cyuchuan.7streams@gmail.com\u003e"
    },
    {
      "commit": "5c213498a72e003657a0522f29a538f9c5a5d346",
      "tree": "8b111c3556a28b4eb2367587f93fef401b0db02d",
      "parents": [
        "3523725eb7b04e1c617063bd0ce77037cbf48599"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Sun Aug 30 14:28:27 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Aug 30 14:28:27 2026 -0400"
      },
      "message": "[CORE] Propagate static object type bounds in Any conversions (#719)\n\nAdd narrow static-object type-index assumptions to the non-null\n`ObjectPtr`, `ObjectRef`, and raw-object conversion paths into `AnyView`\nand `Any`.\n\nRuntime validation for unconstrained incoming `Any` and `AnyView` values\nremains unchanged.\n\nValidation: all 471 enabled CTest entries passed. The GCC 11 debug build\nrequired demoting only the pre-existing `-Werror\u003dredundant-move` warning\nin `include/tvm/ffi/container/array.h:867`."
    },
    {
      "commit": "3523725eb7b04e1c617063bd0ce77037cbf48599",
      "tree": "d3c66e80734575f75360f398129280c3264db26a",
      "parents": [
        "8682539fda858409ab4705cd4b02e726f453f8d2"
      ],
      "author": {
        "name": "Shushi Hong",
        "email": "820958424@qq.com",
        "time": "Sat Aug 29 19:45:58 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Aug 29 19:45:58 2026 -0400"
      },
      "message": "[FEAT][RUST] Add object binding runtime support (#716)\n\nThis PR adds the Rust runtime support needed by handwritten and\nstubgen-generated object bindings.\n\n### Object reference support\n\n- Adds zero-copy derived-to-base conversions through\n`impl_object_upcast!`\n- Generates `From\u003c\u0026ObjectRef\u003e` conversions for inexpensive owned-handle\ncloning\n- Adds `ObjectRefCore::same_as` for object identity comparison\n- Adds the owning and hashable `ObjectIdentity` key\n- Makes `ObjectRefCore::from_data` unsafe because typed reference views\nmay require additional invariants\n\n### Reflection access\n\n- Adds `TypeAttrColumn` and `get_type_attr` for type-attribute lookup\n- Adds `FieldGetter` for cached access to reflected object fields\n- Adds `Function::from_type_attr`\n- Reuses the public type-attribute implementation in structural visit\nand mutate\n\n### Packed-call support\n\n- Adds `RValueRef\u003cT\u003e`, compatible with C++ `ffi::RValueRef\u003cT\u003e`, for\nmove-aware object arguments\n- Avoids an unnecessary reference-count increment when the callee\nconsumes an object argument\n- Adds typed packed-call holders for `Any`, `Option\u003cT\u003e`, `Array\u003cT\u003e`,\n`DLDataType`, `DLDevice`, and unit values\n\nNo C++ implementation or C ABI changes are introduced.\n\nThe complete Rust workspace test suite passes."
    },
    {
      "commit": "8682539fda858409ab4705cd4b02e726f453f8d2",
      "tree": "71f00cc17e619fa57a30b80c440e58d3fa61b4c0",
      "parents": [
        "b29dd742ae1b7ac8fffd2ee7142b05869db04800"
      ],
      "author": {
        "name": "Shushi Hong",
        "email": "820958424@qq.com",
        "time": "Sat Aug 29 14:40:12 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Aug 29 14:40:12 2026 -0400"
      },
      "message": "[REFACTOR][RUST] Clarify structural mutator dispatch and recursion APIs (#714)\n\nThis PR clarifies the Rust structural-mutation API by separating engine\ndispatch hooks from user-controlled recursive mutation.\n\nThe engine-facing hooks are renamed to:\n\n- `mutate` → `dispatch_mutate`\n- `maybe_inplace_mutate` → `dispatch_maybe_inplace_mutate`\n\nThe user-facing recursive methods are renamed to:\n\n- `mutate_child` → `mutate`\n- `maybe_inplace_mutate_child` → `maybe_inplace_mutate`\n\nThis makes the correspondence with the C++ protocol clearer:\n\n- C++ vtable dispatch → Rust `dispatch_mutate`\n- Recursive mutation → Rust `mutate`\n- Default mutation of the current value → Rust `default_mutate`\n\nThis PR also adds `default_mutate_value`, allowing a typed\n`#[dispatch(mutate)]` handler to apply default recursion to its current\nvalue before performing a post-order rewrite.\n\nThe dispatch macro, documentation, and tests are updated accordingly.\nAll Rust workspace tests pass."
    },
    {
      "commit": "b29dd742ae1b7ac8fffd2ee7142b05869db04800",
      "tree": "74d70001e9e720c0be6d5a2fb19cf728268455ee",
      "parents": [
        "783db93284270a814b0e6cf2f013ba3012837ca4"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Sat Aug 29 11:39:59 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Aug 29 14:39:59 2026 -0400"
      },
      "message": "[FIX] Stabilize Python annotation metadata (#718)\n\n## Summary\n\n- use `typing_extensions.get_annotations` for class-local annotations\nacross Python versions\n- preserve decorated enum subclass identity under static type checking\n- keep `converter` in dataclass-transform metadata without passing an\nunsupported decorator keyword\n- raise the minimum `typing-extensions` version to the release that\nprovides `get_annotations`\n\nThis branch contains only the content of commit\n`3c6003f0809174477004ccf900108e2b893ae126`, replayed independently onto\ncurrent Apache `main`.\n\n## Testing\n\n- `uv run pytest -q\ntests/python/test_dataclass_c_class.py::test_c_class_dataclass_transform_has_converter\ntests/python/test_dataclass_py_class.py::test_py_class_dataclass_transform_has_converter`\n- changed-file pre-commit hooks"
    },
    {
      "commit": "783db93284270a814b0e6cf2f013ba3012837ca4",
      "tree": "e6d49bda1b1fba99b35857c9beb28dce40f0fde9",
      "parents": [
        "c8be16ed56d0fc25ec4261f16f440079aa3c5da7"
      ],
      "author": {
        "name": "Shushi Hong",
        "email": "820958424@qq.com",
        "time": "Sat Aug 29 14:39:07 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Aug 29 14:39:07 2026 -0400"
      },
      "message": "[FEAT][RUST] Support Any elements in FFI containers (#715)\n\nThis PR adds support for heterogeneous Rust FFI containers such as:\n\n- `Array\u003cAny\u003e`\n- `Map\u003cString, Any\u003e`\n- `Map\u003cAny, Any\u003e`\n\n`Any` cannot implement `AnyCompatible` because doing so would conflict\nwith Rust\u0027s existing identity conversion from `Any` to `Any`. This PR\ntherefore introduces a sealed internal `ContainerElement` trait.\n\nAll existing `AnyCompatible` types implement `ContainerElement`\nautomatically, while `Any` receives a dedicated implementation. Regular\ntyped containers continue to use their existing conversion behavior.\n\nThis allows Rust bindings and generated IR wrappers to represent\nheterogeneous TVM fields such as attributes and annotations using the\nstandard `Array` and `Map` types, without introducing a separate\n`AnyMap` abstraction.\n\nThe PR covers:\n\n- Container construction and iteration\n- Strict type checking and element-wise conversion\n- `Any` and `AnyView` round trips\n- Object reference-count preservation\n- Passing heterogeneous containers through typed packed calls\n\nThe complete Rust workspace test suite passes."
    },
    {
      "commit": "c8be16ed56d0fc25ec4261f16f440079aa3c5da7",
      "tree": "0b44f563809b5ed572ff721dc2ebf05af91eab50",
      "parents": [
        "32ab66ee756997208e7666841eb77b6de5e8420d"
      ],
      "author": {
        "name": "Linzhang Li",
        "email": "yuchuan.7streams@gmail.com",
        "time": "Wed Aug 26 19:33:43 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Aug 26 19:33:43 2026 -0400"
      },
      "message": "[FEAT][RUST] Add AnyCompatible::to_any. (#712)\n\n## Summary\n\nAdd `AnyCompatible::to_any(\u0026self) -\u003e Any`, the by-reference counterpart\nof `Any::from(value)`.\n\n`From\u003cAnyView\u003e for Any` now dispatches inline instead of always calling\n`TVMFFIAnyViewToOwnedAny`: an object increfs, a self-contained cell is a\nbitwise copy, and only the three borrowed forms Rust never produces\n(`kTVMFFIRawStr`, `kTVMFFIByteArrayPtr`, `kTVMFFIObjectRValueRef`) still\ngo to the runtime, behind `#[cold] #[inline(never)]`. This mirrors C++\n`details::InplaceConvertAnyViewToAny`. `is_plain_inline` moves from\n`extra::structural_common` into `any.rs`.\n\n## Motivation\n\n`Any::from` takes ownership. A value reachable only through a shared\nreference — a field behind a `Deref` into object storage, e.g. `node.a`\non a `\u0026AddObj` — cannot be moved out, so every such site has to write\n`Any::from(node.a.clone())` today.\n\n`impl From\u003c\u0026T\u003e for Any` cannot be added instead: `\u0026` is fundamental, so\na downstream crate may implement `AnyCompatible` for its own `\u0026T` and\nthe two impls overlap (E0119). A provided trait method has no such\nconflict, and every `AnyCompatible` type — including `Option\u003cT\u003e` and the\ncontainers — picks it up for free.\n\n## Usage\n\n```rust\nfn first_operand(node: \u0026AddObj) -\u003e Any {\n    node.a.to_any() // was: Any::from(node.a.clone())\n}\n```\n\n`to_any()` leaves the borrowed value usable and retains object-backed\nvalues by increfing them.\n\n## Efficiency and Test\n\n`to_any` costs whatever `From\u003cAnyView\u003e for Any` costs, which no longer\ncrosses the C ABI on every conversion. Where the type index is a\ncompile-time constant (`i64`, `Array`, `Map`) the dispatch folds away\nand `to_any` matches `Any::from`. For `String`/`Bytes` and derived\nobject refs the index is read at runtime, so the normalizing branch\nsurvives and the caller keeps a stack frame. That is deliberate: a type\nwhose view is a borrowed representation — the Rust counterpart of C++\n`RValueRef\u003cT\u003e` — needs that branch to stay.\n\nThe result is on par with `Any::from`: neither emits a call or an unwind\npath, and on the object path both do the same single `lock incq`.\nVerified on the release asm (x86-64, `-C codegen-units\u003d1`).\n\nTests in `tests/test_any.rs`: `to_any` matches `Any::from` across the\nscalar, small-string/bytes, and object representations and increfs\nexactly once (given back on drop); and it works on fields reached\nthrough `Deref` — `String`, `Option\u003cString\u003e`, `i64` — where `Any::from`\ndoes not compile.\n\nDocs: new \"Converting Borrowed Values into `Any`\" section in\n`docs/guides/rust_lang_guide.md`.\n\n---------\n\nSigned-off-by: yuchuan \u003cyuchuan.7streams@gmail.com\u003e"
    },
    {
      "commit": "32ab66ee756997208e7666841eb77b6de5e8420d",
      "tree": "9b9c221a49d9f76d0f26fef4e1650875a074b9a5",
      "parents": [
        "c4a89570a9b361301eded1aff7933f5a7ff2f9f3"
      ],
      "author": {
        "name": "Yaxing Cai",
        "email": "caiyaxing666@gmail.com",
        "time": "Tue Aug 25 02:28:50 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Aug 24 14:28:50 2026 -0400"
      },
      "message": "[FIX] Make ffi.Error picklable (#709)\n\n## Motivation\n\n`Error.py_error()` attaches the FFI error object to the Python exception\nit raises:\n\n```python\npy_error.__tvm_ffi_error__ \u003d self\n```\n\n`BaseException.__reduce__` includes the instance `__dict__`, so pickling\nan FFI-originated exception pickles that `Error` through\n`CObject.__getstate__` → `ToJSONGraph`. `ffi.Error` has no native\ncreator and no `__ffi_new__` type attr, so this fails:\n\n```\nTypeError: Type `ffi.Error` does not support ToJSONGraph\n           (no native creator or __ffi_new__ type attr)\n```\n\nHarnesses that ship exceptions across a process boundary lose the\noriginal error and report this instead. It was reported downstream\nagainst a CUDA IMA (error 700), where the replacement message made it\nlook like tvm-ffi had suppressed a coredump — it had not; the coredump\nhappens before the error is raised, and the only real defect is that the\nexception could not be pickled.\n\n`copy.deepcopy` hits the same path.\n\n## Changes\n\n`ffi.Error` now pickles by value. An error is fully described by its\n`(kind, message, backtrace)` strings, so `Error.__reduce__` reconstructs\nit through `__init__` rather than the JSON graph. This mirrors `Device`\nand `DataType`, which already carry hand-written `__reduce__`\nimplementations for the same reason.\n\n`extra_context` is intentionally dropped — it may hold arbitrary native\npayloads, and preserving it only when it happens to be serializable\nwould make pickling an error depend on where the error came from.\n\nThe attribute stays a live `Error` rather than degrading to `None`,\nbecause `set_last_ffi_error` calls `update_backtrace` on\n`__tvm_ffi_error__` when a restored exception propagates back through\nthe FFI; a `None` there would fail on an unrelated `hasattr` check that\nis already in the code.\n\n## Not in scope\n\nAn earlier revision of this PR also rewrote the message raised when\npickling types that genuinely cannot round-trip (`ffi.Function`,\n`ffi.Module`, `ffi.Tensor`, `ffi.OpaquePyObject`). Per review, that is\ndropped here and can be revisited separately — this PR is now only the\n`Error` fix. Those types are unchanged and still surface the\nserializer\u0027s own message.\n\n## Testing\n\nNew tests in `tests/python/test_error.py`: exception and bare-`Error`\npickle round trips, `deepcopy`, NULL handle, the `extra_context` drop,\nand re-propagating a restored exception through an FFI call (which\nexercises `set_last_ffi_error`\u0027s `update_backtrace` on the restored\nobject).\n\nFull Python suite: 2421 passed, 52 skipped, 2 xfailed. `pre-commit`\nclean on all changed files."
    },
    {
      "commit": "c4a89570a9b361301eded1aff7933f5a7ff2f9f3",
      "tree": "769abab143a217782bd339c15bbbbae4ea1055b6",
      "parents": [
        "86b40856a33c0bb3352311a409ddaf29d7eccd66"
      ],
      "author": {
        "name": "Linzhang Li",
        "email": "yuchuan.7streams@gmail.com",
        "time": "Fri Aug 21 23:54:09 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Aug 21 23:54:09 2026 -0400"
      },
      "message": "[FEAT][RUST] Complete structural walk/map/visit/mutate dispatch APIs (#711)\n\n## Summary\n\nThis PR completes the Rust structural traversal API by giving all four\nstructural operations a\ntyped callback and `#[dispatch(...)]` frontend while preserving the\ndistinction between\nengine-driven and user-driven recursion.\n\n| API | Recursion owner | Callback state model | Generated dispatch |\n|---|---|---|---|\n| `structural_walk` | Engine | `FnMut` capture / walker fields |\n`#[dispatch(walk)]` |\n| `structural_map` | Engine | `FnMut` capture / mapper fields |\n`#[dispatch(map)]` |\n| `structural_visit` | Callback or visitor | `VisitCallbacks\u003cState,\n...\u003e` + `VisitContext\u003cState\u003e` | `#[dispatch(visit)]` |\n| `structural_mutate` | Callback or mutator | `MutateCallbacks\u003cState,\n...\u003e` + `MutateContext\u003cState\u003e` | `#[dispatch(mutate)]` |\n\nThe callback-backed visit and mutate paths implement `StructuralVisitor`\nand\n`StructuralMutator` directly. As a result, callbacks, generated dispatch\ntypes, and hand-written\nvisitors/mutators now share the same mutable runtime protocol and\nregistered structural hooks.\n\n## Motivation\n\nBefore this PR, the Rust walk/map layers already accepted typed\ncallbacks, but user-driven visit\nand mutate required hand-written trait implementations. In addition,\n`#[dispatch(visit)]` named\nthe engine-driven walk dispatcher rather than the `StructuralVisitor`\nlayer, leaving the four APIs\nasymmetric.\n\nThis PR aligns the names and entry points with their recursion model,\nadds lightweight callback\nfrontends for one-off user-driven traversals, and retains a fully\nborrow-checked state model for\ncallbacks that recursively re-enter themselves.\n\n## Changes\n\n### Extend `#[dispatch]` to four explicit modes\n\n- Add `dispatch(walk)` for engine-driven observers using `walk_*`\nhandlers.\n- Keep `dispatch(map)` for engine-driven replacements using `map_*`\nhandlers.\n- Make `dispatch(visit)` generate `StructuralVisitor` from user-driven\n`visit_*` handlers.\n- Add `dispatch(mutate)` to generate `StructuralMutator` from\nuser-driven `mutate_*` handlers.\n- Preserve source-order, first-match dispatch over owned FFI values,\nborrowed object nodes, and\n  catch-all `VisitValue`/`MapValue` handlers.\n- Forward an optional trailing `DefRegionKind` argument in every mode.\n- Use mode-specific fallback behavior: `Advance` for walk, no\nreplacement for map, default child\ntraversal for visit, and the appropriate copy/in-place default for\nmutate.\n\n### Add callback-driven structural visitors\n\n- Allow `structural_visit` to accept either `\u0026mut StructuralVisitor`,\none typed callback, or a\n  nested callback tuple.\n- Add `VisitCallbacks\u003cState, ...\u003e` for reusable callback chains with\nordinary mutable state.\n- Add `VisitContext\u003cState\u003e` with access to state, the current value and\ndefinition region,\n  selected-child recursion, and default child traversal.\n- A matched callback owns traversal of its value; unmatched values use\ndefault child traversal.\n- Support `()`, `Result\u003c()\u003e`, `Option\u003cVisitInterrupt\u003e`, and\n  `Result\u003cOption\u003cVisitInterrupt\u003e\u003e` callback outcomes.\n\n### Add callback-driven structural mutators\n\n- Allow `structural_mutate` to accept either `\u0026mut StructuralMutator`,\none typed callback, or a\n  nested callback tuple.\n- Add `MutateCallbacks\u003cState, ...\u003e` for reusable callback chains with\nordinary mutable state.\n- Add `MutateContext\u003cState\u003e` with access to state, the current value and\ndefinition region,\nborrowed-child mutation, owned-child maybe-in-place mutation, default\nmutation, and\n  invocation-local variable remapping.\n- A matched callback supplies the final value; unmatched values retain\nthe engine\u0027s current\n  copy/maybe-in-place permission and use default mutation.\n- Keep `MutateContext::default_mutate()` on the copy path because the\ncallback may still hold a\n  shared borrow of the current value. Owned children can explicitly use\n  `maybe_inplace_mutate()` when reuse is safe.\n\n### Make recursive callback state borrow-checked\n\n- Visit and mutate callbacks remain `Fn`, allowing the same callback to\nbe recursively\n  re-entered.\n- Callback code is stored independently behind `Rc`, while mutable state\nand the active driver\n  remain in the callback wrapper.\n- Recursive context methods require `\u0026mut self`, so Rust rejects a state\nborrow that remains live\nacross recursive visit/mutate calls instead of relying on external\n`Cell`/`RefCell` state.\n- Direct callbacks are wrapped in a temporary `VisitCallbacks\u003c(), ...\u003e`\nor\n`MutateCallbacks\u003c(), ...\u003e`; users opt into state by constructing the\nwrapper explicitly.\n\n### Preserve structural runtime semantics\n\n- Registered `__s_visit__`, `__s_mutate__`, and\n`__s_maybe_inplace_mutate__` hooks continue to\nreceive the active Rust-backed visitor/mutator and can re-enter Rust\nthrough the shared ABI.\n- Definition-region propagation, reflected-field fallback,\ninterrupt/error context, panic\nresumption, and nested traversal state restoration continue to work\nacross callback paths.\n- Mutation keeps invocation-local `FreeVar`/`DAGNode` remapping and\nrechecks uniqueness before an\n  in-place write.\n- No C or C++ ABI changes are introduced.\n\n## Compatibility note\n\nThe former walk-layer naming is intentionally changed:\n\n- `#[dispatch(visit)]` with `visit_*` observer methods becomes\n`#[dispatch(walk)]` with `walk_*`\n  methods.\n- `VisitDispatch` becomes `WalkDispatch`.\n- `DispatchVisitor` becomes `DispatchWalker`.\n\n`#[dispatch(visit)]` now denotes the user-driven visitor layer and\ngenerates\n`StructuralVisitor`. Existing hand-written `StructuralVisitor` and\n`StructuralMutator` call sites\nremain valid.\n\n## Tests\n\n- `cargo test --workspace`\n- `cargo test --workspace --release`\n- `cargo test --workspace --all-features`\n- `RUSTDOCFLAGS\u003d\"-D warnings\" cargo doc --workspace --no-deps`\n- `uv run --group docs sphinx-build -W --keep-going -b html docs\ndocs/_build/html`\n- Pre-commit hooks on all changed files\n\nThe expanded regression coverage includes callback first-match behavior,\nnested tuples,\ndefinition regions, selected-child recursion, stateful recursive\nre-entry, interrupts, registered\nhooks, reflection, nested traversals, panic/error propagation,\ncopy-on-write/in-place behavior,\nand invocation-local identity remapping.\n\n---------\n\nSigned-off-by: yuchuan \u003cyuchuan.7streams@gmail.com\u003e"
    },
    {
      "commit": "86b40856a33c0bb3352311a409ddaf29d7eccd66",
      "tree": "d2357689cba5360572749aa933b3b987ea226910",
      "parents": [
        "f894595bc5db1183a2bbd5eb9c2f2471d8dba1fb"
      ],
      "author": {
        "name": "Shushi Hong",
        "email": "820958424@qq.com",
        "time": "Fri Aug 21 15:03:47 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Aug 21 15:03:47 2026 -0400"
      },
      "message": "[Fix][Rust] Serialize structural visit test registration (#710)\n\nThis pr fixes a flaky failure in the Rust structural visit tests.\n\nThe Rust test harness runs tests in parallel, and several independent\n`LazyLock` initializers could register fixture types concurrently. The\nruntime `TypeTable` intentionally does not synchronize updates and\nrequires registration callers to provide synchronization."
    },
    {
      "commit": "f894595bc5db1183a2bbd5eb9c2f2471d8dba1fb",
      "tree": "6df75dd3ff5fe8413c060435cba511f5ac097541",
      "parents": [
        "c4d9cd3ee05e0911635d9e08d2b89782cea6bc3c"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Fri Aug 21 00:36:55 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Aug 21 12:36:55 2026 +0800"
      },
      "message": "[FEAT] Add core opaque pointer handler map (#708)\n\nThird-party extension types cannot always define or accept\nmonkey-patching of `__tvm_ffi_opaque_ptr__`. Add a direct exact-class\n`tvm_ffi.core._OPAQUE_PTR_HANDLERS` dictionary in the Cython core so\nthose objects can participate in opaque-pointer argument conversion\nwithout changing their owning package.\n\nHandlers are populated during application setup and treated as read-only\nonce FFI calls begin. Native conversions and the class-defined\nopaque-pointer protocol retain precedence."
    },
    {
      "commit": "c4d9cd3ee05e0911635d9e08d2b89782cea6bc3c",
      "tree": "9018604a36247a3e6377d85f07b36f40a2b0337d",
      "parents": [
        "ca8803c9f34d26cdc665f5dc5adfc0bc816771eb"
      ],
      "author": {
        "name": "Shushi Hong",
        "email": "820958424@qq.com",
        "time": "Thu Aug 20 15:54:56 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Aug 20 15:54:56 2026 -0400"
      },
      "message": "[Feat][Rust] Add native structural_map and structural_mutate (#704)\n\nThis PR adds Rust-native `structural_map` and `structural_mutate`\nsupport as the Rust counterpart to the C++ structural mutation APIs\nintroduced in #649. It builds on the Rust `structural_visit` and\n`structural_walk` infrastructure from #693.\n\n## Design\n\nRust owns:\n\n- Callback dispatch and walk order.\n- Definition-region propagation.\n- DAG and FreeVar identity remapping.\n- Error context and panic propagation.\n- The user-facing structural-map and structural-mutator APIs.\n\nType-specific traversal remains with the implementation that registered\nthe runtime type.\n\nFor default recursion, Rust looks up the existing structural mutation\ntype attributes:\n\n- `__s_mutate__`\n- `__s_maybe_inplace_mutate__`\n\nRust constructs an ABI-compatible `ffi.StructuralMutator` object.\nRegistered hooks receive this active mutator and recursively call its\nlanguage-independent vtable to return child values to Rust.\n\nThis allows the existing C++ hooks for Array, List, Map, and Dict to\nmanage their private storage while Rust continues to control callback\ndispatch and recursive transformation.\n\nHooks may be registered as either opaque function pointers or\n`ffi.Function` objects.\n\nThis PR does not add a Map/Dict-specific C API, does not add\n`TVMFFIMapMutateValues`, and does not mirror the private C++ Map/Dict\nstorage layout.\n\n## Rust APIs\n\nThis PR provides:\n\n- `structural_map` with pre-order and post-order callbacks.\n- A low-level `StructuralMutator` trait for custom recursion.\n- `InplaceValue` for engine-authorized in-place mutation.\n- `StructuralVarRemap` for owning DAG and FreeVar substitutions.\n- Typed closures and ordered callback tuples of up to eight handlers.\n- `#[dispatch(map)]` generated dispatch.\n- Optional `DefRegionKind` callback arguments.\n- Fallible callbacks returning `Result\u003cAny\u003e`.\n- Shared callback value handling between structural visit and map.\n- Structural error context for objects and reflected fields.\n\nCallback tuples use ordered first-match dispatch. A `\u0026MapValue` handler\nacts as the catch-all handler and should therefore appear last.\n\n## Mutation semantics\n\nThe root is consumed so Rust ownership and the runtime reference count\ndetermine whether in-place mutation is allowed.\n\n- Uniquely owned Array, List, Map, and Dict objects may reuse their\nstorage.\n- Passing a shared root, such as `root.clone()`, selects copy-on-write\nbehavior.\n- Map and Dict keys are structural anchors and are not mapped.\n- If no value changes, the original object may be returned.\n- Reflected objects use `__ffi_shallow_copy__` together with registered\nfield getters and setters.\n- FreeVar and DAG-node identities are mapped once and reuse the\ncompleted mapped result.\n- `None` and other inline values are passed through normal callback\ndispatch.\n- Changes completed through an in-place path are not rolled back if a\nlater callback fails.\n\nRust panics are caught before crossing the C ABI. The panic is resumed\nonly after the registered runtime hook returns, allowing C++ RAII\ncleanup to finish first.\n\nA retained `ffi.StructuralMutator` reference also fails safely after the\nactive structural-mutation call ends instead of keeping a dangling Rust\ncallback context.\n\n## Shared structural callback support\n\nThe structural visit and map implementations share:\n\n- Borrowed callback-value handling.\n- Typed object-node casts.\n- Callback tuple arity generation.\n\nThe procedural macro implementation is generalized from visit-only\ndispatch to support both `#[dispatch(visit)]` and `#[dispatch(map)]`.\n\n---------\n\nSigned-off-by: tlopex \u003c820958424@qq.com\u003e"
    },
    {
      "commit": "ca8803c9f34d26cdc665f5dc5adfc0bc816771eb",
      "tree": "3379e73d817aedc9efc32f7bd4a167cbb13c2a3a",
      "parents": [
        "75e693f88338e5264a02f73da2eeb2d5aae2163e"
      ],
      "author": {
        "name": "Kathryn (Jinqi) Chen",
        "email": "65606304+Kathryn-cat@users.noreply.github.com",
        "time": "Thu Aug 13 20:03:29 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Aug 14 12:03:29 2026 +0900"
      },
      "message": "[FEAT] Add structural map, maybe_inplace_mutate, and var_remap APIs (#649)\n\n## Summary\n\nThis PR adds structural transformation support to TVM FFI, complementing\nthe existing structural equality, hashing, and walking APIs.\n\nThe new `StructuralMutator` recursively transforms reflected object\ngraphs, while `structural_map` provides a convenient callback-based\ninterface for compiler passes.\n\n  ## Structural mapping\n\n`structural_map` follows the same typed callback model as\n`structural_walk`. Callbacks are matched by runtime type and return\neither the unchanged value or a replacement.\n\nMapping defaults to post-order, so callbacks observe values whose\nchildren have already been transformed. This makes bottom-up rewrites\nsuch as constant folding straightforward:\n\n```py\n  def fold_add(expr):\n      if isinstance(expr.lhs, IntImm) and isinstance(expr.rhs, IntImm):\n          return IntImm(expr.lhs.value + expr.rhs.value)\n      return expr\n\n  optimized \u003d tvm_ffi.structural_map(function, (Add, fold_add))\n```\n\n  The PR exposes:\n\n  - structural_map in Python.\n  - StructuralMap and StructuralMapExpected in C++.\n  - Ordered typed callbacks and grouped callback types.\n  - Pre-order and post-order transformation.\n  - Callbacks receiving either value or (value, def_region_kind).\n  - Structural error context when transformation fails.\n\n  ## StructuralMutator\n\n`StructuralMutator` provides the low-level transformation engine through\ntwo operations:\n\n- `Mutate` transforms a value without intentionally modifying the input.\n- `MaybeInplaceMutate` permits implementations to reuse an object when\ndoing so is safe.\n\n  ## Custom mutation behavior\n\n  Object types can customize mutation using:\n\n  - `__s_mutate__` for canonical non-in-place transformation.\n- `__s_maybe_inplace_mutate__` for an optional type-specific in-place\noptimization.\n\nThe maybe-in-place hook owns its safety policy and may reuse the input,\ndelegate to normal mutation, or return another value. A type providing\nit must also provide `__s_mutate__`.\n\n  Built-in hooks are registered for Array, List, Map, and Dict.\n\n  ## Variable identity remapping\n\nThe mutator maintains an identity-substitution environment for FreeVar\nobjects. Once an identity is mapped, later occurrences reuse the same\nresult.\n\n  For example:\n\n```py\n  def specialize_shape_var(var):\n      if var.name \u003d\u003d \"n\":\n          return IntImm(10)\n      return var\n\n  specialized \u003d tvm_ffi.structural_map(\n      function,\n      (Var, specialize_shape_var),\n  )\n```\n\nIf the same `Var` occurs in a function parameter and its body, both\noccurrences resolve to the same mapped result.\n\nThe mutator also exposes `get_var_remap` and `set_var_remap`, allowing\ncustom DAG-style variable wrappers to use their underlying identity\nobject as the remapping key."
    },
    {
      "commit": "75e693f88338e5264a02f73da2eeb2d5aae2163e",
      "tree": "183639894e6dfc94686b019f97e5cd4def43ecdc",
      "parents": [
        "f59eae05349dd77d5de07a1883fe88fabe6bab65"
      ],
      "author": {
        "name": "Linzhang Li",
        "email": "yuchuan.7streams@gmail.com",
        "time": "Tue Aug 11 20:19:13 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Aug 12 09:19:13 2026 +0900"
      },
      "message": "[FEAT][RUST] Resolve reflected type methods and constructors from Rust (#707)\n\nAdd Function::from_type_method(type_index, name) and\nFunction::from_type_key_method(type_key, name) to look up methods\nregistered through the C++ reflection registry\n(`efl::ObjectDef\u003cT\u003e::def(...)`), which live in the per-type method table\nrather than the global function table. Constructors registered via\nrefl::init are reachable under the reserved name __ffi_init__.\n\nDownstream Rust consumers of libraries that follow the ObjectDef idiom\npreviously had to hand-roll this table walk against raw tvm-ffi-sys\nstructs; this provides the missing primitive in the crate itself.\n\nSigned-off-by: yuchuan \u003cyuchuan.7streams@gmail.com\u003e"
    },
    {
      "commit": "f59eae05349dd77d5de07a1883fe88fabe6bab65",
      "tree": "c9c436abd4f01a3e1457aaa7ced52d78777d2ad6",
      "parents": [
        "620fece9f8d81dded637cec9fc52e388f7bd0ae1"
      ],
      "author": {
        "name": "Tom McTiernan",
        "email": "tmct@users.noreply.github.com",
        "time": "Mon Aug 10 02:49:11 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Aug 10 09:49:11 2026 +0800"
      },
      "message": "fix: create wheel for GIL build of Python 3.14 (#703)"
    },
    {
      "commit": "620fece9f8d81dded637cec9fc52e388f7bd0ae1",
      "tree": "cae2a067264850f6aa3e3656218b21757cb54245",
      "parents": [
        "12dbf053b3d9ba4ebd9da3123b1aeca79cf74229"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Wed Aug 05 07:40:16 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Aug 04 16:40:16 2026 -0700"
      },
      "message": "[TEST] Relax shared DAG hash scaling threshold (#702)\n\nRelax the flaky shared-DAG `RecursiveHash` timing threshold and adjacent\nexplanation from 4x to 10x"
    },
    {
      "commit": "12dbf053b3d9ba4ebd9da3123b1aeca79cf74229",
      "tree": "fdd32a07c0aafbc631d6c219e708ec7cd904590e",
      "parents": [
        "6c98ca25213b31516f7d9d03526805f9a09015ba"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Wed Aug 05 06:31:44 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Aug 04 15:31:44 2026 -0700"
      },
      "message": "[FFI] Keep object optionals pointer-sized (#701)\n\nThis restores the established pointer-sized ABI for object optionals\nwhile preserving the Any-backed representation for non-object values."
    },
    {
      "commit": "6c98ca25213b31516f7d9d03526805f9a09015ba",
      "tree": "83e573e537d9975ab09feba66577afd3ea24eb81",
      "parents": [
        "b98be1bf4062b85a95a7330327645ffd86f99b05"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Tue Aug 04 20:31:05 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Aug 04 20:31:05 2026 +0800"
      },
      "message": "[CORE] Make ModuleObj Stable (#700)\n\n## Rationale\n\nThe TVMFFIAny-backed Optional layout is the intended forward ABI, but\nOptional\u003cFunction\u003e grew from one pointer to one TVMFFIAny cell.\nModuleObj function lookup is a C++ ABI boundary whose symbols do not\nencode return types, so retaining Optional\u003cFunction\u003e makes old and new\ncallers disagree about return storage.\n\nUse nullable Function for both ModuleObj lookup overloads. Function\nremains pointer-sized and preserves the historical null representation,\nwhile Optional itself and the String metadata APIs retain their current\nABI.\n\n## Change\n\n- Return nullable Function from direct and import-aware module lookup.\n- Update library and ORCJIT module implementations plus C++ examples."
    },
    {
      "commit": "b98be1bf4062b85a95a7330327645ffd86f99b05",
      "tree": "92874addcc52a6d19d49eae0cffbc80762240ad1",
      "parents": [
        "3bfcffa58476935c9b08b7e6e74f8491b4ec54cf"
      ],
      "author": {
        "name": "Linzhang Li",
        "email": "yuchuan.7streams@gmail.com",
        "time": "Sun Aug 02 21:37:11 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Aug 03 09:37:11 2026 +0800"
      },
      "message": "[FEAT][RUST] Add rust structural_visit and structural_walk. (#693)\n\nA refreshed summary of the API as it now stands, since it has moved\nsince the description above was written.\n\n`structural_walk(root, walker, order)` walks a value graph and\ndispatches typed handlers in pre- or post-order; handlers steer the\ntraversal through the returned `WalkResult` (`Advance`, `Skip`,\n`Interrupt`/`InterruptWith(payload)`) and may return\n`Result\u003cWalkResult\u003e` to propagate errors with `?`. The walker can be:\n\n- a `\u0026mut` `#[dispatch(visit)]` visitor (or a hand-written\n`VisitDispatch`) — its `visit_*` methods dispatch on argument type in\nsource order;\n- a single closure over an FFI value type `T` (value cast), a borrowed\nobject node `\u0026N` (refcount-free subtype check), or the `\u0026VisitValue`\ncatch-all;\n- a tuple of up to 8 such callbacks — closures and `\u0026mut` visitors mixed\nfreely — tried in order with the first matching argument type winning,\nthe analog of the variadic C++ `StructuralWalk(root, callbacks...)`\nchain.\n\nEvery handler shape may declare a trailing `DefRegionKind` argument to\nreceive the definition-region state:\n\n```rust\nuse tvm_ffi::{structural_walk, Array, DefRegionKind, Object, WalkOrder, WalkResult};\n\nlet values \u003d Array::new(vec![10_i64, 2]);\nlet mut total \u003d 0_i64;\nlet mut objects \u003d 0;\nassert!(structural_walk(\n    \u0026values,\n    (\n        |value: i64| {\n            total +\u003d value;\n            WalkResult::Advance\n        },\n        |_object: \u0026Object, _kind: DefRegionKind| {\n            objects +\u003d 1;\n            WalkResult::Advance\n        },\n    ),\n    WalkOrder::PreOrder,\n)\n.unwrap()\n.is_none());\nassert_eq!((total, objects), (12, 1));\n```\n\n`structural_visit(root, visitor)` drives a hand-written\n`StructuralVisitor` when recursion itself is part of the analysis,\nmirroring a C++ `StructuralVisitorObj`: `visit` runs for each value and\ncontrols all descent through `default_visit_children` or\n`visit_child(child, kind)`, whose explicit kind argument plays the role\nof `WithDefRegionKind`. Both entry points return\n`Result\u003cOption\u003cVisitInterrupt\u003e\u003e`: `Ok(None)` means the whole graph was\nvisited, and an interrupting handler\u0027s payload comes back in\n`Ok(Some(interrupt))`:\n\n```rust\nuse tvm_ffi::{\n    structural_visit, Array, DefRegionKind, Result, StructuralVisitor, VisitInterrupt, VisitValue,\n};\n\n#[derive(Default)]\nstruct Depth {\n    max: usize,\n    current: usize,\n}\n\nimpl StructuralVisitor for Depth {\n    fn visit(\n        \u0026mut self,\n        value: \u0026VisitValue,\n        def_region_kind: DefRegionKind,\n    ) -\u003e Result\u003cOption\u003cVisitInterrupt\u003e\u003e {\n        self.current +\u003d 1;\n        self.max \u003d self.max.max(self.current);\n        let interrupt \u003d self.default_visit_children(value, def_region_kind)?;\n        self.current -\u003d 1;\n        Ok(interrupt)\n    }\n}\n\nlet values \u003d Array::new(vec![1_i64, 2]);\nlet mut depth \u003d Depth::default();\nstructural_visit(\u0026values, \u0026mut depth)?;\nassert_eq!(depth.max, 2);\n```\n\n## Performance\n\nRe-measured on the current branch with the shared benchmark: Rust\n`structural_visit` (pre-order) and `structural_walk` (post-order)\nagainst the equivalent C++ `StructuralWalk` traversals on identical\nobject graphs, all language x style combinations checksum-asserted\nbefore timing. Medians of 30 pinned reps.\n\nRust / C++ time ratio (lower is better; \u003c 1 means Rust is faster):\n\n| shape | structural_visit | structural_walk |\n|---|---|---|\n| reflected-object tree (196k values) | 0.98x | 1.04x |\n| nested arrays (87k values) | 1.10x | 1.16x |\n| map trees, small \u0026 dense layouts (31k values) | 0.90x | 0.96x |\n\nEvery combination is within 1.16x of C++, at an absolute cost of ~7-21\nns per visited value, matching C++.\n\nSigned-off-by: yuchuan \u003cyuchuan.7streams@gmail.com\u003e\nCo-authored-by: tlopex \u003c820958424@qq.com\u003e"
    },
    {
      "commit": "3bfcffa58476935c9b08b7e6e74f8491b4ec54cf",
      "tree": "8f84fcd5446877403813df0de0e5d73c4c297c13",
      "parents": [
        "a8ba3a3075cabc6e1105cc32c427ed4bd10c18c3"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Mon Aug 03 06:29:12 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Aug 03 06:29:12 2026 +0800"
      },
      "message": "[CORE] Mark type-info lookup as pure (#699)\n\n## Rationale\n\n`TVMFFIGetTypeInfo` returns the stable entry for a registered type index\nwithout modifying observable state. Exposing this contract lets\nsupporting compilers coalesce repeated lookups.\n\n## Change\n\n- Add a portable `TVM_FFI_ATTRIBUTE_PURE` macro for GCC and Clang, with\na safe no-op fallback.\n- State the registered-index precondition and annotate\n`TVMFFIGetTypeInfo`.\n\n## Validation\n\nThe C and C++ header checks, C++ test suite, formatting, and a focused\noptimized compiler benchmark pass."
    },
    {
      "commit": "a8ba3a3075cabc6e1105cc32c427ed4bd10c18c3",
      "tree": "5c8d23c573945556d4714ab9c7e6a527012f7c80",
      "parents": [
        "60e0614d6ca0ae3c15df60596131f9f8a3a2e6c2"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Sun Aug 02 23:08:27 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Aug 02 11:08:27 2026 -0400"
      },
      "message": "fix(version): Keep source patch ahead of post releases (#698)\n\n- Preserve setuptools-scm post-release versions as the Python package\nidentity.\n- Derive checked C++ and Rust source versions from the already-advanced\npatch after a post release.\n- Document why setuptools-scm\u0027s default scheme remains on the\npost-release line instead of advancing the patch."
    },
    {
      "commit": "60e0614d6ca0ae3c15df60596131f9f8a3a2e6c2",
      "tree": "013a2c249f3a0622ea0953d103e8a7e27950c5c0",
      "parents": [
        "a7eafccdf2f75df35d0e7819cad7c975d63f4091"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Sat Aug 01 10:08:38 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Aug 01 10:08:38 2026 +0800"
      },
      "message": "[CORE] Staging Object Tying Feature (#696)\n\n## Summary\n\nObject tying remains compiled but is deliberately staged dormant:\ncanonical-wrapper detection returns false, while C++, Python-defined\ndataclasses, and Rust objects continue to use matching legacy allocation\nand deletion paths.\n\nThis staging has three goals:\n\n- let downstream projects upgrade without making existing generated\ncaches depend on the new allocator contract;\n- keep the compatibility change compact by changing only the\nactivation/allocation boundary instead of removing the object-tying\nimplementation;\n- preserve the custom allocator API and a clean path for a later\ncoordinated object-tying activation.\n\nLegacy wrapper identity and reference-count expectations are restored,\nwhile activation-only tying tests remain as skipped coverage for the\nlater rollout.\n\n## Testing\n\n- C++: 465 enabled tests passed (2 disabled).\n- Python: 2,381 passed, 78 skipped, 2 expected failures.\n- Rust: 138 unit/integration tests and 3 doctests passed; formatting is\nclean.\n- Pre-commit: all changed-file checks passed, including ruff, ty, and\nclang-format.\n- Order-balanced microbenchmarks place the dormant path about 1.3-7.9%\nbehind active tying and 4.7-12.5% ahead of a full revert."
    },
    {
      "commit": "a7eafccdf2f75df35d0e7819cad7c975d63f4091",
      "tree": "f0a9bce24baf4d1c7c1222c002b4f76ef215f798",
      "parents": [
        "c7fcf88f62b4b5c530f83828deb494acb1739a14"
      ],
      "author": {
        "name": "Shushi Hong",
        "email": "820958424@qq.com",
        "time": "Thu Jul 30 21:02:35 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Jul 31 09:02:35 2026 +0800"
      },
      "message": "[Perf][Rust] Optimize match_any! ordered conversion and exact-leaf dispatch (#692)\n\nThis PR improves both Rust `match_any!` dispatch paths without changing\nhow matching works.\n\n## Ordered dispatch\n\nWhen an arm does not match, the internal conversion now returns\n`Err(())` instead of creating a `TypeError`. This makes failed checks\ncheaper while keeping the public `TryFrom\u003cAnyView\u003e` API unchanged.\n\nCustom `TryInto` matchers are still supported and continue to run in\nsource order.\n\n## Exact-leaf dispatch\n\nFor a match with many exact final object types, the macro builds one\n`TypeIndex → ArmId` table through `OnceLock`.\n\nThe table uses the smallest pattern `TypeIndex` as its starting point:\n\n```text\nbase \u003d minimum pattern TypeIndex\narm_ids[pattern_type_index - base] \u003d source ArmId\n```\n\nEach call then selects an arm directly with:\n\n```text\narm_ids[runtime_type_index - base]\n```\n\nThis is an O(1) lookup. Only the selected object handle is created, and\nits type check is not repeated.\n\nThe direct table is used when there are at least 20 typed arms, every\npattern matches one exact final runtime type, there are no guards, and\nbindings are simple names or `_`. Smaller matches, guarded arms,\nparent-type patterns, parameterized containers, and custom matchers\ncontinue using ordered dispatch.\n\nThe input value is still evaluated once. Duplicate types still select\nthe first arm, and unmatched or non-object values still use the final\n`_` fallback. A `TypeId` check prevents the same static table from being\nincorrectly shared by different generic pattern lists."
    },
    {
      "commit": "c7fcf88f62b4b5c530f83828deb494acb1739a14",
      "tree": "5116a77a64c01eaba3bece129fa9c05567c45d3d",
      "parents": [
        "68932438dc809b1199f9ac80dc458b73b4e7ec7d"
      ],
      "author": {
        "name": "Yaxing Cai",
        "email": "caiyaxing666@gmail.com",
        "time": "Fri Jul 31 09:02:22 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Jul 31 09:02:22 2026 +0800"
      },
      "message": "chore(release): Version bump after release v0.1.13 (#686)\n\nVersion bump after release v0.1.13."
    },
    {
      "commit": "68932438dc809b1199f9ac80dc458b73b4e7ec7d",
      "tree": "a4d32a3e5fc810ecf253bd5a16e65c58da83ca5c",
      "parents": [
        "b19448e2b9f5e4ec499cbfe21bc6cbefa1081b09"
      ],
      "author": {
        "name": "Yaxing Cai",
        "email": "caiyaxing666@gmail.com",
        "time": "Wed Jul 29 14:02:43 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Jul 29 14:02:43 2026 +0800"
      },
      "message": "[CI][ORCJIT] Source manylinux LLVM from a release, link libstdc++ dynamically (#688)\n\n## Motivation\n\nThe orcjit addon links against conda-forge\u0027s LLVM, which is built with a\nnewer GCC whose libstdc++ carries `GLIBCXX_3.4.29+` symbols. Those\nexceed the `manylinux_2_28` floor this project standardized on in #675,\nwhich is why the addon has carried a\n`-static-libstdc++`/`-static-libgcc` workaround since the original addon\nPR (#254).\n\nThis builds LLVM from source inside the `manylinux_2_28` image instead,\npublishes the install prefix as a release asset, and has CI download it.\nBecause that toolchain already sits at the manylinux ABI floor, the\nworkaround is no longer needed.\n\n## What changes\n\n* **LLVM acquisition (Linux).** `/opt/llvm` is obtained by downloading\n`llvm-\u003cversion\u003e-linux-\u003carch\u003e.tar.zst` and extracting it, instead of\nbeing built or installed via conda. macOS/Windows keep the conda-forge\nbinaries (no GLIBCXX floor); their `actions/cache` step is split out so\ntheir install gating is unchanged. Everything downstream is untouched —\nsame `/opt/llvm`, same `LLVM_PREFIX`, same bind-mount into the build\ncontainer.\n* **Drop `-static-libstdc++`/`-static-libgcc`,** so the addon no longer\nbakes in a private copy of the C++ runtime.\n\nThe by-name `--exclude-libs` list is deliberately **kept** rather than\ncollapsed to `--exclude-libs,ALL`. I tried that; it fails. The embedded\n`liborc_rt.a` is linked by the JIT at run time and resolves its C++\nruntime through the process, including archive-only helpers such as\n`_ZSt28__throw_bad_array_new_lengthv` that `libstdc++.so` does not\nexport — `ALL` localizes those and the ORC platform fails to materialize\n(`Failed to materialize symbols: { (\u003cPlatform\u003e, ...) }`). That holds\nwhether libstdc++ is static or dynamic, so the comment there is\ncorrected rather than the flag changed.\n\n## Results\n\nFull CI green on all four platforms. The repaired wheel names are the\nABI evidence — auditwheel tags them:\n\n```\napache_tvm_ffi_orcjit-0.1.1-py3-none-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl\n```\n\ni.e. the prefix stays under the floor with libstdc++ linked dynamically.\nThe addon\u0027s exported dynamic symbols drop from ~965 to ~30, since it no\nlonger re-exports a private libstdc++ that could interpose with a host\u0027s\nown copy (e.g. PyTorch\u0027s bundled LLVM), and the C++ runtime references\n(`_Znwm`, `__cxa_throw`, `__gxx_personality_v0`) are now `UND`, served\nby the process. Tests: 89 passed x86_64 / 87 passed aarch64, plus the\nquick-start C and C++ examples.\n\nPrebuilt LLVM is produced out-of-band, so this also removes a ~50 minute\nfrom-source build from the CI path; the Linux orcjit jobs now spend a\nfew minutes downloading.\n\n## Notes for reviewers\n\nTwo things worth flagging that are not visible in the diff:\n\n1. **Artifact provenance.** Linux LLVM now comes from a release asset in\n`mlc-ai/package`, which is outside the ASF org. The asset is currently a\n**pre-release**, and the workflow that produces it lives on an unmerged\nbranch there. That side should land (and ideally be promoted out of\npre-release) before this is merged — hence the draft status. The\ndownload source is parameterized via the `llvm_release_repo` input if\nyou would prefer it mirrored elsewhere.\n2. **`publish_orcjit_wheel.yml` inherits this.** It calls the same\ncomposite action without passing `llvm_version`/`llvm_release_repo`, so\npublished PyPI wheels will also start sourcing LLVM from that release.\nThis is a supply-chain change to a published artifact that the diff does\nnot visibly touch.\n\nBuilds on #675 (`manylinux_2_28` standardization), which is what makes\nthe floor the right target."
    },
    {
      "commit": "b19448e2b9f5e4ec499cbfe21bc6cbefa1081b09",
      "tree": "bd405fe04005fbd7d557ca7e1a44421ccee37ec8",
      "parents": [
        "2a35d327a6fe2578693b3d9958fdb05de4e18383"
      ],
      "author": {
        "name": "Shushi Hong",
        "email": "820958424@qq.com",
        "time": "Mon Jul 27 18:18:05 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Jul 28 06:18:05 2026 +0800"
      },
      "message": "[Feat][Rust] Add leaf lookup dispatch for match_any (#685)\n\nThis PR adds a leaf-only lookup fast path to Rust match_any!. For at\nleast two unguarded arms with simple bindings, when every pattern\ncorresponds to one stable runtime TypeIndex, it lazily maps each\nTypeIndex to a source-order ArmId and uses a native Rust match to select\nonly the relevant conversion. The table stores no closures or arm\nbodies, duplicate types preserve first-arm semantics, and misses use the\n_ fallback. Single-arm, guarded, non-leaf/category, or content-dependent\nmatches retain the Phase 1 ordered path. The PR also adds opt-in\nfinal-type metadata and focused integration tests. The two-arm threshold\nis based on release benchmarks of standard ObjectRef conversions."
    },
    {
      "commit": "2a35d327a6fe2578693b3d9958fdb05de4e18383",
      "tree": "e52a91cd754c87a0664c7045fe9ef2e4e4c041ea",
      "parents": [
        "ff7e3d4f6ece3ffcf48b7111932fd7b6bd77db5d"
      ],
      "author": {
        "name": "Linzhang Li",
        "email": "yuchuan.7streams@gmail.com",
        "time": "Mon Jul 27 12:55:36 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Jul 27 12:55:36 2026 -0400"
      },
      "message": "[FEAT][RUST] Support runtime-checked try_cast between ObjectRef types (#684)\n\nThis PR adds direct, runtime-checked casting between Rust object\nhandles, mirroring C++ `ObjectRef::as\u003cT\u003e` / `Downcast\u003cT\u003e`.\n\n**ObjectRefCast** is blanket-implemented for types implementing both\n`ObjectRefCore` and `AnyCompatible`. `try_cast::\u003cB\u003e(self)` consumes the\nsource and, on success, rewraps the same object as `B` without cloning\nor copying it. A failed cast returns a `TypeError` describing the source\nand target types.\n\nTarget compatibility is delegated to `B::check_any_strict`. ObjectRef\nhierarchies accept `B` and its runtime subtypes, while parameterized\ncontainers use their complete type semantics.\n\n```rust\nlet base: TestBase \u003d derived.try_cast()?; // upcast\nlet obj: ObjectRef \u003d base.try_cast()?;    // upcast to root\nlet d: TestDerived \u003d obj.try_cast()?;     // checked downcast\n```\n\nThe direct `A -\u003e B` path reuses the existing `AnyCompatible` conversion\ntraits through a raw `TVMFFIAny`, so callers do not need to construct an\n`Any` or `AnyView`. It first creates a non-owning view for the target\ncheck and transfers ownership only after that check succeeds, keeping\nfailure and panic paths leak-free.\n\nDerived ObjectRef conversions preserve the runtime type index stored in\nthe object header. A derived object upcast to a base handle can\ntherefore still round-trip through `Any` or `AnyView` and downcast\ncorrectly.\n\nA hidden `is_instance_of` helper provides hierarchy checks for\nderive-generated object containers. The cast path uses\n`assert_unchecked` after establishing the object type-index invariant;\nrelease codegen confirms that the intermediate `TVMFFIAny` storage and\nredundant object-range check are eliminated.\n\nThe PR also includes the derive fixes required by downstream crates and\nfocused tests covering hierarchy casts, failure ownership, dynamic-type\npreservation through `Any`/`AnyView`, direct `try_cast_from_any_view`,\nand parameterized-container mismatch.\n\n---------\n\nSigned-off-by: yuchuan \u003cyuchuan.7streams@gmail.com\u003e\nCo-authored-by: tlopex \u003c820958424@qq.com\u003e"
    },
    {
      "commit": "ff7e3d4f6ece3ffcf48b7111932fd7b6bd77db5d",
      "tree": "8c95ba39cade6848e8936338cda85ffff30dacf2",
      "parents": [
        "135c2e8bbf51a353db1c26a75404e03d03e802cb"
      ],
      "author": {
        "name": "Yaxing Cai",
        "email": "caiyaxing666@gmail.com",
        "time": "Mon Jul 27 06:04:35 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Jul 27 06:04:35 2026 +0800"
      },
      "message": "[FIX] Select the C++ standard for the torch addon by torch version (#687)\n\nTorch 2.13 uses C++20 constructs in its public headers, such as\ndesignated initializers and default member initializers for bit-fields,\nand builds its own extensions with C++20 accordingly. The torch C-DLPack\naddon still compiled with C++17, which makes the Windows wheel job fail\nto compile:\n\n```\nerror C7582: default member initializers for bit-fields requires at least /std:c++20\nerror C7555: use of designated initializers requires at least /std:c++20\nerror C2139: \u0027torch::autograd::Node\u0027: an undefined class is not allowed as an argument to compiler intrinsic type trait \u0027__is_base_of\u0027\n```\n\nGCC and Clang accept those constructs in C++17 mode as extensions and\nonly warn about them, so Linux and macOS keep building while MSVC\nrejects them outright. That is why `main` has been red on Windows since\ntorch 2.13.0 (released 2026-07-08) while the other platforms stayed\ngreen on the same commit.\n\n### Changes\n\n- Select the C++ standard from the installed torch version rather than\nhard-coding it: C++20 for torch 2.13 and later, C++17 before that.\nApplied to both the Windows (`/std:`) and Linux/macOS (`-std\u003d`) build\npaths.\n- The build script already reports compiler errors through its own\nstderr, but the tests discarded the child output and asserted on the\nexit code alone, so failures surfaced as a bare `exit status 1` and hid\nthe diagnostics above. Capture that output and attach it to the\nassertion.\n\n### Testing\n\n- `tests/python/test_optional_torch_c_dlpack.py` passes on Linux with\ntorch 2.13.0, building the addon from a clean cache.\n- Version selection verified across torch 2.8.0, 2.12.1, 2.13.0, 2.13.1,\n2.14.0 and 3.0.0.\n- The Windows wheel job only runs on `main` (`ci_mainline_only.yml`) and\ninstalls torch 2.13 there, so it was validated by dispatching that\nworkflow against this branch."
    },
    {
      "commit": "135c2e8bbf51a353db1c26a75404e03d03e802cb",
      "tree": "c94648b27954980a870d2f0dbfa64483b4039cb8",
      "parents": [
        "4108fd226e0048d0e5bfd53b7fc3434e67b03052"
      ],
      "author": {
        "name": "Shushi Hong",
        "email": "820958424@qq.com",
        "time": "Thu Jul 23 00:37:24 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Jul 23 12:37:24 2026 +0800"
      },
      "message": "[Rust][Feat] Add match_any! for object-backed values (#682)\n\nThis PR adds Rust match_any!, a Phase 1 macro that evaluates an\nAny-compatible scrutinee once, converts it to AnyView, and tries\nobject-backed target conversions in source order using the existing\nstandard TryInto/TryFrom implementations. The first successful\nconversion whose optional guard passes selects its arm; a failed\nconversion or guard continues to the next arm, while a required final _\nhandles non-object or unmatched values. This implementation\nintentionally does not add type-index dispatch tables, caches, custom\npattern protocols, or heuristic dispatch.\n\n```rust\nmatch_any! {\n    value {\n        Tensor(tensor)\n            if tensor.shape().len() \u003d\u003d 2 \u003d\u003e (\"matrix\", tensor.shape().len()),\n        Tensor(tensor) \u003d\u003e (\"tensor\", tensor.shape().len()),\n        Shape(shape) \u003d\u003e (\"shape\", shape.len()),\n        Array::\u003ci64\u003e(array) \u003d\u003e (\"array\", array.len()),\n        _ \u003d\u003e (\"unsupported\", 0),\n    }\n}\n```"
    },
    {
      "commit": "4108fd226e0048d0e5bfd53b7fc3434e67b03052",
      "tree": "08fb706a57ad33cfb00c7ed4ab0219f70ed70370",
      "parents": [
        "3e8b2a860936fdacc85d65ec07bcebe150d23b5f"
      ],
      "author": {
        "name": "Yixin Dong",
        "email": "ubospica@gmail.com",
        "time": "Wed Jul 22 15:19:03 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Jul 23 06:19:03 2026 +0800"
      },
      "message": "[FEAT] Expose Tensor data_ptr in Python (#679)\n\n## Summary\n- add `Tensor.data_ptr()` to return the address of the first tensor\nelement\n- include the DLPack tensor\u0027s byte offset in the returned address\n- add the Python type stub and tests using real NumPy arrays and sliced\nviews\n\nThis allows callers to access tensor memory directly without exporting\nand parsing a DLPack capsule.\n\n## Test plan\n- [x] `uv run pytest tests/python/test_tensor.py -q` (8 passed, 3\nskipped)\n- [x] `uv run pytest tests/python -q` (2418 passed, 41 skipped, 2\nexpected failures)\n- [x] `uv run pre-commit run --files python/tvm_ffi/cython/base.pxi\npython/tvm_ffi/cython/tensor.pxi python/tvm_ffi/core.pyi\ntests/python/test_tensor.py`"
    },
    {
      "commit": "3e8b2a860936fdacc85d65ec07bcebe150d23b5f",
      "tree": "9378db78d26d4fc20763b4c396d2194d358e438d",
      "parents": [
        "d6c18a666a79d6261239e134861c749c168c8e6a"
      ],
      "author": {
        "name": "Kathryn (Jinqi) Chen",
        "email": "65606304+Kathryn-cat@users.noreply.github.com",
        "time": "Tue Jul 21 20:45:15 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Jul 22 11:45:15 2026 +0800"
      },
      "message": "fix(structural): update StructuralVisitor def-region propagation (#681)\n\n## PR summary\n\n  ### Summary\n\nThis PR corrects how `StructuralVisitor` propagates definition-region\nstate while traversing reflected fields. When a non-recursive definition\nis applied to the defined FreeVar identity, its children should be\nvisited with a \"use\" instead of \"def\".\n\nAlso make `StructuralVisitor` constructor a protected member with vtable\nas input."
    },
    {
      "commit": "d6c18a666a79d6261239e134861c749c168c8e6a",
      "tree": "5b9f9cbcfda968850a04e7955424f42531b41834",
      "parents": [
        "503b098fcc66632600112b7f3d36abac4a48f5aa"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Wed Jul 22 11:41:32 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Jul 22 11:41:32 2026 +0800"
      },
      "message": "[FIX] Pack uint1 tensors by data type width (#680)\n\nRemove the legacy scalar `uint1` byte-per-element special case from\n`GetDataSize`, so all sub-byte integer types use the packed size\ncalculation. Add focused coverage for packed `uint1` and byte-sized\n`bool8` tensors."
    },
    {
      "commit": "503b098fcc66632600112b7f3d36abac4a48f5aa",
      "tree": "d9cc95194e6af8ce235b9e1c460b43fe68c2f209",
      "parents": [
        "a39cddaace892987787449632a9c9b39725c1bfa"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Tue Jul 21 10:48:32 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Jul 21 10:48:32 2026 +0800"
      },
      "message": "feat(abi): introduce Arc for required object values (#676)\n\nAdd `Arc\u003cT\u003e` and `make_arc\u003cT\u003e` as one-pointer, reference-counted\ncarriers whose safe API does not admit null. Give Arc bare object\nschemas while representing nullable `ObjectPtr\u003cT\u003e` as `Optional[T]`, and\nreject empty or moved-from Arc values at FFI boundaries.\n\nTeach reflected fields, typed containers, and C++ ABI generation to\npreserve object nullability. Required objects and object-only unions use\nArc, nullable pointer fields use ObjectPtr, and 16-byte optionals use\n`Optional\u003cArc\u003cT\u003e\u003e`.\n\nDocument the ownership and unsafe-initialization rules, preserve\ncontainer exception safety when conversion fails, and extend C++ and\nPython coverage for casts, reflection, structural operations,\nserialization, and generated layouts."
    },
    {
      "commit": "a39cddaace892987787449632a9c9b39725c1bfa",
      "tree": "798e1375e9fe2e97a06d18aac06ff1f7386dcfc1",
      "parents": [
        "0ec8dc8befe3c77742cf8c42181d6e3950aa66f0"
      ],
      "author": {
        "name": "Matthew Brookhart",
        "email": "matthewbrookhart@gmail.com",
        "time": "Mon Jul 20 18:01:46 2026 -0600"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Jul 21 08:01:46 2026 +0800"
      },
      "message": "Improve typing of overloaded methods in stubgen (#678)"
    },
    {
      "commit": "0ec8dc8befe3c77742cf8c42181d6e3950aa66f0",
      "tree": "1ebe3aa03433f9d1a2e6d2a89ad502ed93bbdb13",
      "parents": [
        "d7981f272f270b6f8ff44f0cbf725cb0ca863cae"
      ],
      "author": {
        "name": "Yong Wu",
        "email": "yongcale@gmail.com",
        "time": "Mon Jul 20 15:18:10 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Jul 21 06:18:10 2026 +0800"
      },
      "message": "[FIX] Build dlpack exchange test in a per-test tmp dir to avoid JIT lock hang (#677)\n\nFixes https://github.com/apache/tvm-ffi/issues/641\n\n### root cause\nThe test JIT-compiles a C++ snippet with torch\u0027s\n`cpp_extension.load_inline`, which by default builds into the shared\n`~/.cache/torch_extensions` cache, serialized by torch\u0027s `FileBaton`:\n- `try_acquire()` creates an ordinary lock **file** (`os.open`\n`O_CREAT|O_EXCL`).\n- `wait()` spins on `os.path.exists(lock)` with **no timeout** and no\nstaleness check.\n- `release()` (which deletes the file) only runs on the normal path.\n\nIf a build is killed mid-compile — e.g. a CI time limit sends SIGTERM —\nthe lock file is left behind. On CI where that cache sits on a\npersistent shared filesystem, every subsequent run then waits on the\norphaned lock **forever**.\n\n### Fix\nPass `build_directory\u003dtmp_path` to `load_inline` so each run builds in a\nfresh, unique directory. The baton lock is always fresh, so a killed\nprior run can no longer poison later runs, and the test no longer uses\n(or can be poisoned by) any shared cache — independent of the\nfilesystem."
    },
    {
      "commit": "d7981f272f270b6f8ff44f0cbf725cb0ca863cae",
      "tree": "15704b0659ef2ca82cb2263914002211b55ba2bb",
      "parents": [
        "894419b0021b284d25883519c21e4faadfe8389c"
      ],
      "author": {
        "name": "Yaxing Cai",
        "email": "caiyaxing666@gmail.com",
        "time": "Mon Jul 20 19:40:29 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Jul 20 19:40:29 2026 +0800"
      },
      "message": "ci: drop manylinux2014 wheel builds (#675)\n\nnumpy 2.5.1 ships no glibc-2.17 wheel, so the 2014 test phase compiled\nit from sdist and failed on GCC 10.2.1.\n\nStandardize Linux wheels on manylinux_2_28 (drops the 2014 matrix rows\nin publish/mainline workflows; moves sdist onto the surviving x86_64\nrow; removes the now-obsolete cp313-aarch64 test-skip)."
    },
    {
      "commit": "894419b0021b284d25883519c21e4faadfe8389c",
      "tree": "8d4543eb421f7e5c935953bbabb74eb72f28c923",
      "parents": [
        "a849ee3e5354a47321bceeaf562d97b5e5b3217a"
      ],
      "author": {
        "name": "Kathryn (Jinqi) Chen",
        "email": "65606304+Kathryn-cat@users.noreply.github.com",
        "time": "Sat Jul 18 00:08:09 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Jul 18 15:08:09 2026 +0800"
      },
      "message": "fix(reflection): require exact field and method name matches (#674)\n\nGetFieldInfo and GetMethodInfo previously compared only the stored name\nlength, allowing longer queries with the same prefix to resolve to the\nwrong member. This PR fixes the bug."
    },
    {
      "commit": "a849ee3e5354a47321bceeaf562d97b5e5b3217a",
      "tree": "ccb05e8d36b1b1a23e4c4094b822d5f60372dee4",
      "parents": [
        "21e30c3b1d4421f95fd69a6ba3fd0285c7b69e9c"
      ],
      "author": {
        "name": "Kathryn (Jinqi) Chen",
        "email": "65606304+Kathryn-cat@users.noreply.github.com",
        "time": "Thu Jul 16 16:12:23 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Jul 17 07:12:23 2026 +0800"
      },
      "message": "[FEAT] Add Expected\u003cvoid\u003e specialization (#673)\n\nThis PR adds Expected\u003cvoid\u003e for operations that can succeed without\nreturning a value. Success uses the canonical FFI None representation,\nwhile failures retain ffi::Error.\n\nIt extends ExpectedUnsafe and TypeTraits for Expected\u003cvoid\u003e, adds\nFunction::CallExpected\u003cvoid\u003e support with result validation, and\nincludes tests covering construction, access, FFI conversion, error\npropagation, and typed function integration."
    }
  ],
  "next": "21e30c3b1d4421f95fd69a6ba3fd0285c7b69e9c"
}
