Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

underscores for routine parameters #21192

Merged
merged 4 commits into from
Jan 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions changelogs/changelog_2_0_0.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,21 @@

- The experimental strictFuncs feature now disallows a store to the heap via a `ref` or `ptr` indirection.

- Underscores (`_`) as routine parameters are now ignored and cannot be used in the routine body.
The following code now does not compile:

```nim
proc foo(_: int): int = _ + 1
echo foo(1)
```

Instead, the following code now compiles:

```nim
proc foo(_, _: int): int = 123
echo foo(1, 2)
```

- - Added the `--legacy:verboseTypeMismatch` switch to get legacy type mismatch error messages.

## Standard library additions and changes
Expand Down
1 change: 1 addition & 0 deletions compiler/lookups.nim
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ proc wrongRedefinition*(c: PContext; info: TLineInfo, s: string;
# xxx pending bootstrap >= 1.4, replace all those overloads with a single one:
# proc addDecl*(c: PContext, sym: PSym, info = sym.info, scope = c.currentScope) {.inline.} =
proc addDeclAt*(c: PContext; scope: PScope, sym: PSym, info: TLineInfo) =
if sym.name.s == "_": return
let conflict = scope.addUniqueSym(sym)
if conflict != nil:
if sym.kind == skModule and conflict.kind == skModule and sym.owner == conflict.owner:
Expand Down
5 changes: 3 additions & 2 deletions compiler/semtempl.nim
Original file line number Diff line number Diff line change
Expand Up @@ -642,8 +642,9 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
# body by the absence of the sfGenSym flag:
for i in 1..<s.typ.n.len:
let param = s.typ.n[i].sym
param.flags.incl sfTemplateParam
param.flags.excl sfGenSym
if param.name.s != "_":
param.flags.incl sfTemplateParam
param.flags.excl sfGenSym
if param.typ.kind != tyUntyped: allUntyped = false
else:
s.typ = newTypeS(tyProc, c)
Expand Down
4 changes: 3 additions & 1 deletion compiler/semtypes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1372,7 +1372,9 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
inc(counter)
if def != nil and def.kind != nkEmpty:
arg.ast = copyTree(def)
if containsOrIncl(check, arg.name.id):
if arg.name.s == "_":
arg.flags.incl(sfGenSym)
elif containsOrIncl(check, arg.name.id):
localError(c.config, a[j].info, "attempt to redefine: '" & arg.name.s & "'")
result.n.add newSymNode(arg)
rawAddSon(result, finalType)
Expand Down
109 changes: 109 additions & 0 deletions tests/proc/tunderscoreparam.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
discard """
targets: "c cpp js"
"""

import std/[assertions, sequtils]

proc test() =
block:
proc ok(_, _, a: int): int =
doAssert not compiles(_)
a
doassert ok(4, 2, 5) == 5

block:
proc ok(_: int, _: int, a: int): int = a
doAssert ok(4, 2, 5) == 5

block:
proc ok(_: int, _: float, a: int): int = a
doAssert ok(1, 2.0, 5) == 5

block:
proc ok(_: int, _: float, _: string, a: int): int = a
doAssert ok(1, 2.6, "5", 5) == 5

block:
proc ok[T](_, _, a: T): T =
doAssert not compiles(_)
a
doAssert ok(4, 2, 5) == 5
doAssert ok("a", "b", "c") == "c"
doAssert not compiles(ok(1, 2, "a"))

block:
let ok = proc (_, _, a: int): int =
doAssert not compiles(_)
a
doAssert ok(4, 2, 5) == 5

block:
proc foo(lam: proc (_, _, a: int): int): int =
lam(4, 2, 5)
doAssert foo(proc (_, _, a: auto): auto =
doAssert not compiles(_)
a) == 5

block:
iterator fn(_, _: int, c: int): int = yield c
doAssert toSeq(fn(1,2,3)) == @[3]

block:
template ok(_, _, a: int): int = a
doAssert ok(4, 2, 5) == 5

block:
doAssert not (compiles do:
template bad(_: int): int = _
discard bad(3))

block:
template ok(_: int, _: int, a: int): int = a
doAssert ok(4, 2, 5) == 5

block:
template ok(_: int, _: float, a: int): int = a
doAssert ok(1, 2.0, 5) == 5

block:
template ok(_: int, _: float, _: string, a: int): int = a
doAssert ok(1, 2.6, "5", 5) == 5

block:
template main2() =
iterator fn(_, _: int, c: int): int = yield c
main2()

block:
template main =
proc foo(_: int) =
let a = _
doAssert not compiles(main())

proc closureTest() =
var x = 0

block:
proc foo(_, _: int) = x += 5

foo(1, 2)
doAssert x == 5

block:
proc foo(_: int, _: float) = x += 5

foo(1, 2)
doAssert x == 10

block:
proc foo(_: int, _: float, _: string) = x += 5

foo(1, 2, "5")
doAssert x == 15

static: test()
test()

when not defined(js):
static: closureTest()
closureTest()