Merge branch 'master' of github.com:Araq/Nimrod
This commit is contained in:
commit
c2b8669e04
25 changed files with 827 additions and 497 deletions
|
|
@ -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!
|
||||
|
||||
|
|
|
|||
|
|
@ -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})
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue