make the current PContext accessible through TCandidate

the goal here is to remove all the hacks from ParamTypeMatch and to handle
all type matching in typeRel (the context there is required to evaluate any static
params and to run the compilation tests of user-defined type classes)
This commit is contained in:
Zahary Karadjov 2013-12-25 00:58:22 +02:00
commit 299cefdc98
5 changed files with 53 additions and 46 deletions

View file

@ -47,14 +47,14 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
var z: TCandidate var z: TCandidate
if sym == nil: return if sym == nil: return
initCandidate(best, sym, initialBinding, symScope) initCandidate(c, best, sym, initialBinding, symScope)
initCandidate(alt, sym, initialBinding, symScope) initCandidate(c, alt, sym, initialBinding, symScope)
best.state = csNoMatch best.state = csNoMatch
while sym != nil: while sym != nil:
if sym.kind in filter: if sym.kind in filter:
determineType(c, sym) determineType(c, sym)
initCandidate(z, sym, initialBinding, o.lastOverloadScope) initCandidate(c, z, sym, initialBinding, o.lastOverloadScope)
z.calleeSym = sym z.calleeSym = sym
matches(c, n, orig, z) matches(c, n, orig, z)
if errors != nil: if errors != nil:
@ -199,15 +199,15 @@ proc instGenericConvertersSons*(c: PContext, n: PNode, x: TCandidate) =
proc IndexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode = proc IndexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode =
var m: TCandidate var m: TCandidate
initCandidate(m, f) initCandidate(c, m, f)
result = paramTypesMatch(c, m, f, a, arg, nil) result = paramTypesMatch(m, f, a, arg, nil)
if m.genericConverter and result != nil: if m.genericConverter and result != nil:
instGenericConvertersArg(c, result, m) instGenericConvertersArg(c, result, m)
proc ConvertTo*(c: PContext, f: PType, n: PNode): PNode = proc ConvertTo*(c: PContext, f: PType, n: PNode): PNode =
var m: TCandidate var m: TCandidate
initCandidate(m, f) initCandidate(c, m, f)
result = paramTypesMatch(c, m, f, n.typ, n, nil) result = paramTypesMatch(m, f, n.typ, n, nil)
if m.genericConverter and result != nil: if m.genericConverter and result != nil:
instGenericConvertersArg(c, result, m) instGenericConvertersArg(c, result, m)
@ -243,9 +243,9 @@ proc explicitGenericInstError(n: PNode): PNode =
result = n result = n
proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode = proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
var x: TCandidate var m: TCandidate
initCandidate(x, s, n) initCandidate(c, m, s, n)
var newInst = generateInstance(c, s, x.bindings, n.info) var newInst = generateInstance(c, s, m.bindings, n.info)
markUsed(n, s) markUsed(n, s)
result = newSymNode(newInst, n.info) result = newSymNode(newInst, n.info)

View file

