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:
parent
952dbc4b8f
commit
299cefdc98
5 changed files with 53 additions and 46 deletions
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue