Merge branch 'master' of github.com:Araq/Nimrod

This commit is contained in:
Araq 2012-10-03 20:51:22 +02:00
commit c2b8669e04
25 changed files with 827 additions and 497 deletions

View file

@ -350,6 +350,8 @@ type
# pass of semProcTypeNode performed after instantiation.
# this won't be needed if we don't perform this redundant
# second pass (stay tuned).
tfRetType # marks return types in proc (used to detect type classes
# used as return types for return type inference)
tfAll, # type class requires all constraints to be met (default)
tfAny, # type class requires any constraint to be met
tfCapturesEnv, # whether proc really captures some environment
@ -779,6 +781,11 @@ proc add*(father, son: PNode) =
proc `[]`*(n: PNode, i: int): PNode {.inline.} =
result = n.sons[i]
# son access operators with support for negative indices
template `{}`*(n: PNode, i: int): expr = n[i -| n]
template `{}=`*(n: PNode, i: int, s: PNode): stmt =
n.sons[i -| n] = s
var emptyNode* = newNode(nkEmpty)
# There is a single empty node that is shared! Do not overwrite it!

View file

@ -41,6 +41,7 @@ type
callsite: PNode # for 'callsite' magic
mode*: TEvalMode
globals*: TIdNodeTable # state of global vars
getType*: proc(n: PNode): PNode
PEvalContext* = ref TEvalContext
@ -521,7 +522,7 @@ proc evalSym(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
else: result = nil
if result == nil or {sfImportc, sfForward} * s.flags != {}:
result = raiseCannotEval(c, n.info)
proc evalIncDec(c: PEvalContext, n: PNode, sign: biggestInt): PNode =
result = evalAux(c, n.sons[1], {efLValue})
if isSpecial(result): return
@ -875,6 +876,27 @@ proc evalTypeTrait*(n: PNode, context: PSym): PNode =
else:
internalAssert false
proc evalIsOp*(n: PNode): PNode =
InternalAssert n.sonsLen == 3 and
n[1].kind == nkSym and n[1].sym.kind == skType and
n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
let t1 = n[1].sym.typ
if n[2].kind in {nkStrLit..nkTripleStrLit}:
case n[2].strVal.normalize
of "closure":
let t = skipTypes(t1, abstractRange)
result = newIntNode(nkIntLit, ord(t.kind == tyProc and
t.callConv == ccClosure))
else:
let t2 = n[2].typ
var match = if t2.kind == tyTypeClass: matchTypeClass(t2, t1)
else: sameType(t1, t2)
result = newIntNode(nkIntLit, ord(match))
result.typ = n.typ
proc expectString(n: PNode) =
if n.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit}:
GlobalError(n.info, errStringLiteralExpected)
@ -968,6 +990,9 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
of mTypeTrait:
n.sons[1] = evalAux(c, n.sons[1], {})
result = evalTypeTrait(n, c.module)
of mIs:
n.sons[1] = evalAux(c, n.sons[1], {})
result = evalIsOp(n)
of mSlurp: result = evalSlurp(evalAux(c, n.sons[1], {}), c.module)
of mStaticExec:
let cmd = evalAux(c, n.sons[1], {})
@ -1067,7 +1092,10 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
result = evalAux(c, n.sons[1], {})
if isSpecial(result): return
if result.kind != nkIdent: stackTrace(c, n, errFieldXNotFound, "ident")
of mNGetType: result = evalAux(c, n.sons[1], {})
of mNGetType:
var ast = evalAux(c, n.sons[1], {})
InternalAssert c.getType != nil
result = c.getType(ast)
of mNStrVal:
result = evalAux(c, n.sons[1], {})
if isSpecial(result): return
@ -1128,7 +1156,8 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
var a = result
result = evalAux(c, n.sons[2], {efLValue})
if isSpecial(result): return
a.typ = result.typ # XXX: exception handling?
InternalAssert result.kind == nkSym and result.sym.kind == skType
a.typ = result.sym.typ
result = emptyNode
of mNSetStrVal:
result = evalAux(c, n.sons[1], {efLValue})

View file

@ -575,19 +575,22 @@ proc inCheckpoint*(current: TLineInfo): TCheckPointResult =
type
TErrorHandling = enum doNothing, doAbort, doRaise
proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) =
if msg == errInternal:
assert(false) # we want a stack trace here
proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) =
template maybeTrace =
if defined(debug) or gVerbosity >= 3:
writeStackTrace()
if msg == errInternal:
writeStackTrace() # we always want a stack trace here
if msg >= fatalMin and msg <= fatalMax:
if gVerbosity >= 3: assert(false)
maybeTrace()
quit(1)
if msg >= errMin and msg <= errMax:
if gVerbosity >= 3: assert(false)
maybeTrace()
inc(gErrorCounter)
options.gExitcode = 1'i8
if gErrorCounter >= gErrorMax or eh == doAbort:
if gVerbosity >= 3: assert(false)
quit(1) # one error stops the compiler
quit(1) # one error stops the compiler
elif eh == doRaise:
raiseRecoverableError(s)

View file

@ -743,7 +743,7 @@ proc isExprStart(p: TParser): bool =
case p.tok.tokType
of tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf, tkProc, tkBind,
tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit, tkVar, tkRef, tkPtr,
tkTuple, tkType, tkWhen:
tkTuple, tkType, tkWhen, tkCase:
result = true
else: result = false
@ -763,9 +763,9 @@ proc parseExpr(p: var TParser): PNode =
case p.tok.tokType:
of tkIf: result = parseIfExpr(p, nkIfExpr)
of tkWhen: result = parseIfExpr(p, nkWhenExpr)
of tkCase: result = parseCase(p)
else: result = lowestExpr(p)
# XXX needs proper support:
#of tkCase: result = parseCase(p)
#of tkTry: result = parseTry(p)
proc primary(p: var TParser, skipSuffix = false): PNode =
@ -1044,9 +1044,9 @@ proc parseCase(p: var TParser): PNode =
if b.kind == nkElse: break
if wasIndented:
eat(p, tkDed)
if p.tok.tokType != tkEof: eat(p, tkDed)
popInd(p.lex)
proc parseTry(p: var TParser): PNode =
result = newNodeP(nkTryStmt, p)
getTok(p)

View file

@ -43,6 +43,7 @@ proc addParams(c: PContext, n: PNode, kind: TSymKind)
proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind)
proc addResultNode(c: PContext, n: PNode)
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType
proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
proc typeMismatch(n: PNode, formal, actual: PType) =
if formal.kind != tyError and actual.kind != tyError:
@ -156,8 +157,18 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
markUsed(n, sym)
if sym == c.p.owner:
GlobalError(n.info, errRecursiveDependencyX, sym.name.s)
if c.evalContext == nil:
c.evalContext = newEvalContext(c.module, "", emStatic)
c.evalContext.getType = proc (n: PNode): PNode =
var e = tryExpr(c, n)
if e == nil:
result = symNodeFromType(c, errorType(c), n.info)
elif e.typ == nil:
result = newSymNode(getSysSym"void")
else:
result = symNodeFromType(c, e.typ, n.info)
result = evalMacroCall(c.evalContext, n, nOrig, sym)
if semCheck: result = semAfterMacroCall(c, result, sym)

View file