@ -142,7 +142,7 @@ proc checkConversionBetweenObjects(castDest, src: PType): TConvStatus =
const const
IntegralTypes = {tyBool, tyEnum, tyChar, tyInt..tyUInt64} IntegralTypes = {tyBool, tyEnum, tyChar, tyInt..tyUInt64}
proc checkConvertible(castDest, src: PType): TConvStatus = proc checkConvertible(c: PContext, castDest, src: PType): TConvStatus =
result = convOK result = convOK
if sameType(castDest, src) and castDest.sym == src.sym: if sameType(castDest, src) and castDest.sym == src.sym:
# don't annoy conversions that may be needed on another processor: # don't annoy conversions that may be needed on another processor:
@ -163,7 +163,7 @@ proc checkConvertible(castDest, src: PType): TConvStatus =
# accept conversion between integral types # accept conversion between integral types
else: else:
# we use d, s here to speed up that operation a bit: # we use d, s here to speed up that operation a bit:
case cmpTypes(d, s) case cmpTypes(c, d, s)
of isNone, isGeneric: of isNone, isGeneric:
if not compareTypes(castDest, src, dcEqIgnoreDistinct): if not compareTypes(castDest, src, dcEqIgnoreDistinct):
result = convNotLegal result = convNotLegal
@ -202,7 +202,7 @@ proc semConv(c: PContext, n: PNode): PNode =
var op = result.sons[1] var op = result.sons[1]
if not isSymChoice(op): if not isSymChoice(op):
let status = checkConvertible(result.typ, op.typ) let status = checkConvertible(c, result.typ, op.typ)
case status case status
of convOK: nil of convOK: nil
of convNotNeedeed: of convNotNeedeed:
@ -213,7 +213,7 @@ proc semConv(c: PContext, n: PNode): PNode =
else: else:
for i in countup(0, sonsLen(op) - 1): for i in countup(0, sonsLen(op) - 1):
let it = op.sons[i] let it = op.sons[i]
let status = checkConvertible(result.typ, it.typ) let status = checkConvertible(c, result.typ, it.typ)
if status == convOK: if status == convOK:
markUsed(n, it.sym) markUsed(n, it.sym)
markIndirect(c, it.sym) markIndirect(c, it.sym)
@ -324,15 +324,15 @@ proc isOpImpl(c: PContext, n: PNode): PNode =
case t2.kind case t2.kind
of tyTypeClasses: of tyTypeClasses:
var m: TCandidate var m: TCandidate
InitCandidate(m, t2) InitCandidate(c, m, t2)
match = matchUserTypeClass(c, m, emptyNode, t2, t1) != nil match = matchUserTypeClass(c, m, emptyNode, t2, t1) != nil
of tyOrdinal: of tyOrdinal:
var m: TCandidate var m: TCandidate
InitCandidate(m, t2) InitCandidate(c, m, t2)
match = isOrdinalType(t1) match = isOrdinalType(t1)
of tySequence, tyArray, tySet: of tySequence, tyArray, tySet:
var m: TCandidate var m: TCandidate
InitCandidate(m, t2) InitCandidate(c, m, t2)
match = typeRel(m, t2, t1) != isNone match = typeRel(m, t2, t1) != isNone
else: else:
match = sameType(t1, t2) match = sameType(t1, t2)
@ -707,7 +707,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
if t != nil and t.kind == tyProc: if t != nil and t.kind == tyProc:
# This is a proc variable, apply normal overload resolution # This is a proc variable, apply normal overload resolution
var m: TCandidate var m: TCandidate
initCandidate(m, t) initCandidate(c, m, t)
matches(c, n, nOrig, m) matches(c, n, nOrig, m)
if m.state != csMatch: if m.state != csMatch:
if c.inCompilesContext > 0: if c.inCompilesContext > 0:

View file

@ -838,7 +838,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
else: else:
internalAssert s.typ.kind == tyGenericBody internalAssert s.typ.kind == tyGenericBody
var m = newCandidate(s, n) var m = newCandidate(c, s, n)
matches(c, n, copyTree(n), m) matches(c, n, copyTree(n), m)
if m.state != csMatch: if m.state != csMatch:

View file

