diff options
-rw-r--r-- | compiler/seminst.nim | 2 | ||||
-rw-r--r-- | compiler/semstmts.nim | 1 | ||||
-rw-r--r-- | compiler/semtypinst.nim | 16 | ||||
-rw-r--r-- | lib/core/seqs.nim | 2 | ||||
-rw-r--r-- | lib/core/strs.nim | 1 | ||||
-rw-r--r-- | tests/destructor/tgcdestructors.nim | 65 |
6 files changed, 85 insertions, 2 deletions
diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 09991048e..51303d1b5 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -306,7 +306,9 @@ proc instantiateProcType(c: PContext, pt: TIdTable, resetIdTable(cl.symMap) resetIdTable(cl.localCache) + cl.isReturnType = true result.sons[0] = replaceTypeVarsT(cl, result.sons[0]) + cl.isReturnType = false result.n.sons[0] = originalParams[0].copyTree if result.sons[0] != nil: propagateToOwner(result, result.sons[0]) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index aa0230f2f..c16de0723 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -481,6 +481,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = if typ == nil: continue typeAllowedCheck(c.config, a.info, typ, symkind, if c.matchedConcept != nil: {taConcept} else: {}) liftTypeBoundOps(c.graph, typ, a.info) + instAllTypeBoundOp(c, a.info) var tup = skipTypes(typ, {tyGenericInst, tyAlias, tySink}) if a.kind == nkVarTuple: if tup.kind != tyTuple: diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 002f4f402..483588e6b 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -88,6 +88,7 @@ type allowMetaTypes*: bool # allow types such as seq[Number] # i.e. the result contains unresolved generics skipTypedesc*: bool # wether we should skip typeDescs + isReturnType*: bool owner*: PSym # where this instantiation comes from recursionLimit: int @@ -594,6 +595,21 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = eraseVoidParams(result) skipIntLiteralParams(result) + of tySequence: + if cl.isReturnType and cl.c.config.selectedGc == gcDestructors and result.destructor.isNil and + result[0].kind != tyEmpty: + let s = cl.c.graph.sysTypes[tySequence] + var old = copyType(s, s.owner, keepId=false) + # Remove the 'T' parameter from tySequence: + old.sons.setLen 0 + old.n = nil + old.flags = {tfHasAsgn} + old.addSonSkipIntLit result[0] + result.destructor = old.destructor + result.assignment = old.assignment + result.sink = old.sink + cl.c.typesWithOps.add((result, old)) + else: discard else: # If this type doesn't refer to a generic type we may still want to run it diff --git a/lib/core/seqs.nim b/lib/core/seqs.nim index 20ea9e035..2b39c6b41 100644 --- a/lib/core/seqs.nim +++ b/lib/core/seqs.nim @@ -118,7 +118,7 @@ proc shrink*[T](x: var seq[T]; newLen: Natural) = when not supportsCopyMem(T): for i in countdown(x.len - 1, newLen - 1): `=destroy`(x[i]) - + # XXX This is wrong for const seqs that were moved into 'x'! cast[ptr NimSeqV2[T]](addr x).len = newLen proc grow*[T](x: var seq[T]; newLen: Natural; value: T) = diff --git a/lib/core/strs.nim b/lib/core/strs.nim index e55c88493..406efe5a1 100644 --- a/lib/core/strs.nim +++ b/lib/core/strs.nim @@ -164,6 +164,7 @@ proc mnewString(len: int): NimStringV2 {.compilerProc.} = proc setLengthStrV2(s: var NimStringV2, newLen: int) {.compilerRtl.} = if newLen > s.len: prepareAdd(s, newLen - s.len) + # XXX This is wrong for const strings that got moved into 's'! s.len = newLen # this also only works because the destructor # looks at s.p and not s.len diff --git a/tests/destructor/tgcdestructors.nim b/tests/destructor/tgcdestructors.nim index 1ae2b2549..f83007470 100644 --- a/tests/destructor/tgcdestructors.nim +++ b/tests/destructor/tgcdestructors.nim @@ -3,7 +3,7 @@ discard """ output: '''hi ho ha -1 1''' +7 7''' """ import allocators @@ -21,6 +21,69 @@ const for t in test: echo t +type + InterpolatedKind* = enum + ikStr, ## ``str`` part of the interpolated string + ikDollar, ## escaped ``$`` part of the interpolated string + ikVar, ## ``var`` part of the interpolated string + ikExpr ## ``expr`` part of the interpolated string + +iterator interpolatedFragments*(s: string): tuple[kind: InterpolatedKind, + value: string] = + var i = 0 + var kind: InterpolatedKind + while true: + var j = i + if j < s.len and s[j] == '$': + if j+1 < s.len and s[j+1] == '{': + inc j, 2 + var nesting = 0 + block curlies: + while j < s.len: + case s[j] + of '{': inc nesting + of '}': + if nesting == 0: + inc j + break curlies + dec nesting + else: discard + inc j + raise newException(ValueError, + "Expected closing '}': " & substr(s, i, s.high)) + inc i, 2 # skip ${ + kind = ikExpr + elif j+1 < s.len and s[j+1] in {'A'..'Z', 'a'..'z', '_'}: + inc j, 2 + while j < s.len and s[j] in {'A'..'Z', 'a'..'z', '0'..'9', '_'}: inc(j) + inc i # skip $ + kind = ikVar + elif j+1 < s.len and s[j+1] == '$': + inc j, 2 + inc i # skip $ + kind = ikDollar + else: + raise newException(ValueError, + "Unable to parse a varible name at " & substr(s, i, s.high)) + else: + while j < s.len and s[j] != '$': inc j + kind = ikStr + if j > i: + # do not copy the trailing } for ikExpr: + yield (kind, substr(s, i, j-1-ord(kind == ikExpr))) + else: + break + i = j + +let input = "$test{} $this is ${an{ example}} " +let expected = @[(ikVar, "test"), (ikStr, "{} "), (ikVar, "this"), + (ikStr, " is "), (ikExpr, "an{ example}"), (ikStr, " ")] +var i = 0 +for s in interpolatedFragments(input): + doAssert s == expected[i] + inc i + + #echo s let (a, d) = allocCounters() cprintf("%ld %ld\n", a, d) |