From 73986c03a10c1bc5db1edb5750f6841c206b89bf Mon Sep 17 00:00:00 2001 From: Corey Leavitt Date: Mon, 1 Jun 2026 23:07:44 -0600 Subject: [PATCH] fixes #25857; don't treat typeof(result) as a use-before-init of result (#25858) fixes #25857 ## Bug `typeof(result)` inside the expression that builds `result` gets counted as a read of `result` before it's set. On a `{.requiresInit.}` return type that's a hard error ("'result' requires explicit initialization"). `typeof` never evaluates its operand, so it's a false positive. On 2.2.4 it compiles, but the same line still emits a bogus `ProveInit` warning, so no released version gets it right. Regression from #25151. That PR made a used-before-init `requiresInit` result a hard error instead of a warning, which is correct on its own. The side effect was that this old false-positive warning became a build error. ## Root cause `track` in `compiler/sempass2.nim` has no arm for `nkTypeOfExpr`, so it hits the default that recurses into every child, reaches the `result` `nkSym` inside the `typeof`, and calls `useVar`. `sizeof`/`compiles`/`declared` don't hit this because they fold to a constant before `track` runs. A `typeof(result)` typedesc argument survives into `track`. ## Fix Skip `nkTypeOfExpr` in `track`. Its operand is never evaluated, so it isn't a definite-assignment use. After the patch there's no error and no warning here, even with `--warnings:on`. The #25151 check is untouched: a real use of `result` before init is a plain `nkSym`, not inside a `typeof`, so it still reaches `useVar`. ## Test `tests/init/t25857.nim`, a positive test that compiles and prints `1`. ## Checks - Repro compiles and runs on patched 2.2.6 and patched devel. - `tests/errmsgs/t25117.nim` still fails as expected. A real `xxx(result)` before init still errors. - `testament cat init` and `testament cat errmsgs` green on patched devel (55 tests, 0 failures), including the `--warningAsError:ProveInit` tests. - Bisect: parent `1ab68797` good, `576c4018` (#25151) bad. --- compiler/sempass2.nim | 2 ++ tests/init/t25857.nim | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 tests/init/t25857.nim diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index f1e2e69cbe..7b2be510f9 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -1308,6 +1308,8 @@ proc allowCStringConv(n: PNode): bool = proc track(tracked: PEffects, n: PNode) = case n.kind + of nkTypeOfExpr: + discard "typeof() never evaluates its operand; not a definite-assignment use" of nkSym: useVar(tracked, n) if n.sym.typ != nil and tfHasAsgn in n.sym.typ.flags: diff --git a/tests/init/t25857.nim b/tests/init/t25857.nim new file mode 100644 index 0000000000..5e71481f5e --- /dev/null +++ b/tests/init/t25857.nim @@ -0,0 +1,19 @@ +discard """ + output: "1" +""" + +# Regression for #25857: `typeof(result)` inside `result`'s initializer must not be +# treated as a use-before-initialization of `result`. `typeof` is a type query and +# never evaluates its operand, so this compiles and runs. +# (Before the fix this errored: "'result' requires explicit initialization" on +# {.requiresInit.} return types, breaking the `ok(typeof(result), v)` idiom.) + +type Box[T] {.requiresInit.} = object + v: T + +func make[T](_: typedesc[Box[T]], v: T): Box[T] = Box[T](v: v) + +proc f(): Box[int] = + make(typeof(result), 1) + +echo f().v