open new scope for const values (#24084)

fixes #5395

Previously values of `const` statements used the same scope as the
`const` statement itself, meaning variables could be declared inside
them and referred to in other statements in the same block. Now each
`const` value opens its own scope, so any variable declared in the value
of a constant can only be accessed for that constant.

We could change this to open a new scope for the `const` *section*
rather than each constant, so the variables can be used in other
constants, but I'm not sure if this is sound.
This commit is contained in:
metagn
2024-09-09 12:29:30 +03:00
committed by GitHub
parent 9ff0333a4c
commit a6595e5b49
5 changed files with 31 additions and 0 deletions

View File

@@ -41,6 +41,16 @@
bar[int]() # before: (1.0, "abc"), now: type mismatch, missing generic parameter
```
- `const` values now open a new scope for each constant, meaning symbols
declared in them can no longer be used outside or in the value of
other constants.
```nim
const foo = (var a = 1; a)
const bar = a # error
let baz = a # error
```
## Standard library additions and changes
[//]: # "Changes:"

View File

@@ -985,6 +985,7 @@ proc semConst(c: PContext, n: PNode): PNode =
var typFlags: TTypeAllowedFlags = {}
# don't evaluate here since the type compatibility check below may add a converter
openScope(c)
var def = semExprWithType(c, a[^1], {efTypeAllowed}, typ)
if def.kind == nkSym and def.sym.kind in {skTemplate, skMacro}:
@@ -1011,6 +1012,7 @@ proc semConst(c: PContext, n: PNode): PNode =
if c.matchedConcept != nil:
typFlags.incl taConcept
typeAllowedCheck(c, a.info, typ, skConst, typFlags)
closeScope(c)
if a.kind == nkVarTuple:
# generate new section from tuple unpacking and embed it into this one

View File

@@ -3220,6 +3220,15 @@ A const section declares constants whose values are constant expressions:
Once declared, a constant's symbol can be used as a constant expression.
The value part of a constant declaration opens a new scope for each constant,
so no symbols declared in the constant value are accessible outside of it.
```nim
const foo = (var a = 1; a)
const bar = a # error
let baz = a # error
```
See [Constants and Constant Expressions] for details.
Static statement/expression

View File

@@ -0,0 +1,5 @@
# issue #5395
const a = (var b = 3; b)
echo b #[tt.Error
^ undeclared identifier: 'b']#

View File

@@ -0,0 +1,5 @@
const
a = (var x = 3; x)
# should we allow this?
b = x #[tt.Error
^ undeclared identifier: 'x']#