mirror of
https://github.com/nim-lang/Nim.git
synced 2026-05-24 21:59:52 +00:00
SSO strings: bugfix (#25810)
This commit is contained in:
@@ -637,6 +637,11 @@ proc renderNotLValue*(n: PNode): string =
|
||||
elif n.kind in {nkHiddenStdConv, nkHiddenSubConv} and n.len == 2:
|
||||
result = typeToString(n.typ.skipTypes(abstractVar)) & "(" & result & ")"
|
||||
|
||||
proc isSsoStringIndex*(conf: ConfigRef; n: PNode): bool =
|
||||
result = conf.usesSso() and n.kind == nkBracketExpr and n.len >= 1 and
|
||||
n[0].typ != nil and
|
||||
n[0].typ.skipTypes(abstractVar + abstractInst - {tyTypeDesc}).kind == tyString
|
||||
|
||||
proc isAssignable(c: PContext, n: PNode): TAssignableResult =
|
||||
result = parampatterns.isAssignable(c.p.owner, n)
|
||||
|
||||
|
||||
@@ -809,6 +809,10 @@ proc trackOperandForIndirectCall(tracked: PEffects, n: PNode, formals: PType; ar
|
||||
markSideEffect(tracked, a, n.info)
|
||||
let paramType = if formals != nil and argIndex < formals.signatureLen: formals[argIndex] else: nil
|
||||
if paramType != nil and paramType.kind in {tyVar}:
|
||||
let arg = n.skipAddr()
|
||||
if isSsoStringIndex(tracked.config, arg):
|
||||
localError(tracked.config, arg.info,
|
||||
"expression '$1' is immutable, not 'var'" % renderNotLValue(arg))
|
||||
invalidateFacts(tracked.guards, n)
|
||||
if n.kind == nkSym and isLocalSym(tracked, n.sym):
|
||||
makeVolatile(tracked, n.sym)
|
||||
|
||||
@@ -2694,7 +2694,9 @@ when hasAlloc or defined(nimscript):
|
||||
setLen(x, xl+item.len)
|
||||
var j = xl-1
|
||||
while j >= i:
|
||||
when defined(gcArc) or defined(gcOrc) or defined(gcYrc) or defined(gcAtomicArc):
|
||||
when defined(nimsso):
|
||||
x[j+item.len] = x[j]
|
||||
elif defined(gcArc) or defined(gcOrc) or defined(gcYrc) or defined(gcAtomicArc):
|
||||
x[j+item.len] = move x[j]
|
||||
else:
|
||||
shallowCopy(x[j+item.len], x[j])
|
||||
|
||||
@@ -59,16 +59,35 @@ template `[]=`*(s: string; i: int; val: char) = arrPut(s, i, val)
|
||||
template `^^`(s, i: untyped): untyped =
|
||||
(when i is BackwardsIndex: s.len - int(i) else: int(i))
|
||||
|
||||
template spliceImpl(s, a, L, b: typed): untyped =
|
||||
template spliceStringImpl(s, a, L, b: typed): untyped =
|
||||
# make room for additional elements or cut:
|
||||
var shift = b.len - max(0,L) # ignore negative slice size
|
||||
var newLen = s.len + shift
|
||||
if shift > 0:
|
||||
# enlarge:
|
||||
setLen(s, newLen)
|
||||
for i in countdown(newLen-1, a+b.len): movingCopy(s[i], s[i-shift])
|
||||
for i in countdown(newLen-1, a+b.len):
|
||||
s[i] = s[i-shift]
|
||||
else:
|
||||
for i in countup(a+b.len, newLen-1): movingCopy(s[i], s[i-shift])
|
||||
for i in countup(a+b.len, newLen-1):
|
||||
s[i] = s[i-shift]
|
||||
# cut down:
|
||||
setLen(s, newLen)
|
||||
# fill the hole:
|
||||
for i in 0 ..< b.len: s[a+i] = b[i]
|
||||
|
||||
template spliceSeqImpl(s, a, L, b: typed): untyped =
|
||||
# make room for additional elements or cut:
|
||||
var shift = b.len - max(0,L) # ignore negative slice size
|
||||
var newLen = s.len + shift
|
||||
if shift > 0:
|
||||
# enlarge:
|
||||
setLen(s, newLen)
|
||||
for i in countdown(newLen-1, a+b.len):
|
||||
movingCopy(s[i], s[i-shift])
|
||||
else:
|
||||
for i in countup(a+b.len, newLen-1):
|
||||
movingCopy(s[i], s[i-shift])
|
||||
# cut down:
|
||||
setLen(s, newLen)
|
||||
# fill the hole:
|
||||
@@ -102,7 +121,7 @@ proc `[]=`*[T, U: Ordinal](s: var string, x: HSlice[T, U], b: string) {.systemRa
|
||||
if L == b.len:
|
||||
for i in 0..<L: s[i+a] = b[i]
|
||||
else:
|
||||
spliceImpl(s, a, L, b)
|
||||
spliceStringImpl(s, a, L, b)
|
||||
|
||||
proc `[]`*[Idx, T; U, V: Ordinal](a: array[Idx, T], x: HSlice[U, V]): seq[T] {.systemRaisesDefect.} =
|
||||
## Slice operation for arrays.
|
||||
@@ -162,4 +181,4 @@ proc `[]=`*[T; U, V: Ordinal](s: var seq[T], x: HSlice[U, V], b: openArray[T]) {
|
||||
if L == b.len:
|
||||
for i in 0 ..< L: s[i+a] = b[i]
|
||||
else:
|
||||
spliceImpl(s, a, L, b)
|
||||
spliceSeqImpl(s, a, L, b)
|
||||
|
||||
@@ -224,13 +224,14 @@ proc cmpStringPtrs(a, b: ptr SmallString): int {.inline.} =
|
||||
minLen - AlwaysAvail)
|
||||
if result == 0: result = aslen - bslen
|
||||
return
|
||||
# At least one is long. Hot prefix: inlinePtr[0..AlwaysAvail-1] mirrors heap data.
|
||||
let pfxLen = min(min(aslen, bslen), AlwaysAvail)
|
||||
result = cmpInlineBytes(inlinePtrOf(a), inlinePtrOf(b), pfxLen)
|
||||
if result != 0: return
|
||||
# At least one is long. Hot prefix mirrors heap data, but only up to fullLen:
|
||||
# shrinking can leave stale bytes in the inline cache past the logical length.
|
||||
let la = if aslen > PayloadSize: a.more.fullLen else: aslen
|
||||
let lb = if bslen > PayloadSize: b.more.fullLen else: bslen
|
||||
let minLen = min(la, lb)
|
||||
let pfxLen = min(minLen, AlwaysAvail)
|
||||
result = cmpInlineBytes(inlinePtrOf(a), inlinePtrOf(b), pfxLen)
|
||||
if result != 0: return
|
||||
if minLen <= AlwaysAvail:
|
||||
result = la - lb
|
||||
return
|
||||
|
||||
13
tests/errmsgs/tsso_string_index_var.nim
Normal file
13
tests/errmsgs/tsso_string_index_var.nim
Normal file
@@ -0,0 +1,13 @@
|
||||
discard """
|
||||
cmd: "nim check --strings:sso --mm:orc --hints:off $file"
|
||||
action: "reject"
|
||||
nimout: '''
|
||||
tsso_string_index_var.nim(13, 12) Error: expression 's[0]' is immutable, not 'var'
|
||||
'''
|
||||
"""
|
||||
|
||||
proc passByVar(c: var char) =
|
||||
c = 'x'
|
||||
|
||||
var s = "abc"
|
||||
passByVar(s[0])
|
||||
Reference in New Issue
Block a user