diff options
author | metagn <metagngn@gmail.com> | 2023-01-08 08:49:49 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-01-08 06:49:49 +0100 |
commit | 05c6db6500de0551882a2d6cc612c9afb6ca674c (patch) | |
tree | 2b7492ae69524ed95384a160d048a573f969cf84 | |
parent | b34412ff0fb450278d8c93f6e5d7bf0e8d3f0a0b (diff) | |
download | Nim-05c6db6500de0551882a2d6cc612c9afb6ca674c.tar.gz |
underscores for routine parameters (#21192)
* underscores for routine parameters fixes #13443, fixes #13804, refs #21121 * add changelog + more tests * support generics and ensure inferred lambdas work
-rw-r--r-- | changelogs/changelog_2_0_0.md | 15 | ||||
-rw-r--r-- | compiler/lookups.nim | 1 | ||||
-rw-r--r-- | compiler/semtempl.nim | 5 | ||||
-rw-r--r-- | compiler/semtypes.nim | 4 | ||||
-rw-r--r-- | tests/proc/tunderscoreparam.nim | 109 |
5 files changed, 131 insertions, 3 deletions
diff --git a/changelogs/changelog_2_0_0.md b/changelogs/changelog_2_0_0.md index 9ff493b54..c8427cc2a 100644 --- a/changelogs/changelog_2_0_0.md +++ b/changelogs/changelog_2_0_0.md @@ -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 diff --git a/compiler/lookups.nim b/compiler/lookups.nim index d50fc6e27..3f4fcb4d0 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -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: diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index 0016e9edf..3b2f2dd9e 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -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) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index a8b147eef..844bc2070 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -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) diff --git a/tests/proc/tunderscoreparam.nim b/tests/proc/tunderscoreparam.nim new file mode 100644 index 000000000..c2f6cf8ad --- /dev/null +++ b/tests/proc/tunderscoreparam.nim @@ -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() |