Skip to content

Commit 9c87cd8

Browse files
committed
add decls.byLent for overload resolution
1 parent cbcaf2b commit 9c87cd8

File tree

5 files changed

+62
-43
lines changed

5 files changed

+62
-43
lines changed

changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@
119119
- add `macros.extractDocCommentsAndRunnables` helper
120120

121121
- `strformat.fmt` and `strformat.&` support `= specifier`. `fmt"{expr=}"` now expands to `fmt"expr={expr}"`.
122+
- Add `decls.byLent` to turn an argument into a let param, useful for overload resolution.
122123

123124
## Language changes
124125
- In the newruntime it is now allowed to assign to the discriminator field

compiler/options.nim

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import
1313

1414
from terminal import isatty
1515
from times import utc, fromUnix, local, getTime, format, DateTime
16+
from std/decls import byLent
1617

1718
const
1819
hasTinyCBackend* = defined(tinyc)
@@ -619,12 +620,6 @@ proc shortenDir*(conf: ConfigRef; dir: string): string {.
619620
return substr(dir, prefix.len)
620621
result = dir
621622

622-
proc removeTrailingDirSep*(path: string): string =
623-
if (path.len > 0) and (path[^1] == DirSep):
624-
result = substr(path, 0, path.len - 2)
625-
else:
626-
result = path
627-
628623
proc disableNimblePath*(conf: ConfigRef) =
629624
incl conf.globalOptions, optNoNimblePath
630625
conf.lazyPaths.setLen(0)
@@ -653,7 +648,7 @@ proc getNimcacheDir*(conf: ConfigRef): AbsoluteDir =
653648
(if isDefined(conf, "release") or isDefined(conf, "danger"): "_r" else: "_d"))
654649

