summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2016-08-25 16:35:33 +0200
committerGitHub <noreply@github.com>2016-08-25 16:35:33 +0200
commit56c31a51d0fe15b3e039701b99fbe869fe933d11 (patch)
treeb8e582c6a31b4567ccfb093bc8e6fe901a899e40
parentf1e4d8ed74549a868be58c15fc8cfe04159c52fd (diff)
parentb0c12a7dc4065372960a696907947812b4c01e0d (diff)
downloadNim-56c31a51d0fe15b3e039701b99fbe869fe933d11.tar.gz
Merge pull request #4633 from mbaulch/pickbestcand_faster_inlined
Optimise pickBestCandidate: reduce heap allocations.
-rw-r--r--compiler/semcall.nim104
1 files changed, 43 insertions, 61 deletions
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index 97209167d..b83872fe9 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -40,67 +40,49 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
                        filter: TSymKinds,
                        best, alt: var TCandidate,
                        errors: var CandidateErrors) =
-  var o: TOverloadIter
-  # thanks to the lazy semchecking for operands, we need to iterate over the
-  # symbol table *before* any call to 'initCandidate' which might invoke
-  # semExpr which might modify the symbol table in cases like
-  # 'init(a, 1, (var b = new(Type2); b))'.
-  var symx = initOverloadIter(o, c, headSymbol)
-  let symScope = o.lastOverloadScope
-
-  var syms: seq[tuple[a: PSym, b: int]] = @[]
-  while symx != nil:
-    if symx.kind in filter:
-      syms.add((symx, o.lastOverloadScope))
-    symx = nextOverloadIter(o, c, headSymbol)
-  if syms.len == 0:
-    when false:
-      if skIterator notin filter:
-        # also try iterators, but these are 2nd class:
-        symx = initOverloadIter(o, c, headSymbol)
-        while symx != nil:
-          if symx.kind == skIterator:
-            syms.add((symx, 100))
-          symx = nextOverloadIter(o, c, headSymbol)
-        if syms.len == 0: return
-    else:
-      return
-
-  var z: TCandidate
-  initCandidate(c, best, syms[0][0], initialBinding, symScope)
-  initCandidate(c, alt, syms[0][0], initialBinding, symScope)
-  best.state = csNoMatch
-
-  for i in 0 .. <syms.len:
-    let sym = syms[i][0]
-    determineType(c, sym)
-    initCandidate(c, z, sym, initialBinding, syms[i][1])
-
-    #if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140:
-    #  gDebug = true
-    matches(c, n, orig, z)
-    if errors != nil:
-      errors.safeAdd((sym, int z.mutabilityProblem))
-      if z.errors != nil:
-        for err in z.errors:
-          errors.add(err)
-    if z.state == csMatch:
-      # little hack so that iterators are preferred over everything else:
-      if sym.kind == skIterator: inc(z.exactMatches, 200)
-      case best.state
-      of csEmpty, csNoMatch: best = z
-      of csMatch:
-        var cmp = cmpCandidates(best, z)
-        if cmp < 0: best = z   # x is better than the best so far
-        elif cmp == 0: alt = z # x is as good as the best so far
-        else: discard
-      #if sym.name.s == "cmp" and (n.info ?? "rstgen.nim") and n.info.line == 516:
-      #  echo "Matches ", n.info, " ", typeToString(sym.typ)
-      #  debug sym
-      #  writeMatches(z)
-      #  for i in 1 .. <len(z.call):
-      #    z.call[i].typ.debug
-      #  quit 1
+  while true:
+    block pickAttempt:
+      var o: TOverloadIter
+      var sym = initOverloadIter(o, c, headSymbol)
+      # Thanks to the lazy semchecking for operands, we need to check whether
+      # 'initCandidate' modifies the symbol table (via semExpr).
+      # This can occur in cases like 'init(a, 1, (var b = new(Type2); b))'
+      let counterInitial = c.currentScope.symbols.counter
+      # Initialise 'best' and 'alt' with the first available symbol
+      while sym != nil:
+        if sym.kind in filter:
+          initCandidate(c, best, sym, initialBinding, o.lastOverloadScope)
+          initCandidate(c, alt, sym, initialBinding, o.lastOverloadScope)
+          best.state = csNoMatch
+          break
+        else:
+          sym = nextOverloadIter(o, c, headSymbol)
+      var z: TCandidate
+      while sym != nil:
+        if sym.kind notin filter:
+          sym = nextOverloadIter(o, c, headSymbol)
+          continue
+        determineType(c, sym)
+        initCandidate(c, z, sym, initialBinding, o.lastOverloadScope)
+        if c.currentScope.symbols.counter != counterInitial: break pickAttempt
+        matches(c, n, orig, z)
+        if errors != nil:
+          errors.safeAdd((sym, int z.mutabilityProblem))
+          if z.errors != nil:
+            for err in z.errors:
+              errors.add(err)
+        if z.state == csMatch:
+          # little hack so that iterators are preferred over everything else:
+          if sym.kind == skIterator: inc(z.exactMatches, 200)
+          case best.state
+          of csEmpty, csNoMatch: best = z
+          of csMatch:
+            var cmp = cmpCandidates(best, z)
+            if cmp < 0: best = z   # x is better than the best so far
+            elif cmp == 0: alt = z # x is as good as the best so far
+            else: discard
+        sym = nextOverloadIter(o, c, headSymbol)
+    break # pick attempt was successful
 
 proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
   # Gives a detailed error message; this is separated from semOverloadedCall,