mirror of
https://github.com/nim-lang/Nim.git
synced 2026-07-19 23:41:29 +00:00
Optimise pickBestCandidate: reduce heap allocations.
This commit is contained in:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user