@ -21,7 +21,8 @@ type
TCandidateState* = enum TCandidateState* = enum
csEmpty, csMatch, csNoMatch csEmpty, csMatch, csNoMatch
TCandidate* {.final.} = object TCandidate* {.final.} = object
c*: PContext
exactMatches*: int # also misused to prefer iters over procs exactMatches*: int # also misused to prefer iters over procs
genericMatches: int # also misused to prefer constraints genericMatches: int # also misused to prefer constraints
subtypeMatches: int subtypeMatches: int
@ -58,7 +59,9 @@ const
proc markUsed*(n: PNode, s: PSym) proc markUsed*(n: PNode, s: PSym)
proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} = proc initCandidateAux(ctx: PContext,
c: var TCandidate, callee: PType) {.inline.} =
c.c = ctx
c.exactMatches = 0 c.exactMatches = 0
c.subtypeMatches = 0 c.subtypeMatches = 0
c.convMatches = 0 c.convMatches = 0
@ -71,17 +74,17 @@ proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} =
c.genericConverter = false c.genericConverter = false
c.inheritancePenalty = 0 c.inheritancePenalty = 0
proc initCandidate*(c: var TCandidate, callee: PType) = proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PType) =
initCandidateAux(c, callee) initCandidateAux(ctx, c, callee)
c.calleeSym = nil c.calleeSym = nil
initIdTable(c.bindings) initIdTable(c.bindings)
proc put(t: var TIdTable, key, val: PType) {.inline.} = proc put(t: var TIdTable, key, val: PType) {.inline.} =
IdTablePut(t, key, val) IdTablePut(t, key, val)
proc initCandidate*(c: var TCandidate, callee: PSym, binding: PNode, proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
calleeScope = -1) = binding: PNode, calleeScope = -1) =
initCandidateAux(c, callee.typ) initCandidateAux(ctx, c, callee.typ)
c.calleeSym = callee c.calleeSym = callee
c.calleeScope = calleeScope c.calleeScope = calleeScope
initIdTable(c.bindings) initIdTable(c.bindings)
@ -93,10 +96,12 @@ proc initCandidate*(c: var TCandidate, callee: PSym, binding: PNode,
#debug(formalTypeParam) #debug(formalTypeParam)
put(c.bindings, formalTypeParam, binding[i].typ) put(c.bindings, formalTypeParam, binding[i].typ)
proc newCandidate*(callee: PSym, binding: PNode, calleeScope = -1): TCandidate = proc newCandidate*(ctx: PContext, callee: PSym,
initCandidate(result, callee, binding, calleeScope) binding: PNode, calleeScope = -1): TCandidate =
initCandidate(ctx, result, callee, binding, calleeScope)
proc copyCandidate(a: var TCandidate, b: TCandidate) = proc copyCandidate(a: var TCandidate, b: TCandidate) =
a.c = b.c
a.exactMatches = b.exactMatches a.exactMatches = b.exactMatches
a.subtypeMatches = b.subtypeMatches a.subtypeMatches = b.subtypeMatches
a.convMatches = b.convMatches a.convMatches = b.convMatches
@ -762,10 +767,10 @@ proc typeRel(c: var TCandidate, f, a: PType, doBind = true): TTypeRelation =
result = isEqual result = isEqual
else: internalError("typeRel: " & $f.kind) else: internalError("typeRel: " & $f.kind)
proc cmpTypes*(f, a: PType): TTypeRelation = proc cmpTypes*(c: PContext, f, a: PType): TTypeRelation =
var c: TCandidate var m: TCandidate
InitCandidate(c, f) InitCandidate(c, m, f)
result = typeRel(c, f, a) result = typeRel(m, f, a)
proc getInstantiatedType(c: PContext, arg: PNode, m: TCandidate, proc getInstantiatedType(c: PContext, arg: PNode, m: TCandidate,
f: PType): PType = f: PType): PType =
@ -887,13 +892,14 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
result = arg result = arg
put(m.bindings, f, a) put(m.bindings, f, a)
proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, argType: PType, proc ParamTypesMatchAux(m: var TCandidate, f, argType: PType,
argSemantized, argOrig: PNode): PNode = argSemantized, argOrig: PNode): PNode =
var var
r: TTypeRelation r: TTypeRelation
arg = argSemantized arg = argSemantized
let let
c = m.c
a0 = if c.InTypeClass > 0: argType.skipTypes({tyTypeDesc}) a0 = if c.InTypeClass > 0: argType.skipTypes({tyTypeDesc})
else: argType else: argType
a = if a0 != nil: a0.skipTypes({tyStatic}) else: a0 a = if a0 != nil: a0.skipTypes({tyStatic}) else: a0
@ -1007,19 +1013,20 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, argType: PType,
else: else:
result = userConvMatch(c, m, base(f), a, arg) result = userConvMatch(c, m, base(f), a, arg)
proc ParamTypesMatch*(c: PContext, m: var TCandidate, f, a: PType, proc ParamTypesMatch*(m: var TCandidate, f, a: PType,
arg, argOrig: PNode): PNode = arg, argOrig: PNode): PNode =
if arg == nil or arg.kind notin nkSymChoices: if arg == nil or arg.kind notin nkSymChoices:
result = ParamTypesMatchAux(c, m, f, a, arg, argOrig) result = ParamTypesMatchAux(m, f, a, arg, argOrig)
else: else:
# CAUTION: The order depends on the used hashing scheme. Thus it is # CAUTION: The order depends on the used hashing scheme. Thus it is
# incorrect to simply use the first fitting match. However, to implement # 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 # this correctly is inefficient. We have to copy `m` here to be able to
# roll back the side effects of the unification algorithm. # roll back the side effects of the unification algorithm.
let c = m.c
var x, y, z: TCandidate var x, y, z: TCandidate
initCandidate(x, m.callee) initCandidate(c, x, m.callee)
initCandidate(y, m.callee) initCandidate(c, y, m.callee)
initCandidate(z, m.callee) initCandidate(c, z, m.callee)
x.calleeSym = m.calleeSym x.calleeSym = m.calleeSym
y.calleeSym = m.calleeSym y.calleeSym = m.calleeSym
z.calleeSym = m.calleeSym z.calleeSym = m.calleeSym
@ -1051,7 +1058,7 @@ proc ParamTypesMatch*(c: PContext, m: var TCandidate, f, a: PType,
else: else:
# only one valid interpretation found: # only one valid interpretation found:
markUsed(arg, arg.sons[best].sym) markUsed(arg, arg.sons[best].sym)
result = ParamTypesMatchAux(c, m, f, arg.sons[best].typ, arg.sons[best], result = ParamTypesMatchAux(m, f, arg.sons[best].typ, arg.sons[best],
argOrig) argOrig)
proc setSon(father: PNode, at: int, son: PNode) = proc setSon(father: PNode, at: int, son: PNode) =
@ -1142,7 +1149,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
m.baseTypeMatch = false m.baseTypeMatch = false
n.sons[a].sons[1] = prepareOperand(c, formal.typ, n.sons[a].sons[1]) n.sons[a].sons[1] = prepareOperand(c, formal.typ, n.sons[a].sons[1])
n.sons[a].typ = n.sons[a].sons[1].typ n.sons[a].typ = n.sons[a].sons[1].typ
var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ, var arg = ParamTypesMatch(m, formal.typ, n.sons[a].typ,
n.sons[a].sons[1], nOrig.sons[a].sons[1]) n.sons[a].sons[1], nOrig.sons[a].sons[1])
if arg == nil: if arg == nil:
m.state = csNoMatch m.state = csNoMatch
@ -1172,7 +1179,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
elif formal != nil: elif formal != nil:
m.baseTypeMatch = false m.baseTypeMatch = false
n.sons[a] = prepareOperand(c, formal.typ, n.sons[a]) n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ, var arg = ParamTypesMatch(m, formal.typ, n.sons[a].typ,
n.sons[a], nOrig.sons[a]) n.sons[a], nOrig.sons[a])
if (arg != nil) and m.baseTypeMatch and (container != nil): if (arg != nil) and m.baseTypeMatch and (container != nil):
addSon(container, arg) addSon(container, arg)
@ -1195,7 +1202,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
return return
m.baseTypeMatch = false m.baseTypeMatch = false
n.sons[a] = prepareOperand(c, formal.typ, n.sons[a]) n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ, var arg = ParamTypesMatch(m, formal.typ, n.sons[a].typ,
n.sons[a], nOrig.sons[a]) n.sons[a], nOrig.sons[a])
if arg == nil: if arg == nil:
m.state = csNoMatch m.state = csNoMatch
@ -1249,8 +1256,8 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
proc argtypeMatches*(c: PContext, f, a: PType): bool = proc argtypeMatches*(c: PContext, f, a: PType): bool =
var m: TCandidate var m: TCandidate
initCandidate(m, f) initCandidate(c, m, f)
let res = paramTypesMatch(c, m, f, a, ast.emptyNode, nil) let res = paramTypesMatch(m, f, a, ast.emptyNode, nil)
#instantiateGenericConverters(c, res, m) #instantiateGenericConverters(c, res, m)
# XXX this is used by patterns.nim too; I think it's better to not # XXX this is used by patterns.nim too; I think it's better to not
# instantiate generic converters for that # instantiate generic converters for that
@ -1312,7 +1319,7 @@ tests:
setup: setup:
var c: TCandidate var c: TCandidate
InitCandidate(c, nil) InitCandidate(nil, c, nil)
template yes(x, y) = template yes(x, y) =
test astToStr(x) & " is " & astToStr(y): test astToStr(x) & " is " & astToStr(y):

View file

@ -119,7 +119,7 @@ proc argsFit(c: PContext, candidate: PSym, n, nOrig: PNode): bool =
case candidate.kind case candidate.kind
of OverloadableSyms: of OverloadableSyms:
var m: TCandidate var m: TCandidate
initCandidate(m, candidate, nil) initCandidate(c, m, candidate, nil)
sigmatch.partialMatch(c, n, nOrig, m) sigmatch.partialMatch(c, n, nOrig, m)
result = m.state != csNoMatch result = m.state != csNoMatch
else: else: