Skip to content

Commit

Permalink
underscores for routine parameters (nim-lang#21192)
Browse files Browse the repository at this point in the history
* underscores for routine parameters

fixes nim-lang#13443, fixes nim-lang#13804, refs nim-lang#21121

* add changelog + more tests

* support generics and ensure inferred lambdas work
  • Loading branch information
metagn authored and bung87 committed Jul 29, 2023
1 parent 7517aac commit 7f36ecf
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 3 deletions.
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()

0 comments on commit 7f36ecf

Please sign in to comment.