mirror of
https://github.com/nim-lang/Nim.git
synced 2026-06-14 23:53:47 +00:00
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.
(cherry picked from commit 73986c03a1)
This commit is contained in:
@@ -1303,6 +1303,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:
|
||||
|
||||
19
tests/init/t25857.nim
Normal file
19
tests/init/t25857.nim
Normal file
@@ -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
|
||||
Reference in New Issue
Block a user