@ -281,18 +281,29 @@ proc semOf(c: PContext, n: PNode): PNode =
n.typ = getSysType(tyBool)
result = n
proc semIs(c: PContext, n: PNode): PNode =
if sonsLen(n) == 3:
n.typ = getSysType(tyBool)
let a = semTypeNode(c, n[1], nil)
n.sons[1] = newNodeIT(nkType, n[1].info, a)
if n[2].kind notin {nkStrLit..nkTripleStrLit}:
let b = semTypeNode(c, n[2], nil)
n.sons[2] = newNodeIT(nkType, n[2].info, b)
else:
proc semIs(c: PContext, n: PNode): PNode =
if sonsLen(n) != 3:
LocalError(n.info, errXExpectsTwoArguments, "is")
result = n
result = n
n.typ = getSysType(tyBool)
n.sons[1] = semExprWithType(c, n[1])
if n[1].typ.kind != tyTypeDesc:
LocalError(n[0].info, errTypeExpected)
if n[2].kind notin {nkStrLit..nkTripleStrLit}:
let t2 = semTypeNode(c, n[2], nil)
n.sons[2] = newNodeIT(nkType, n[2].info, t2)
if n[1].typ.sonsLen == 0:
# this is a typedesc variable, leave for evals
return
else:
let t1 = n[1].typ.sons[0]
# BUGFIX: don't evaluate this too early: ``T is void``
if not containsGenericType(t1): result = evalIsOp(n)
proc semOpAux(c: PContext, n: PNode, tailToExclude = 1) =
for i in countup(1, sonsLen(n) - tailToExclude):
var a = n.sons[i]
@ -1048,8 +1059,20 @@ proc semAsgn(c: PContext, n: PNode): PNode =
localError(a.info, errXCannotBeAssignedTo,
renderTree(a, {renderNoComments}))
else:
n.sons[1] = semExprWithType(c, n.sons[1])
n.sons[1] = fitNode(c, le, n.sons[1])
var
rhs = semExprWithType(c, n.sons[1])
lhs = n.sons[0]
if lhs.kind == nkSym and lhs.sym.kind == skResult and
lhs.sym.typ.kind == tyGenericParam:
if matchTypeClass(lhs.typ, rhs.typ):
InternalAssert c.p.resultSym != nil
lhs.typ = rhs.typ
c.p.resultSym.typ = rhs.typ
c.p.owner.typ.sons[0] = rhs.typ
else:
typeMismatch(n, lhs.typ, rhs.typ)
n.sons[1] = fitNode(c, le, rhs)
fixAbstractType(c, n)
asgnToResultVar(c, n, n.sons[0], n.sons[1])
result = n
@ -1214,12 +1237,7 @@ proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym,
else:
result = semDirectOp(c, n, flags)
proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
# we replace this node by a 'true' or 'false' node:
if sonsLen(n) != 2: return semDirectOp(c, n, flags)
result = newIntNode(nkIntLit, 0)
result.info = n.info
result.typ = getSysType(tyBool)
proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
# watch out, hacks ahead:
let oldErrorCount = msgs.gErrorCounter
let oldErrorMax = msgs.gErrorMax
@ -1241,8 +1259,8 @@ proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
let oldProcCon = c.p
c.generics = newGenericsCache()
try:
discard semExpr(c, n.sons[1])
result.intVal = ord(msgs.gErrorCounter == oldErrorCount)
result = semExpr(c, n, flags)
if msgs.gErrorCounter != oldErrorCount: result = nil
except ERecoverableError:
nil
# undo symbol table changes (as far as it's possible):
@ -1259,6 +1277,14 @@ proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
msgs.gErrorCounter = oldErrorCount
msgs.gErrorMax = oldErrorMax
proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
# we replace this node by a 'true' or 'false' node:
if sonsLen(n) != 2: return semDirectOp(c, n, flags)
result = newIntNode(nkIntLit, ord(tryExpr(c, n, flags) != nil))
result.info = n.info
result.typ = getSysType(tyBool)
proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode =
if sonsLen(n) == 3:
# XXX ugh this is really a hack: shallowCopy() can be overloaded only
@ -1352,19 +1378,28 @@ proc semSetConstr(c: PContext, n: PNode): PNode =
m = fitNode(c, typ, n.sons[i])
addSon(result, m)
proc semTableConstr(c: PContext, n: PNode): PNode =
# we simply transform ``{key: value, key2: value}`` to
# ``[(key, value), (key2, value2)]``
proc semTableConstr(c: PContext, n: PNode): PNode =
# we simply transform ``{key: value, key2, key3: value}`` to
# ``[(key, value), (key2, value2), (key3, value2)]``
result = newNodeI(nkBracket, n.info)
var lastKey = 0
for i in 0..n.len-1:
var x = n.sons[i]
if x.kind == nkExprColonExpr and sonsLen(x) == 2:
for j in countup(lastKey, i-1):
var pair = newNodeI(nkPar, x.info)
pair.add(n.sons[j])
pair.add(x[1])
result.add(pair)
var pair = newNodeI(nkPar, x.info)
pair.add(x[0])
pair.add(x[1])
result.add(pair)
else:
illFormedAst(x)
lastKey = i+1
if lastKey != n.len: illFormedAst(n)
result = semExpr(c, result)
type
@ -1507,6 +1542,57 @@ proc semMacroStmt(c: PContext, n: PNode, flags: TExprFlags,
renderTree(a, {renderNoComments}))
result = errorNode(c, n)
proc semCaseExpr(c: PContext, caseStmt: PNode): PNode =
# The case expression is simply rewritten to a StmtListExpr:
# var res {.noInit, genSym.}: type(values)
#
# case E
# of X: res = value1
# of Y: res = value2
#
# res
var
info = caseStmt.info
resVar = newSym(skVar, getIdent":res", getCurrOwner(), info)
resNode = newSymNode(resVar, info)
resType: PType
resVar.flags = { sfGenSym, sfNoInit }
for i in countup(1, caseStmt.len - 1):
var cs = caseStmt[i]
case cs.kind
of nkOfBranch, nkElifBranch, nkElse:
# the value is always the last son regardless of the branch kind
cs.checkMinSonsLen 1
var value = cs{-1}
if value.kind == nkStmtList: value.kind = nkStmtListExpr
value = semExprWithType(c, value)
if resType == nil:
resType = value.typ
elif not sameType(resType, value.typ):
# XXX: semeType is a bit too harsh.
# work on finding a common base type.
# this will be useful for arrays/seq too:
# [ref DerivedA, ref DerivedB, ref Base]
typeMismatch(cs, resType, value.typ)
cs{-1} = newNode(nkAsgn, cs.info, @[resNode, value])
else:
IllFormedAst(caseStmt)
result = newNode(nkStmtListExpr, info, @[
newNode(nkVarSection, info, @[
newNode(nkIdentDefs, info, @[
resNode,
symNodeFromType(c, resType, info),
emptyNode])]),
caseStmt,
resNode])
result = semStmtListExpr(c, result)
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result = n
if gCmd == cmdIdeTools: suggestExpr(c, n)
@ -1686,7 +1772,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
of nkTryStmt: result = semTry(c, n)
of nkBreakStmt, nkContinueStmt: result = semBreakOrContinue(c, n)
of nkForStmt, nkParForStmt: result = semFor(c, n)
of nkCaseStmt: result = semCase(c, n)
of nkCaseStmt:
if efWantStmt in flags: result = semCase(c, n)
else: result = semCaseExpr(c, n)
of nkReturnStmt: result = semReturn(c, n)
of nkAsmStmt: result = semAsm(c, n)
of nkYieldStmt: result = semYield(c, n)

