diff options
Diffstat (limited to 'rod/sigmatch.nim')
-rwxr-xr-x | rod/sigmatch.nim | 750 |
1 files changed, 750 insertions, 0 deletions
diff --git a/rod/sigmatch.nim b/rod/sigmatch.nim new file mode 100755 index 000000000..1bb68ef1a --- /dev/null +++ b/rod/sigmatch.nim @@ -0,0 +1,750 @@ +# +# +# The Nimrod Compiler +# (c) Copyright 2009 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# +# This module implements the signature matching for resolving +# the call to overloaded procs, generic procs and operators. + +type + TCandidateState = enum + csEmpty, csMatch, csNoMatch + TCandidate{.final.} = object + exactMatches*: int + subtypeMatches*: int + intConvMatches*: int # conversions to int are not as expensive + convMatches*: int + genericMatches*: int + state*: TCandidateState + callee*: PType # may not be nil! + calleeSym*: PSym # may be nil + call*: PNode # modified call + bindings*: TIdTable # maps sym-ids to types + baseTypeMatch*: bool # needed for conversions from T to openarray[T] + # for example + + TTypeRelation = enum # order is important! + isNone, isConvertible, isIntConv, isSubtype, isGeneric, isEqual + +proc initCandidate(c: var TCandidate, callee: PType) = + c.exactMatches = 0 + c.subtypeMatches = 0 + c.convMatches = 0 + c.intConvMatches = 0 + c.genericMatches = 0 + c.state = csEmpty + c.callee = callee + c.calleeSym = nil + c.call = nil + c.baseTypeMatch = false + initIdTable(c.bindings) #assert(c.callee <> nil); + +proc copyCandidate(a: var TCandidate, b: TCandidate) = + a.exactMatches = b.exactMatches + a.subtypeMatches = b.subtypeMatches + a.convMatches = b.convMatches + a.intConvMatches = b.intConvMatches + a.genericMatches = b.genericMatches + a.state = b.state + a.callee = b.callee + a.calleeSym = b.calleeSym + a.call = copyTree(b.call) + a.baseTypeMatch = b.baseTypeMatch + copyIdTable(a.bindings, b.bindings) + +proc cmpCandidates(a, b: TCandidate): int = + result = a.exactMatches - b.exactMatches + if result != 0: return + result = a.genericMatches - b.genericMatches + if result != 0: return + result = a.subtypeMatches - b.subtypeMatches + if result != 0: return + result = a.intConvMatches - b.intConvMatches + if result != 0: return + result = a.convMatches - b.convMatches + +proc writeMatches(c: TCandidate) = + Writeln(stdout, "exact matches: " & $(c.exactMatches)) + Writeln(stdout, "subtype matches: " & $(c.subtypeMatches)) + Writeln(stdout, "conv matches: " & $(c.convMatches)) + Writeln(stdout, "intconv matches: " & $(c.intConvMatches)) + Writeln(stdout, "generic matches: " & $(c.genericMatches)) + +proc getNotFoundError(c: PContext, n: PNode): string = + # Gives a detailed error message; this is seperated from semDirectCall, + # as semDirectCall is already pretty slow (and we need this information only + # in case of an error). + var + sym: PSym + o: TOverloadIter + candidates: string + result = msgKindToString(errTypeMismatch) + for i in countup(1, sonsLen(n) - 1): + #debug(n.sons[i].typ); + add(result, typeToString(n.sons[i].typ)) + if i != sonsLen(n) - 1: add(result, ", ") + add(result, ')') + candidates = "" + sym = initOverloadIter(o, c, n.sons[0]) + while sym != nil: + if sym.kind in {skProc, skMethod, skIterator, skConverter}: + add(candidates, getProcHeader(sym)) + add(candidates, "\n") + sym = nextOverloadIter(o, c, n.sons[0]) + if candidates != "": + add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates) + +proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation +proc concreteType(mapping: TIdTable, t: PType): PType = + case t.kind + of tyArrayConstr: + # make it an array + result = newType(tyArray, t.owner) + addSon(result, t.sons[0]) # XXX: t.owner is wrong for ID! + addSon(result, t.sons[1]) # XXX: semantic checking for the type? + of tyNil: + result = nil # what should it be? + of tyGenericParam: + result = t + while true: + result = PType(idTableGet(mapping, t)) + if result == nil: InternalError("lookup failed") + if result.kind != tyGenericParam: break + else: + result = t # Note: empty is valid here + +proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation = + var k: TTypeKind + if a.kind == f.kind: + result = isEqual + else: + k = skipTypes(a, {tyRange}).kind + if k == f.kind: result = isSubtype + elif (f.kind == tyInt) and (k in {tyInt..tyInt32}): result = isIntConv + elif (k >= min) and (k <= max): result = isConvertible + else: result = isNone + +proc handleFloatRange(f, a: PType): TTypeRelation = + var k: TTypeKind + if a.kind == f.kind: + result = isEqual + else: + k = skipTypes(a, {tyRange}).kind + if k == f.kind: result = isSubtype + elif (k >= tyFloat) and (k <= tyFloat128): result = isConvertible + else: result = isNone + +proc isObjectSubtype(a, f: PType): bool = + var t: PType + t = a + while (t != nil) and (t.id != f.id): t = base(t) + result = t != nil + +proc minRel(a, b: TTypeRelation): TTypeRelation = + if a <= b: result = a + else: result = b + +proc tupleRel(mapping: var TIdTable, f, a: PType): TTypeRelation = + var + x, y: PSym + m: TTypeRelation + result = isNone + if sonsLen(a) == sonsLen(f): + result = isEqual + for i in countup(0, sonsLen(f) - 1): + m = typeRel(mapping, f.sons[i], a.sons[i]) + if m < isSubtype: + return isNone + result = minRel(result, m) + if (f.n != nil) and (a.n != nil): + for i in countup(0, sonsLen(f.n) - 1): + # check field names: + if f.n.sons[i].kind != nkSym: InternalError(f.n.info, "tupleRel") + if a.n.sons[i].kind != nkSym: InternalError(a.n.info, "tupleRel") + x = f.n.sons[i].sym + y = a.n.sons[i].sym + if x.name.id != y.name.id: + return isNone + +proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation = + var + x, concrete: PType + m: TTypeRelation + # is a subtype of f? + result = isNone + assert(f != nil) + assert(a != nil) + if (a.kind == tyGenericInst) and + not (skipTypes(f, {tyVar}).kind in {tyGenericBody, tyGenericInvokation}): + return typeRel(mapping, f, lastSon(a)) + if (a.kind == tyVar) and (f.kind != tyVar): + return typeRel(mapping, f, a.sons[0]) + case f.kind + of tyEnum: + if (a.kind == f.kind) and (a.id == f.id): result = isEqual + elif (skipTypes(a, {tyRange}).id == f.id): result = isSubtype + of tyBool, tyChar: + if (a.kind == f.kind): result = isEqual + elif skipTypes(a, {tyRange}).kind == f.kind: result = isSubtype + of tyRange: + if (a.kind == f.kind): + result = typeRel(mapping, base(a), base(f)) + if result < isGeneric: result = isNone + elif skipTypes(f, {tyRange}).kind == a.kind: + result = isConvertible # a convertible to f + of tyInt: + result = handleRange(f, a, tyInt8, tyInt32) + of tyInt8: + result = handleRange(f, a, tyInt8, tyInt8) + of tyInt16: + result = handleRange(f, a, tyInt8, tyInt16) + of tyInt32: + result = handleRange(f, a, tyInt, tyInt32) + of tyInt64: + result = handleRange(f, a, tyInt, tyInt64) + of tyFloat: + result = handleFloatRange(f, a) + of tyFloat32: + result = handleFloatRange(f, a) + of tyFloat64: + result = handleFloatRange(f, a) + of tyFloat128: + result = handleFloatRange(f, a) + of tyVar: + if (a.kind == f.kind): result = typeRel(mapping, base(f), base(a)) + else: result = typeRel(mapping, base(f), a) + of tyArray, tyArrayConstr: + # tyArrayConstr cannot happen really, but + # we wanna be safe here + case a.kind + of tyArray: + result = minRel(typeRel(mapping, f.sons[0], a.sons[0]), + typeRel(mapping, f.sons[1], a.sons[1])) + if result < isGeneric: result = isNone + of tyArrayConstr: + result = typeRel(mapping, f.sons[1], a.sons[1]) + if result < isGeneric: + result = isNone + else: + if (result != isGeneric) and (lengthOrd(f) != lengthOrd(a)): + result = isNone + elif f.sons[0].kind in GenericTypes: + result = minRel(result, typeRel(mapping, f.sons[0], a.sons[0])) + else: + nil + of tyOpenArray: + case a.Kind + of tyOpenArray: + result = typeRel(mapping, base(f), base(a)) + if result < isGeneric: result = isNone + of tyArrayConstr: + if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty): + result = isSubtype # [] is allowed here + elif typeRel(mapping, base(f), a.sons[1]) >= isGeneric: + result = isSubtype + of tyArray: + if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty): + result = isSubtype + elif typeRel(mapping, base(f), a.sons[1]) >= isGeneric: + result = isConvertible + of tySequence: + if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty): + result = isConvertible + elif typeRel(mapping, base(f), a.sons[0]) >= isGeneric: + result = isConvertible + else: + nil + of tySequence: + case a.Kind + of tyNil: + result = isSubtype + of tySequence: + if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty): + result = isSubtype + else: + result = typeRel(mapping, f.sons[0], a.sons[0]) + if result < isGeneric: result = isNone + else: + nil + of tyOrdinal: + if isOrdinalType(a): + if a.kind == tyOrdinal: x = a.sons[0] + else: x = a + result = typeRel(mapping, f.sons[0], x) + if result < isGeneric: result = isNone + of tyForward: + InternalError("forward type in typeRel()") + of tyNil: + if a.kind == f.kind: result = isEqual + of tyTuple: + if a.kind == tyTuple: result = tupleRel(mapping, f, a) + of tyObject: + if a.kind == tyObject: + if a.id == f.id: result = isEqual + elif isObjectSubtype(a, f): result = isSubtype + of tyDistinct: + if (a.kind == tyDistinct) and (a.id == f.id): result = isEqual + of tySet: + if a.kind == tySet: + if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty): + result = isSubtype + else: + result = typeRel(mapping, f.sons[0], a.sons[0]) + if result <= isConvertible: + result = isNone # BUGFIX! + of tyPtr: + case a.kind + of tyPtr: + result = typeRel(mapping, base(f), base(a)) + if result <= isConvertible: result = isNone + of tyNil: + result = isSubtype + else: + nil + of tyRef: + case a.kind + of tyRef: + result = typeRel(mapping, base(f), base(a)) + if result <= isConvertible: result = isNone + of tyNil: + result = isSubtype + else: + nil + of tyProc: + case a.kind + of tyNil: + result = isSubtype + of tyProc: + if (sonsLen(f) == sonsLen(a)) and (f.callconv == a.callconv): + # Note: We have to do unification for the parameters before the + # return type! + result = isEqual # start with maximum; also correct for no + # params at all + for i in countup(1, sonsLen(f) - 1): + m = typeRel(mapping, f.sons[i], a.sons[i]) + if (m == isNone) and + (typeRel(mapping, a.sons[i], f.sons[i]) == isSubtype): + # allow ``f.son`` as subtype of ``a.son``! + result = isConvertible + elif m < isSubtype: + return isNone + else: + result = minRel(m, result) + if f.sons[0] != nil: + if a.sons[0] != nil: + m = typeRel(mapping, f.sons[0], a.sons[0]) # Subtype is sufficient for return types! + if m < isSubtype: result = isNone + elif m == isSubtype: result = isConvertible + else: result = minRel(m, result) + else: + result = isNone + elif a.sons[0] != nil: + result = isNone + if (tfNoSideEffect in f.flags) and not (tfNoSideEffect in a.flags): + result = isNone + else: + nil + of tyPointer: + case a.kind + of tyPointer: result = isEqual + of tyNil: result = isSubtype + of tyRef, tyPtr, tyProc, tyCString: result = isConvertible + else: + nil + of tyString: + case a.kind + of tyString: result = isEqual + of tyNil: result = isSubtype + else: + nil + of tyCString: + # conversion from string to cstring is automatic: + case a.Kind + of tyCString: + result = isEqual + of tyNil: + result = isSubtype + of tyString: + result = isConvertible + of tyPtr: + if a.sons[0].kind == tyChar: result = isConvertible + of tyArray: + if (firstOrd(a.sons[0]) == 0) and + (skipTypes(a.sons[0], {tyRange}).kind in {tyInt..tyInt64}) and + (a.sons[1].kind == tyChar): + result = isConvertible + else: + nil + of tyEmpty: + if a.kind == tyEmpty: result = isEqual + of tyGenericInst: + result = typeRel(mapping, lastSon(f), a) + of tyGenericBody: + result = typeRel(mapping, lastSon(f), a) + of tyGenericInvokation: + assert(f.sons[0].kind == tyGenericBody) + if a.kind == tyGenericInvokation: + InternalError("typeRel: tyGenericInvokation -> tyGenericInvokation") + if (a.kind == tyGenericInst): + if (f.sons[0].containerID == a.sons[0].containerID) and + (sonsLen(a) - 1 == sonsLen(f)): + assert(a.sons[0].kind == tyGenericBody) + for i in countup(1, sonsLen(f) - 1): + if a.sons[i].kind == tyGenericParam: + InternalError("wrong instantiated type!") + if typeRel(mapping, f.sons[i], a.sons[i]) < isGeneric: return + result = isGeneric + else: + result = typeRel(mapping, f.sons[0], a) + if result != isNone: + # we steal the generic parameters from the tyGenericBody: + for i in countup(1, sonsLen(f) - 1): + x = PType(idTableGet(mapping, f.sons[0].sons[i - 1])) + if (x == nil) or (x.kind == tyGenericParam): + InternalError("wrong instantiated type!") + idTablePut(mapping, f.sons[i], x) + of tyGenericParam: + x = PType(idTableGet(mapping, f)) + if x == nil: + if sonsLen(f) == 0: + # no constraints + concrete = concreteType(mapping, a) + if concrete != nil: + #MessageOut('putting: ' + f.sym.name.s); + idTablePut(mapping, f, concrete) + result = isGeneric + else: + InternalError(f.sym.info, "has constraints: " & f.sym.name.s) # check + # constraints: + for i in countup(0, sonsLen(f) - 1): + if typeRel(mapping, f.sons[i], a) >= isSubtype: + concrete = concreteType(mapping, a) + if concrete != nil: + idTablePut(mapping, f, concrete) + result = isGeneric + break + elif a.kind == tyEmpty: + result = isGeneric + elif x.kind == tyGenericParam: + result = isGeneric + else: + result = typeRel(mapping, x, a) # check if it fits + of tyExpr, tyStmt, tyTypeDesc: + if a.kind == f.kind: + result = isEqual + else: + case a.kind + of tyExpr, tyStmt, tyTypeDesc: result = isGeneric + of tyNil: result = isSubtype + else: + nil + else: internalError("typeRel(" & $f.kind & ')') + +proc cmpTypes(f, a: PType): TTypeRelation = + var mapping: TIdTable + InitIdTable(mapping) + result = typeRel(mapping, f, a) + +proc getInstantiatedType(c: PContext, arg: PNode, m: TCandidate, + f: PType): PType = + result = PType(idTableGet(m.bindings, f)) + if result == nil: + result = generateTypeInstance(c, m.bindings, arg, f) + if result == nil: InternalError(arg.info, "getInstantiatedType") + +proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate, + c: PContext): PNode = + result = newNodeI(kind, arg.info) + if containsGenericType(f): result.typ = getInstantiatedType(c, arg, m, f) + else: result.typ = f + if result.typ == nil: InternalError(arg.info, "implicitConv") + addSon(result, nil) + addSon(result, arg) + +proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType, + arg: PNode): PNode = + result = nil + for i in countup(0, len(c.converters) - 1): + var src = c.converters[i].typ.sons[1] + var dest = c.converters[i].typ.sons[0] + if (typeRel(m.bindings, f, dest) == isEqual) and + (typeRel(m.bindings, src, a) == isEqual): + var s = newSymNode(c.converters[i]) + s.typ = c.converters[i].typ + s.info = arg.info + result = newNodeIT(nkHiddenCallConv, arg.info, s.typ.sons[0]) + addSon(result, s) + addSon(result, copyTree(arg)) + inc(m.convMatches) + return + +proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType, + arg: PNode): PNode = + var r = typeRel(m.bindings, f, a) + case r + of isConvertible: + inc(m.convMatches) + result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c) + of isIntConv: + inc(m.intConvMatches) + result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c) + of isSubtype: + inc(m.subtypeMatches) + result = implicitConv(nkHiddenSubConv, f, copyTree(arg), m, c) + of isGeneric: + inc(m.genericMatches) + result = copyTree(arg) + result.typ = getInstantiatedType(c, arg, m, f) + # BUG: f may not be the right key! + if (skipTypes(result.typ, abstractVar).kind in {tyTuple, tyOpenArray}): + result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c) + # BUGFIX: use ``result.typ`` and not `f` here + of isEqual: + inc(m.exactMatches) + result = copyTree(arg) + if (skipTypes(f, abstractVar).kind in {tyTuple, tyOpenArray}): + result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c) + of isNone: + result = userConvMatch(c, m, f, a, arg) + # check for a base type match, which supports openarray[T] without [] + # constructor in a call: + if (result == nil) and (f.kind == tyOpenArray): + r = typeRel(m.bindings, base(f), a) + if r >= isGeneric: + inc(m.convMatches) + result = copyTree(arg) + if r == isGeneric: result.typ = getInstantiatedType(c, arg, m, base(f)) + m.baseTypeMatch = true + else: + result = userConvMatch(c, m, base(f), a, arg) + +proc ParamTypesMatch(c: PContext, m: var TCandidate, f, a: PType, + arg: PNode): PNode = + var + cmp, best: int + x, y, z: TCandidate + r: TTypeRelation + if (arg == nil) or (arg.kind != nkSymChoice): + result = ParamTypesMatchAux(c, m, f, a, arg) + else: + # CAUTION: The order depends on the used hashing scheme. Thus it is + # incorrect to simply use the first fitting match. However, to implement + # this correctly is inefficient. We have to copy `m` here to be able to + # roll back the side effects of the unification algorithm. + initCandidate(x, m.callee) + initCandidate(y, m.callee) + initCandidate(z, m.callee) + x.calleeSym = m.calleeSym + y.calleeSym = m.calleeSym + z.calleeSym = m.calleeSym + best = - 1 + for i in countup(0, sonsLen(arg) - 1): + # iterators are not first class yet, so ignore them + if arg.sons[i].sym.kind in {skProc, skMethod, skConverter}: + copyCandidate(z, m) + r = typeRel(z.bindings, f, arg.sons[i].typ) + if r != isNone: + case x.state + of csEmpty, csNoMatch: + x = z + best = i + x.state = csMatch + of csMatch: + cmp = cmpCandidates(x, z) + if cmp < 0: + best = i + x = z + elif cmp == 0: + y = z # z is as good as x + else: + nil + if x.state == csEmpty: + result = nil + elif (y.state == csMatch) and (cmpCandidates(x, y) == 0): + if x.state != csMatch: + InternalError(arg.info, "x.state is not csMatch") + # ambiguous: more than one symbol fits + result = nil + else: + # only one valid interpretation found: + markUsed(arg, arg.sons[best].sym) + result = ParamTypesMatchAux(c, m, f, arg.sons[best].typ, arg.sons[best]) + +proc IndexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode = + var m: TCandidate + initCandidate(m, f) + result = paramTypesMatch(c, m, f, a, arg) + +proc setSon(father: PNode, at: int, son: PNode) = + if sonsLen(father) <= at: setlen(father.sons, at + 1) + father.sons[at] = son + +proc matches(c: PContext, n: PNode, m: var TCandidate) = + var f = 1 # iterates over formal parameters + var a = 1 # iterates over the actual given arguments + m.state = csMatch # until proven otherwise + m.call = newNodeI(nkCall, n.info) + m.call.typ = base(m.callee) # may be nil + var formalLen = sonsLen(m.callee.n) + addSon(m.call, copyTree(n.sons[0])) + var marker: TIntSet + IntSetInit(marker) + var container: PNode = nil # constructed container + var formal: PSym = nil + while a < sonsLen(n): + if n.sons[a].kind == nkExprEqExpr: + # named param + # check if m.callee has such a param: + if n.sons[a].sons[0].kind != nkIdent: + liMessage(n.sons[a].info, errNamedParamHasToBeIdent) + m.state = csNoMatch + return + formal = getSymFromList(m.callee.n, n.sons[a].sons[0].ident, 1) + if formal == nil: + # no error message! + m.state = csNoMatch + return + if IntSetContainsOrIncl(marker, formal.position): + # already in namedParams: + liMessage(n.sons[a].info, errCannotBindXTwice, formal.name.s) + m.state = csNoMatch + return + m.baseTypeMatch = false + var arg = ParamTypesMatch(c, m, formal.typ, + n.sons[a].typ, n.sons[a].sons[1]) + if (arg == nil): + m.state = csNoMatch + return + if m.baseTypeMatch: + assert(container == nil) + container = newNodeI(nkBracket, n.sons[a].info) + addSon(container, arg) + setSon(m.call, formal.position + 1, container) + if f != formalLen - 1: container = nil + else: + setSon(m.call, formal.position + 1, arg) + else: + # unnamed param + if f >= formalLen: + # too many arguments? + if tfVarArgs in m.callee.flags: + # is ok... but don't increment any counters... + if skipTypes(n.sons[a].typ, abstractVar).kind == tyString: + addSon(m.call, implicitConv(nkHiddenStdConv, getSysType(tyCString), + copyTree(n.sons[a]), m, c)) + else: + addSon(m.call, copyTree(n.sons[a])) + elif formal != nil: + m.baseTypeMatch = false + var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ, n.sons[a]) + if (arg != nil) and m.baseTypeMatch and (container != nil): + addSon(container, arg) + else: + m.state = csNoMatch + return + else: + m.state = csNoMatch + return + else: + if m.callee.n.sons[f].kind != nkSym: + InternalError(n.sons[a].info, "matches") + formal = m.callee.n.sons[f].sym + if IntSetContainsOrIncl(marker, formal.position): + # already in namedParams: + liMessage(n.sons[a].info, errCannotBindXTwice, formal.name.s) + m.state = csNoMatch + return + m.baseTypeMatch = false + var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ, n.sons[a]) + if (arg == nil): + m.state = csNoMatch + return + if m.baseTypeMatch: + assert(container == nil) + container = newNodeI(nkBracket, n.sons[a].info) + addSon(container, arg) + setSon(m.call, formal.position + 1, + implicitConv(nkHiddenStdConv, formal.typ, container, m, c)) + if f != formalLen - 1: container = nil + else: + setSon(m.call, formal.position + 1, arg) + inc(a) + inc(f) + f = 1 + while f < sonsLen(m.callee.n): + formal = m.callee.n.sons[f].sym + if not IntSetContainsOrIncl(marker, formal.position): + if formal.ast == nil: + # no default value + m.state = csNoMatch + break + else: + # use default value: + setSon(m.call, formal.position + 1, copyTree(formal.ast)) + inc(f) + +proc sameMethodDispatcher(a, b: PSym): bool = + result = false + if (a.kind == skMethod) and (b.kind == skMethod): + var aa = lastSon(a.ast) + var bb = lastSon(b.ast) + if (aa.kind == nkSym) and (bb.kind == nkSym) and (aa.sym == bb.sym): + result = true + +proc semDirectCall(c: PContext, n: PNode, filter: TSymKinds): PNode = + var + o: TOverloadIter + x, y, z: TCandidate + #liMessage(n.info, warnUser, renderTree(n)); + var sym = initOverloadIter(o, c, n.sons[0]) + result = nil + if sym == nil: return + initCandidate(x, sym.typ) + x.calleeSym = sym + initCandidate(y, sym.typ) + y.calleeSym = sym + while sym != nil: + if sym.kind in filter: + initCandidate(z, sym.typ) + z.calleeSym = sym + matches(c, n, z) + if z.state == csMatch: + case x.state + of csEmpty, csNoMatch: + x = z + of csMatch: + var cmp = cmpCandidates(x, z) + if cmp < 0: + x = z # z is better than x + elif cmp == 0: + y = z # z is as good as x + else: + nil + sym = nextOverloadIter(o, c, n.sons[0]) + if x.state == csEmpty: + # no overloaded proc found + # do not generate an error yet; the semantic checking will check for + # an overloaded () operator + elif (y.state == csMatch) and (cmpCandidates(x, y) == 0) and + not sameMethodDispatcher(x.calleeSym, y.calleeSym): + if x.state != csMatch: + InternalError(n.info, "x.state is not csMatch") #writeMatches(x); + #writeMatches(y); + liMessage(n.Info, errGenerated, `%`(msgKindToString(errAmbiguousCallXYZ), [ + getProcHeader(x.calleeSym), getProcHeader(y.calleeSym), + x.calleeSym.Name.s])) + else: + # only one valid interpretation found: + markUsed(n, x.calleeSym) + if x.calleeSym.ast == nil: + internalError(n.info, "calleeSym.ast is nil") # XXX: remove this check! + if x.calleeSym.ast.sons[genericParamsPos] != nil: + # a generic proc! + x.calleeSym = generateInstance(c, x.calleeSym, x.bindings, n.info) + x.callee = x.calleeSym.typ + result = x.call + result.sons[0] = newSymNode(x.calleeSym) + result.typ = x.callee.sons[0] |