diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 15d8b14fe7..32c98cdb31 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -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) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 35901ed960..9c84b721ad 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -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) diff --git a/lib/system.nim b/lib/system.nim index c76d096426..63989b1502 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -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]) diff --git a/lib/system/indices.nim b/lib/system/indices.nim index 6230b36788..8f20af5ec5 100644 --- a/lib/system/indices.nim +++ b/lib/system/indices.nim @@ -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.. 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 diff --git a/tests/errmsgs/tsso_string_index_var.nim b/tests/errmsgs/tsso_string_index_var.nim new file mode 100644 index 0000000000..401491e0a5 --- /dev/null +++ b/tests/errmsgs/tsso_string_index_var.nim @@ -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])