View file

@ -610,17 +610,6 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
result = newIntNodeT(sonsLen(a), n)
else:
result = magicCall(m, n)
of mIs:
# BUGFIX: don't evaluate this too early: ``T is void``
if not containsGenericType(n[1].typ):
if n[2].kind in {nkStrLit..nkTripleStrLit}:
case n[2].strVal.normalize
of "closure":
let t = skipTypes(n[1].typ, abstractRange)
result = newIntNodeT(ord(t.kind == tyProc and
t.callConv == ccClosure), n)
elif not containsGenericType(n[2].typ):
result = newIntNodeT(ord(sameType(n[1].typ, n[2].typ)), n)
of mAstToStr:
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
of mConStrStr:

View file

@ -261,16 +261,16 @@ proc semGenericStmt(c: PContext, n: PNode,
else:
a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc}, toBind)
of nkEnumTy:
checkMinSonsLen(n, 1)
if n.sons[0].kind != nkEmpty:
n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, toBind)
for i in countup(1, sonsLen(n) - 1):
var a: PNode
case n.sons[i].kind
of nkEnumFieldDef: a = n.sons[i].sons[0]
of nkIdent: a = n.sons[i]
else: illFormedAst(n)
addDeclAt(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c), c.tab.tos-1)
if n.sonsLen > 0:
if n.sons[0].kind != nkEmpty:
n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, toBind)
for i in countup(1, sonsLen(n) - 1):
var a: PNode
case n.sons[i].kind
of nkEnumFieldDef: a = n.sons[i].sons[0]
of nkIdent: a = n.sons[i]
else: illFormedAst(n)
addDeclAt(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c), c.tab.tos-1)
of nkObjectTy, nkTupleTy:
nil
of nkFormalParams:
@ -306,6 +306,9 @@ proc semGenericStmt(c: PContext, n: PNode,
n.sons[bodyPos] = semGenericStmtScope(c, body, flags, toBind)
closeScope(c.tab)
of nkPragma, nkPragmaExpr: nil
of nkExprColonExpr:
checkMinSonsLen(n, 2)
result.sons[1] = semGenericStmt(c, n.sons[1], flags, toBind)
else:
for i in countup(0, sonsLen(n) - 1):
result.sons[i] = semGenericStmt(c, n.sons[i], flags, toBind)

View file

@ -25,8 +25,13 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
s.flags = s.flags + {sfUsed, sfFromGeneric}
var t = PType(IdTableGet(pt, q.typ))
if t == nil:
LocalError(a.info, errCannotInstantiateX, s.name.s)
t = errorType(c)
if tfRetType in q.typ.flags:
# keep the generic type and allow the return type to be bound
# later by semAsgn in return type inference scenario
t = q.typ
else:
LocalError(a.info, errCannotInstantiateX, s.name.s)
t = errorType(c)
elif t.kind == tyGenericParam:
InternalError(a.info, "instantiateGenericParamList: " & q.name.s)
elif t.kind == tyGenericInvokation:
@ -163,7 +168,6 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
result.typ = newTypeS(tyProc, c)
rawAddSon(result.typ, nil)
result.typ.callConv = fn.typ.callConv
ParamsTypeCheck(c, result.typ)
var oldPrc = GenericCacheGet(c, entry)
if oldPrc == nil:
c.generics.generics.add(entry)
@ -174,6 +178,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
if fn.kind != skTemplate:
instantiateBody(c, n, result)
sideEffectsCheck(c, result)
ParamsTypeCheck(c, result.typ)
else:
result = oldPrc
popInfoContext()

View file

@ -584,22 +584,20 @@ proc paramTypeClass(c: PContext, paramType: PType, procKind: TSymKind):
result.typ = newTypeS(tyTypeDesc, c)
result.typ.sons = paramType.sons
of tyDistinct:
# type T1 = distinct expr
# type S1 = distinct Sortable
# proc x(a, b: T1, c, d: S1)
# This forces bindOnce behavior for the type class, equivalent to
# proc x[T, S](a, b: T, c, d: S)
result = paramTypeClass(c, paramType.lastSon, procKind)
result.id = paramType.sym.name
# disable the bindOnce behavior for the type class
result.id = nil
return
of tyGenericBody:
# type Foo[T] = object
# proc x(a: Foo, b: Foo)
result.typ = newTypeS(tyTypeClass, c)
result.typ.addSonSkipIntLit(paramType)
result.id = paramType.sym.name # bindOnce by default
of tyTypeClass:
result.typ = copyType(paramType, getCurrOwner(), false)
else: nil
# bindOnce by default
if paramType.sym != nil: result.id = paramType.sym.name
proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
paramType: PType, paramName: string,
@ -619,7 +617,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
let s = SymtabGet(c.tab, paramTypId)
# tests/run/tinterf triggers this:
if s != nil: result = s.typ
else:
else:
LocalError(info, errCannotInstantiateX, paramName)
result = errorType(c)
else:
@ -684,8 +682,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue
for j in countup(0, length-3):
var arg = newSymG(skParam, a.sons[j], c)
var finalType = liftParamType(c, kind, genericParams, typ, arg.name.s,
arg.info).skipIntLit
var finalType = liftParamType(c, kind, genericParams, typ,
arg.name.s, arg.info).skipIntLit
arg.typ = finalType
arg.position = counter
inc(counter)
@ -703,6 +701,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
if r.sym == nil or sfAnon notin r.sym.flags:
r = liftParamType(c, kind, genericParams, r, "result", n.sons[0].info)
r.flags.incl tfRetType
result.sons[0] = skipIntLit(r)
res.typ = result.sons[0]
@ -800,22 +799,25 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
LocalError(n.info, errTypeExpected)
result = newOrPrevType(tyError, prev, c)
of nkCallKinds:
let op = n.sons[0].ident
if op.id in {ord(wAnd), ord(wOr)} or op.s == "|":
var
t1 = semTypeNode(c, n.sons[1], nil)
t2 = semTypeNode(c, n.sons[2], nil)
if t1 == nil:
LocalError(n.sons[1].info, errTypeExpected)
result = newOrPrevType(tyError, prev, c)
elif t2 == nil:
LocalError(n.sons[2].info, errTypeExpected)
result = newOrPrevType(tyError, prev, c)
if n[0].kind == nkIdent:
let op = n.sons[0].ident
if op.id in {ord(wAnd), ord(wOr)} or op.s == "|":
var
t1 = semTypeNode(c, n.sons[1], nil)
t2 = semTypeNode(c, n.sons[2], nil)
if t1 == nil:
LocalError(n.sons[1].info, errTypeExpected)
result = newOrPrevType(tyError, prev, c)
elif t2 == nil:
LocalError(n.sons[2].info, errTypeExpected)
result = newOrPrevType(tyError, prev, c)
else:
result = newTypeS(tyTypeClass, c)
result.addSonSkipIntLit(t1)
result.addSonSkipIntLit(t2)
result.flags.incl(if op.id == ord(wAnd): tfAll else: tfAny)
else:
result = newTypeS(tyTypeClass, c)
result.addSonSkipIntLit(t1)
result.addSonSkipIntLit(t2)
result.flags.incl(if op.id == ord(wAnd): tfAll else: tfAny)
result = semTypeExpr(c, n)
else:
result = semTypeExpr(c, n)
of nkCurlyExpr:

View file

@ -59,6 +59,7 @@ type
proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType
proc ReplaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym
proc ReplaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode
proc prepareNode(cl: var TReplTypeVars, n: PNode): PNode =
result = copyNode(n)
@ -66,7 +67,7 @@ proc prepareNode(cl: var TReplTypeVars, n: PNode): PNode =
for i in 0 .. safeLen(n)-1:
# XXX HACK: ``f(a, b)``, avoid to instantiate `f`
if i == 0: result.add(n[i])
else: result.add(prepareNode(cl, n[i]))
else: result.add(ReplaceTypeVarsN(cl, n[i]))
proc ReplaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode =
if n == nil: return

View file

@ -11,7 +11,7 @@
## the call to overloaded procs, generic procs and operators.
import
intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
magicsys, condsyms, idents, lexer, options
type
@ -257,32 +257,6 @@ proc tupleRel(c: var TCandidate, f, a: PType): TTypeRelation =
var y = a.n.sons[i].sym
if x.name.id != y.name.id: return isNone
proc matchTypeClass(c: var TCandidate, typeClass, t: PType): TTypeRelation =
for i in countup(0, typeClass.sonsLen - 1):
let req = typeClass.sons[i]
var match = req.kind == skipTypes(t, {tyRange, tyGenericInst}).kind
if not match:
case req.kind
of tyGenericBody:
if t.kind == tyGenericInst and t.sons[0] == req:
match = true
put(c.bindings, typeClass, t)
of tyTypeClass:
match = matchTypeClass(c, req, t) == isGeneric
else: nil
elif t.kind in {tyObject}:
match = sameType(t, req)
if tfAny in typeClass.flags:
if match: return isGeneric
else:
if not match: return isNone
# if the loop finished without returning, either all constraints matched
# or none of them matched.
result = if tfAny in typeClass.flags: isNone else: isGeneric
proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
proc inconsistentVarTypes(f, a: PType): bool {.inline.} =
result = f.kind != a.kind and (f.kind == tyVar or a.kind == tyVar)
@ -325,6 +299,10 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
result = isNone
else: nil
proc matchTypeClass(c: var TCandidate, f, a: PType): TTypeRelation =
result = if matchTypeClass(c.bindings, f, a): isGeneric
else: isNone
proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
# is a subtype of f?
result = isNone

View file

@ -626,9 +626,9 @@ proc SameTypeOrNil*(a, b: PType, flags: TTypeCmpFlags = {}): bool =
var c = initSameTypeClosure()
c.flags = flags
result = SameTypeAux(a, b, c)
proc equalParam(a, b: PSym): TParamsEquality =
if SameTypeOrNil(a.typ, b.typ):
if SameTypeOrNil(a.typ, b.typ, {TypeDescExactMatch}):
if a.ast == b.ast:
result = paramsEqual
elif a.ast != nil and b.ast != nil:
@ -904,7 +904,38 @@ proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]],
if i >= a.sonslen or a.sons[i] == nil: return false
a = a.sons[i]
result = a.kind == last
proc matchTypeClass*(bindings: var TIdTable, typeClass, t: PType): bool =
for i in countup(0, typeClass.sonsLen - 1):
let req = typeClass.sons[i]
var match = req.kind == skipTypes(t, {tyRange, tyGenericInst}).kind
if not match:
case req.kind
of tyGenericBody:
if t.kind == tyGenericInst and t.sons[0] == req:
match = true
IdTablePut(bindings, typeClass, t)
of tyTypeClass:
match = matchTypeClass(bindings, req, t)
else: nil
elif t.kind in {tyObject}:
match = sameType(t, req)
if tfAny in typeClass.flags:
if match: return true
else:
if not match: return false
# if the loop finished without returning, either all constraints matched
# or none of them matched.
result = if tfAny in typeClass.flags: false else: true
proc matchTypeClass*(typeClass, typ: PType): bool =
var bindings: TIdTable
initIdTable(bindings)
result = matchTypeClass(bindings, typeClass, typ)
proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
assert(kind in {skVar, skLet, skConst, skParam, skResult})
# if we have already checked the type, return true, because we stop the