diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 48e8c90b3404..16ddcacf13d1 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -37,20 +37,13 @@ proc sameMethodDispatcher(a, b: PSym): bool = proc determineType(c: PContext, s: PSym) -proc initCandidateSymbols(c: PContext, headSymbol: PNode, - initialBinding: PNode, - filter: TSymKinds, - best, alt: var TCandidate, - o: var TOverloadIter, - diagnostics: bool): seq[tuple[s: PSym, scope: int]] = - ## puts all overloads into a seq and prepares best+alt +proc collectOverloads(c: PContext, headSymbol: PNode, filter: TSymKinds, + o: var TOverloadIter): seq[tuple[s: PSym, scope: int]] = result = @[] var symx = initOverloadIter(o, c, headSymbol) - var symMarker = initIntSet() while symx != nil: if symx.kind in filter: result.add((symx, o.lastOverloadScope)) - symMarker.incl(symx.id) elif symx.kind == skGenericParam: #[ This code handles looking up a generic parameter when it's a static callable. @@ -64,6 +57,16 @@ proc initCandidateSymbols(c: PContext, headSymbol: PNode, result.add((paramTyp.n.sym, o.lastOverloadScope)) symx = nextOverloadIter(o, c, headSymbol) + + +proc initCandidateSymbols(c: PContext, headSymbol: PNode, + initialBinding: PNode, + filter: TSymKinds, + best, alt: var TCandidate, + o: var TOverloadIter, + diagnostics: bool): seq[tuple[s: PSym, scope: int]] = + ## puts all overloads into a seq and prepares best+alt + result = collectOverloads(c, headSymbol, filter, o) if result.len > 0: best = initCandidate(c, result[0].s, initialBinding, result[0].scope, diagnostics) @@ -125,39 +128,37 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode, determineType(c, sym) z = initCandidate(c, sym, initialBinding, scope, diagnosticsFlag) - # this is kinda backwards as without a check here the described - # problems in recalc would not happen, but instead it 100% - # does check forever in some cases - if c.currentScope.symbols.counter == symCount: - # may introduce new symbols with caveats described in recalc branch - matches(c, n, orig, z) - if typeBoundOps in c.features: - # this match may have given some arguments new types, - # in which case add their type bound ops as well - # type bound ops of arguments always matching `untyped` are not considered - for x in z.newlyTypedOperands: - let arg = n[x] - addTypeBoundOpsFor(arg) - - if z.state == csMatch: - # little hack so that iterators are preferred over everything else: - if sym.kind == skIterator: - if not (efWantIterator notin flags and efWantIterable in flags): - inc(z.exactMatches, 200) - else: - dec(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 - elif errorsEnabled or z.diagnosticsEnabled: - errors.add(CandidateError( - sym: sym, - firstMismatch: z.firstMismatch, - diagnostics: z.diagnostics)) - else: + # may introduce new symbols with caveats described in recalc branch + matches(c, n, orig, z) + + if typeBoundOps in c.features: + # this match may have given some arguments new types, + # in which case add their type bound ops as well + # type bound ops of arguments always matching `untyped` are not considered + for x in z.newlyTypedOperands: + let arg = n[x] + addTypeBoundOpsFor(arg) + + if z.state == csMatch: + # little hack so that iterators are preferred over everything else: + if sym.kind == skIterator: + if not (efWantIterator notin flags and efWantIterable in flags): + inc(z.exactMatches, 200) + else: + dec(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 + elif errorsEnabled or z.diagnosticsEnabled: + errors.add(CandidateError( + sym: sym, + firstMismatch: z.firstMismatch, + diagnostics: z.diagnostics)) + + if c.currentScope.symbols.counter != symCount: # this branch feels like a ticking timebomb # one of two bad things could happen # 1) new symbols are discovered but the loop ends before we recalc @@ -167,17 +168,12 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode, # Symbol table has been modified. Restart and pre-calculate all syms # before any further candidate init and compare. SLOW, but rare case. - let newSyms = initCandidateSymbols(c, headSymbol, initialBinding, filter, - best, alt, o, diagnosticsFlag) + let newSyms = collectOverloads(c, headSymbol, filter, o) for cand in newSyms: if not containsOrIncl(symMarker, cand.s.id): syms.add(cand) - # reset counter because syms may be in a new order symCount = c.currentScope.symbols.counter - # current sym was not considered - # XXX refactor this to be a lone `if` statement - continue if nextSymIndex > high(syms): # we have reached the end