diff options
Diffstat (limited to 'rod/sigmatch.nim')
-rw-r--r-- | rod/sigmatch.nim | 750 |
1 files changed, 0 insertions, 750 deletions
diff --git a/rod/sigmatch.nim b/rod/sigmatch.nim deleted file mode 100644 index 1bb68ef1a..000000000 --- a/rod/sigmatch.nim +++ /dev/null @@ -1,750 +0,0 @@ -# -# -# 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] |