carefully reviewed and merged the changes from the devel branch

This commit is contained in:
Zahary Karadjov 2017-01-27 00:22:02 +02:00
commit d6d548c32f

View file

@ -35,10 +35,11 @@ proc sameMethodDispatcher(a, b: PSym): bool =
proc determineType(c: PContext, s: PSym) proc determineType(c: PContext, s: PSym)
proc initCandidateSymbols(c: PContext, headSymbol: PNode, proc initCandidateSymbols(c: PContext, headSymbol: PNode,
initialBinding: PNode, initialBinding: PNode,
filter: TSymKinds, filter: TSymKinds,
best, alt: var TCandidate, best, alt: var TCandidate,
o: var TOverloadIter): seq[tuple[s: PSym, scope: int]] = o: var TOverloadIter,
diagnostics: bool): seq[tuple[s: PSym, scope: int]] =
result = @[] result = @[]
var symx = initOverloadIter(o, c, headSymbol) var symx = initOverloadIter(o, c, headSymbol)
while symx != nil: while symx != nil:
@ -46,8 +47,10 @@ proc initCandidateSymbols(c: PContext, headSymbol: PNode,
result.add((symx, o.lastOverloadScope)) result.add((symx, o.lastOverloadScope))
symx = nextOverloadIter(o, c, headSymbol) symx = nextOverloadIter(o, c, headSymbol)
if result.len > 0: if result.len > 0:
initCandidate(c, best, result[0].s, initialBinding, result[0].scope) initCandidate(c, best, result[0].s, initialBinding,
initCandidate(c, alt, result[0].s, initialBinding, result[0].scope) result[0].scope, diagnostics)
initCandidate(c, alt, result[0].s, initialBinding,
result[0].scope, diagnostics)
best.state = csNoMatch best.state = csNoMatch
proc pickBestCandidate(c: PContext, headSymbol: PNode, proc pickBestCandidate(c: PContext, headSymbol: PNode,
@ -56,55 +59,62 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
filter: TSymKinds, filter: TSymKinds,
best, alt: var TCandidate, best, alt: var TCandidate,
errors: var CandidateErrors, errors: var CandidateErrors,
diagnostics = false) = diagnosticsFlag = false) =
var o: TOverloadIter var o: TOverloadIter
# thanks to the lazy semchecking for operands, we need to iterate over the var sym = initOverloadIter(o, c, headSymbol)
# symbol table *before* any call to 'initCandidate' which might invoke var scope = o.lastOverloadScope
# semExpr which might modify the symbol table in cases like # Thanks to the lazy semchecking for operands, we need to check whether
# 'init(a, 1, (var b = new(Type2); b))'. # 'initCandidate' modifies the symbol table (via semExpr).
var symx = initOverloadIter(o, c, headSymbol) # This can occur in cases like 'init(a, 1, (var b = new(Type2); b))'
let symScope = o.lastOverloadScope let counterInitial = c.currentScope.symbols.counter
var syms: seq[tuple[s: PSym, scope: int]]
var syms: seq[tuple[a: PSym, b: int]] = @[] var nextSymIndex = 0
while symx != nil: while sym != nil:
if symx.kind in filter: if sym.kind in filter:
syms.add((symx, o.lastOverloadScope)) # Initialise 'best' and 'alt' with the first available symbol
symx = nextOverloadIter(o, c, headSymbol) initCandidate(c, best, sym, initialBinding, scope, diagnosticsFlag)
if syms.len == 0: return initCandidate(c, alt, sym, initialBinding, scope, diagnosticsFlag)
best.state = csNoMatch
break
else:
sym = nextOverloadIter(o, c, headSymbol)
scope = o.lastOverloadScope
var z: TCandidate var z: TCandidate
initCandidate(c, best, syms[0][0], initialBinding, while sym != nil:
symScope, diagnostics = diagnostics) if sym.kind notin filter:
initCandidate(c, alt, syms[0][0], initialBinding, sym = nextOverloadIter(o, c, headSymbol)
symScope, diagnostics = diagnostics) scope = o.lastOverloadScope
best.state = csNoMatch continue
for i in 0 .. <syms.len:
let sym = syms[i][0]
determineType(c, sym) determineType(c, sym)
initCandidate(c, z, sym, initialBinding, initCandidate(c, z, sym, initialBinding, scope, diagnosticsFlag)
syms[i][1], diagnostics = diagnostics) if c.currentScope.symbols.counter == counterInitial or syms != nil:
#if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140: matches(c, n, orig, z)
# gDebug = true if z.state == csMatch:
matches(c, n, orig, z) # little hack so that iterators are preferred over everything else:
if z.state == csMatch: if sym.kind == skIterator: inc(z.exactMatches, 200)
# little hack so that iterators are preferred over everything else: case best.state
if sym.kind == skIterator: inc(z.exactMatches, 200) of csEmpty, csNoMatch: best = z
case best.state of csMatch:
of csEmpty, csNoMatch: best = z var cmp = cmpCandidates(best, z)
of csMatch: if cmp < 0: best = z # x is better than the best so far
var cmp = cmpCandidates(best, z) elif cmp == 0: alt = z # x is as good as the best so far
if cmp < 0: best = z # x is better than the best so far elif errors != nil or z.diagnostics != nil:
elif cmp == 0: alt = z # x is as good as the best so far errors.safeAdd((sym, int z.mutabilityProblem, z.diagnostics))
else: discard else:
#if sym.name.s == "cmp" and (n.info ?? "rstgen.nim") and n.info.line == 516: # Symbol table has been modified. Restart and pre-calculate all syms
# echo "Matches ", n.info, " ", typeToString(sym.typ) # before any further candidate init and compare. SLOW, but rare case.
# debug sym syms = initCandidateSymbols(c, headSymbol, initialBinding, filter,
# writeMatches(z) best, alt, o, diagnosticsFlag)
# for i in 1 .. <len(z.call): if syms == nil:
# z.call[i].typ.debug sym = nextOverloadIter(o, c, headSymbol)
# quit 1 scope = o.lastOverloadScope
elif errors != nil or z.diagnostics != nil: elif nextSymIndex < syms.len:
errors.safeAdd((sym, int z.mutabilityProblem, z.diagnostics)) # rare case: retrieve the next pre-calculated symbol
sym = syms[nextSymIndex].s
scope = syms[nextSymIndex].scope
nextSymIndex += 1
else:
break
proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors): proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
(TPreferedDesc, string) = (TPreferedDesc, string) =
@ -210,6 +220,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
if result.state != csMatch: if result.state != csMatch:
n.sons.delete(1) n.sons.delete(1)
orig.sons.delete(1) orig.sons.delete(1)
excl n.flags, nfExprCall
else: return else: return
if nfDotField in n.flags: if nfDotField in n.flags:
@ -358,7 +369,7 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
proc canDeref(n: PNode): bool {.inline.} = proc canDeref(n: PNode): bool {.inline.} =
result = n.len >= 2 and (let t = n[1].typ; result = n.len >= 2 and (let t = n[1].typ;
t != nil and t.skipTypes({tyGenericInst}).kind in {tyPtr, tyRef}) t != nil and t.skipTypes({tyGenericInst, tyAlias}).kind in {tyPtr, tyRef})
proc tryDeref(n: PNode): PNode = proc tryDeref(n: PNode): PNode =
result = newNodeI(nkHiddenDeref, n.info) result = newNodeI(nkHiddenDeref, n.info)
@ -414,12 +425,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
let formal = s.ast.sons[genericParamsPos].sons[i-1].typ let formal = s.ast.sons[genericParamsPos].sons[i-1].typ
let arg = n[i].typ let arg = n[i].typ
let tm = typeRel(m, formal, arg, true) let tm = typeRel(m, formal, arg, true)
if tm in {isNone, isConvertible}: if tm in {isNone, isConvertible}: return nil
if formal.sonsLen > 0 and formal.sons[0].kind != tyNone:
typeMismatch(n, formal.sons[0], arg)
else:
typeMismatch(n, formal, arg)
break
var newInst = generateInstance(c, s, m.bindings, n.info) var newInst = generateInstance(c, s, m.bindings, n.info)
newInst.typ.flags.excl tfUnresolved newInst.typ.flags.excl tfUnresolved
markUsed(n.info, s, c.graph.usageSym) markUsed(n.info, s, c.graph.usageSym)
@ -441,6 +447,7 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
"; got " & $(n.len-1) & " type(s) but expected " & $expected) "; got " & $(n.len-1) & " type(s) but expected " & $expected)
return n return n
result = explicitGenericSym(c, n, s) result = explicitGenericSym(c, n, s)
if result == nil: result = explicitGenericInstError(n)
elif a.kind in {nkClosedSymChoice, nkOpenSymChoice}: elif a.kind in {nkClosedSymChoice, nkOpenSymChoice}:
# choose the generic proc with the proper number of type parameters. # choose the generic proc with the proper number of type parameters.
# XXX I think this could be improved by reusing sigmatch.paramTypesMatch. # XXX I think this could be improved by reusing sigmatch.paramTypesMatch.
@ -453,10 +460,12 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
# it suffices that the candidate has the proper number of generic # it suffices that the candidate has the proper number of generic
# type parameters: # type parameters:
if safeLen(candidate.ast.sons[genericParamsPos]) == n.len-1: if safeLen(candidate.ast.sons[genericParamsPos]) == n.len-1:
result.add(explicitGenericSym(c, n, candidate)) let x = explicitGenericSym(c, n, candidate)
if x != nil: result.add(x)
# get rid of nkClosedSymChoice if not ambiguous: # get rid of nkClosedSymChoice if not ambiguous:
if result.len == 1 and a.kind == nkClosedSymChoice: if result.len == 1 and a.kind == nkClosedSymChoice:
result = result[0] result = result[0]
elif result.len == 0: result = explicitGenericInstError(n)
# candidateCount != 1: return explicitGenericInstError(n) # candidateCount != 1: return explicitGenericInstError(n)
else: else:
result = explicitGenericInstError(n) result = explicitGenericInstError(n)
@ -471,7 +480,7 @@ proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym =
call.add(newIdentNode(fn.name, fn.info)) call.add(newIdentNode(fn.name, fn.info))
for i in 1.. <fn.typ.n.len: for i in 1.. <fn.typ.n.len:
let param = fn.typ.n.sons[i] let param = fn.typ.n.sons[i]
let t = skipTypes(param.typ, abstractVar-{tyTypeDesc}) let t = skipTypes(param.typ, abstractVar-{tyTypeDesc, tyDistinct})
if t.kind == tyDistinct or param.typ.kind == tyDistinct: hasDistinct = true if t.kind == tyDistinct or param.typ.kind == tyDistinct: hasDistinct = true
var x: PType var x: PType
if param.typ.kind == tyVar: if param.typ.kind == tyVar:
@ -484,3 +493,8 @@ proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym =
var resolved = semOverloadedCall(c, call, call, {fn.kind}, {}) var resolved = semOverloadedCall(c, call, call, {fn.kind}, {})
if resolved != nil: if resolved != nil:
result = resolved.sons[0].sym result = resolved.sons[0].sym
if not compareTypes(result.typ.sons[0], fn.typ.sons[0], dcEqIgnoreDistinct):
result = nil
elif result.magic in {mArrPut, mArrGet}:
# cannot borrow these magics for now
result = nil