655650
proc pathSubs*(conf: ConfigRef; p, config: string): string =
656-
let home = removeTrailingDirSep(os.getHomeDir())
651+
let home = os.getHomeDir().normalizePathEnd
657652
result = unixToNativePath(p % [
658653
"nim", getPrefixDir(conf).string,
659654
"lib", conf.libpath.string,
@@ -668,7 +663,7 @@ iterator nimbleSubs*(conf: ConfigRef; p: string): string =
668663
let pl = p.toLowerAscii
669664
if "$nimblepath" in pl or "$nimbledir" in pl:
670665
for i in countdown(conf.nimblePaths.len-1, 0):
671-
let nimblePath = removeTrailingDirSep(conf.nimblePaths[i].string)
666+
let nimblePath = conf.nimblePaths[i].string.byLent.normalizePathEnd
672667
yield p % ["nimblepath", nimblePath, "nimbledir", nimblePath]
673668
else:
674669
yield p

lib/std/decls.nim

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1-
# see `semLowerLetVarCustomPragma` for compiler support that enables these
2-
# lowerings
1+
#[
2+
keep this module dependency-light to be usable in low level modules.
3+
4+
see `semLowerLetVarCustomPragma` for compiler support that enables these
5+
lowerings
6+
7+
Experimental module,
8+
]#
39

410
template byaddr*(lhs, typ, ex) =
511
## Allows a syntax for lvalue reference, exact analog to
@@ -17,3 +23,15 @@ template byaddr*(lhs, typ, ex) =
1723
else:
1824
let tmp: ptr typ = addr(ex)
1925
template lhs: untyped = tmp[]
26+
27+
proc byLent*[T](a: T): lent T {.inline.} =
28+
## Transforms `a` into a let param without copying; this is useful for overload
29+
## resolution
30+
runnableExamples:
31+
proc fn(a: int): int = result = a*2
32+
proc fn(a: var int) = a = a*2
33+
var x = 3
34+
# x = fn(x) # would give: Error: expression 'fn(x)' has no type (or is ambiguous)
35+
x = fn(x.byLent) # works
36+
doAssert x == 3*2
37+
a

tests/js/taddr.nim

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,11 @@ doAssert(someGlobalPtr[] == 5)
7878
someGlobalPtr[] = 10
7979
doAssert(someGlobal == 10)
8080

81+
from std/decls import byLent
82+
8183
block:
8284
# issue #14576
8385
# lots of these used to give: Error: internal error: genAddr: 2
84-
proc byLent[T](a: T): lent T = a
8586
proc byPtr[T](a: T): ptr T = a.unsafeAddr
8687

8788
block:
@@ -90,14 +91,10 @@ block:
9091
doAssert (x,y) == a
9192

9293
block:
93-
when defined(c) and defined(release):
94-
# bug; pending https://github.com/nim-lang/Nim/issues/14578
95-
discard
96-
else:
97-
let a = 10
98-
doAssert byLent(a) == 10
99-
let a2 = byLent(a)
100-
doAssert a2 == 10
94+
let a = 10
95+
doAssert byLent(a) == 10
96+
let a2 = byLent(a)
97+
doAssert a2 == 10
10198

10299
block:
103100
let a = [11,12]

tests/stdlib/tdecls.nim

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import std/decls
22

3-
block:
3+
block: # byaddr
44
var s = @[10,11,12]
55
var a {.byaddr.} = s[0]
66
a+=100
@@ -34,23 +34,9 @@ block:
3434
doAssert compiles(block:
3535
var b2 {.byaddr.}: int = s[2])
3636

37-
## We can define custom pragmas in user code
38-
template byUnsafeAddr(lhs, typ, expr) =
39-
when typ is type(nil):
40-
let tmp = unsafeAddr(expr)
41-
else:
42-
let tmp: ptr typ = unsafeAddr(expr)
43-
template lhs: untyped = tmp[]
44-
45-
block:
46-
let s = @["foo", "bar"]
47-
let a {.byUnsafeAddr.} = s[0]
48-
doAssert a == "foo"
49-
doAssert a[0].unsafeAddr == s[0][0].unsafeAddr
50-
51-
block: # nkAccQuoted
52-
# shows using a keyword, which requires nkAccQuoted
53-
template `cast`(lhs, typ, expr) =
37+
block: # custom var pragmas
38+
## We can define custom pragmas in user code
39+
template byUnsafeAddr(lhs, typ, expr) =
5440
when typ is type(nil):
5541
let tmp = unsafeAddr(expr)
5642
else:
@@ -59,12 +45,34 @@ block: # nkAccQuoted
5945

6046
block:
6147
let s = @["foo", "bar"]
62-
let a {.`byUnsafeAddr`.} = s[0]
48+
let a {.byUnsafeAddr.} = s[0]
6349
doAssert a == "foo"
6450
doAssert a[0].unsafeAddr == s[0][0].unsafeAddr
6551

66-
block:
67-
let s = @["foo", "bar"]
68-
let a {.`cast`.} = s[0]
69-
doAssert a == "foo"
70-
doAssert a[0].unsafeAddr == s[0][0].unsafeAddr
52+
block: # nkAccQuoted
53+
# shows using a keyword, which requires nkAccQuoted
54+
template `cast`(lhs, typ, expr) =
55+
when typ is type(nil):
56+
let tmp = unsafeAddr(expr)
57+
else:
58+
let tmp: ptr typ = unsafeAddr(expr)
59+
template lhs: untyped = tmp[]
60+
61+
block:
62+
let s = @["foo", "bar"]
63+
let a {.`byUnsafeAddr`.} = s[0]
64+
doAssert a == "foo"
65+
doAssert a[0].unsafeAddr == s[0][0].unsafeAddr
66+
67+
block:
68+
let s = @["foo", "bar"]
69+
let a {.`cast`.} = s[0]
70+
doAssert a == "foo"
71+
doAssert a[0].unsafeAddr == s[0][0].unsafeAddr
72+
73+
block: # byLent
74+
proc fn(a: int): int = result = a*2
75+
proc fn(a: var int) = a = a*5
76+
var x = 3
77+
x = fn(x.byLent)
78+
doAssert x == 3*2

0 commit comments

Comments
 (0)