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
This commit is contained in:
parent
b34412ff0f
commit
05c6db6500
5 changed files with 131 additions and 3 deletions
|
|
@ -135,6 +135,21 @@
|
||||||
|
|
||||||
- The experimental strictFuncs feature now disallows a store to the heap via a `ref` or `ptr` indirection.
|
- 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.
|
- - Added the `--legacy:verboseTypeMismatch` switch to get legacy type mismatch error messages.
|
||||||
|
|
||||||
## Standard library additions and changes
|
## Standard library additions and changes
|
||||||
|
|
|
||||||
|
|
@ -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:
|
# 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 addDecl*(c: PContext, sym: PSym, info = sym.info, scope = c.currentScope) {.inline.} =
|
||||||
proc addDeclAt*(c: PContext; scope: PScope, sym: PSym, info: TLineInfo) =
|
proc addDeclAt*(c: PContext; scope: PScope, sym: PSym, info: TLineInfo) =
|
||||||
|
if sym.name.s == "_": return
|
||||||
let conflict = scope.addUniqueSym(sym)
|
let conflict = scope.addUniqueSym(sym)
|
||||||
if conflict != nil:
|
if conflict != nil:
|
||||||
if sym.kind == skModule and conflict.kind == skModule and sym.owner == conflict.owner:
|
if sym.kind == skModule and conflict.kind == skModule and sym.owner == conflict.owner:
|
||||||
|
|
|
||||||
|
|
@ -642,8 +642,9 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
|
||||||
# body by the absence of the sfGenSym flag:
|
# body by the absence of the sfGenSym flag:
|
||||||
for i in 1..<s.typ.n.len:
|
for i in 1..<s.typ.n.len:
|
||||||
let param = s.typ.n[i].sym
|
let param = s.typ.n[i].sym
|
||||||
param.flags.incl sfTemplateParam
|
if param.name.s != "_":
|
||||||
param.flags.excl sfGenSym
|
param.flags.incl sfTemplateParam
|
||||||
|
param.flags.excl sfGenSym
|
||||||
if param.typ.kind != tyUntyped: allUntyped = false
|
if param.typ.kind != tyUntyped: allUntyped = false
|
||||||
else:
|
else:
|
||||||
s.typ = newTypeS(tyProc, c)
|
s.typ = newTypeS(tyProc, c)
|
||||||
|
|
|
||||||
|
|
@ -1372,7 +1372,9 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||||
inc(counter)
|
inc(counter)
|
||||||
if def != nil and def.kind != nkEmpty:
|
if def != nil and def.kind != nkEmpty:
|
||||||
arg.ast = copyTree(def)
|
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 & "'")
|
localError(c.config, a[j].info, "attempt to redefine: '" & arg.name.s & "'")
|
||||||
result.n.add newSymNode(arg)
|
result.n.add newSymNode(arg)
|
||||||
rawAddSon(result, finalType)
|
rawAddSon(result, finalType)
|
||||||
|
|
|
||||||
109
tests/proc/tunderscoreparam.nim
Normal file
109
tests/proc/tunderscoreparam.nim
Normal file
|
|
@ -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()
|
||||||
Loading…
Add table
Add a link
Reference in a new issue