Merge pull request #4633 from mbaulch/pickbestcand_faster_inlined

Optimise pickBestCandidate: reduce heap allocations.
This commit is contained in:
Andreas Rumpf
2016-08-25 16:35:33 +02:00
committed by GitHub

View File

@@ -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,