carefully reviewed and merged the changes from the devel branch
This commit is contained in:
parent
cbf66e99a8
commit
d6d548c32f
1 changed files with 75 additions and 61 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue