summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/seminst.nim2
-rw-r--r--compiler/semstmts.nim1
-rw-r--r--compiler/semtypinst.nim16
-rw-r--r--lib/core/seqs.nim2
-rw-r--r--lib/core/strs.nim1
-rw-r--r--tests/destructor/tgcdestructors.nim65
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)