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. # pass of semProcTypeNode performed after instantiation.
# this won't be needed if we don't perform this redundant # this won't be needed if we don't perform this redundant
# second pass (stay tuned). # 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) tfAll, # type class requires all constraints to be met (default)
tfAny, # type class requires any constraint to be met tfAny, # type class requires any constraint to be met
tfCapturesEnv, # whether proc really captures some environment tfCapturesEnv, # whether proc really captures some environment
@ -779,6 +781,11 @@ proc add*(father, son: PNode) =
proc `[]`*(n: PNode, i: int): PNode {.inline.} = proc `[]`*(n: PNode, i: int): PNode {.inline.} =
result = n.sons[i] 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) var emptyNode* = newNode(nkEmpty)
# There is a single empty node that is shared! Do not overwrite it! # 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 callsite: PNode # for 'callsite' magic
mode*: TEvalMode mode*: TEvalMode
globals*: TIdNodeTable # state of global vars globals*: TIdNodeTable # state of global vars
getType*: proc(n: PNode): PNode
PEvalContext* = ref TEvalContext PEvalContext* = ref TEvalContext
@ -875,6 +876,27 @@ proc evalTypeTrait*(n: PNode, context: PSym): PNode =
else: else:
internalAssert false 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) = proc expectString(n: PNode) =
if n.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit}: if n.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit}:
GlobalError(n.info, errStringLiteralExpected) GlobalError(n.info, errStringLiteralExpected)
@ -968,6 +990,9 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
of mTypeTrait: of mTypeTrait:
n.sons[1] = evalAux(c, n.sons[1], {}) n.sons[1] = evalAux(c, n.sons[1], {})
result = evalTypeTrait(n, c.module) 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 mSlurp: result = evalSlurp(evalAux(c, n.sons[1], {}), c.module)
of mStaticExec: of mStaticExec:
let cmd = evalAux(c, n.sons[1], {}) let cmd = evalAux(c, n.sons[1], {})
@ -1067,7 +1092,10 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
result = evalAux(c, n.sons[1], {}) result = evalAux(c, n.sons[1], {})
if isSpecial(result): return if isSpecial(result): return
if result.kind != nkIdent: stackTrace(c, n, errFieldXNotFound, "ident") 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: of mNStrVal:
result = evalAux(c, n.sons[1], {}) result = evalAux(c, n.sons[1], {})
if isSpecial(result): return if isSpecial(result): return
@ -1128,7 +1156,8 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
var a = result var a = result
result = evalAux(c, n.sons[2], {efLValue}) result = evalAux(c, n.sons[2], {efLValue})
if isSpecial(result): return 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 result = emptyNode
of mNSetStrVal: of mNSetStrVal:
result = evalAux(c, n.sons[1], {efLValue}) result = evalAux(c, n.sons[1], {efLValue})

View file

@ -576,17 +576,20 @@ type
TErrorHandling = enum doNothing, doAbort, doRaise TErrorHandling = enum doNothing, doAbort, doRaise
proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) = proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) =
template maybeTrace =
if defined(debug) or gVerbosity >= 3:
writeStackTrace()
if msg == errInternal: if msg == errInternal:
assert(false) # we want a stack trace here writeStackTrace() # we always want a stack trace here
if msg >= fatalMin and msg <= fatalMax: if msg >= fatalMin and msg <= fatalMax:
if gVerbosity >= 3: assert(false) maybeTrace()
quit(1) quit(1)
if msg >= errMin and msg <= errMax: if msg >= errMin and msg <= errMax:
if gVerbosity >= 3: assert(false) maybeTrace()
inc(gErrorCounter) inc(gErrorCounter)
options.gExitcode = 1'i8 options.gExitcode = 1'i8
if gErrorCounter >= gErrorMax or eh == doAbort: 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: elif eh == doRaise:
raiseRecoverableError(s) raiseRecoverableError(s)

View file

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

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 addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind)
proc addResultNode(c: PContext, n: PNode) proc addResultNode(c: PContext, n: PNode)
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType 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) = proc typeMismatch(n: PNode, formal, actual: PType) =
if formal.kind != tyError and actual.kind != tyError: if formal.kind != tyError and actual.kind != tyError:
@ -156,8 +157,18 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
markUsed(n, sym) markUsed(n, sym)
if sym == c.p.owner: if sym == c.p.owner:
GlobalError(n.info, errRecursiveDependencyX, sym.name.s) GlobalError(n.info, errRecursiveDependencyX, sym.name.s)
if c.evalContext == nil: if c.evalContext == nil:
c.evalContext = newEvalContext(c.module, "", emStatic) 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) result = evalMacroCall(c.evalContext, n, nOrig, sym)
if semCheck: result = semAfterMacroCall(c, result, sym) if semCheck: result = semAfterMacroCall(c, result, sym)

View file

@ -282,16 +282,27 @@ proc semOf(c: PContext, n: PNode): PNode =
result = n result = n
proc semIs(c: PContext, n: PNode): PNode = proc semIs(c: PContext, n: PNode): PNode =
if sonsLen(n) == 3: 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:
LocalError(n.info, errXExpectsTwoArguments, "is") 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) = proc semOpAux(c: PContext, n: PNode, tailToExclude = 1) =
for i in countup(1, sonsLen(n) - tailToExclude): for i in countup(1, sonsLen(n) - tailToExclude):
@ -1048,8 +1059,20 @@ proc semAsgn(c: PContext, n: PNode): PNode =
localError(a.info, errXCannotBeAssignedTo, localError(a.info, errXCannotBeAssignedTo,
renderTree(a, {renderNoComments})) renderTree(a, {renderNoComments}))
else: else:
n.sons[1] = semExprWithType(c, n.sons[1]) var
n.sons[1] = fitNode(c, le, n.sons[1]) 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) fixAbstractType(c, n)
asgnToResultVar(c, n, n.sons[0], n.sons[1]) asgnToResultVar(c, n, n.sons[0], n.sons[1])
result = n result = n
@ -1214,12 +1237,7 @@ proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym,
else: else:
result = semDirectOp(c, n, flags) result = semDirectOp(c, n, flags)
proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode = proc tryExpr(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)
# watch out, hacks ahead: # watch out, hacks ahead:
let oldErrorCount = msgs.gErrorCounter let oldErrorCount = msgs.gErrorCounter
let oldErrorMax = msgs.gErrorMax let oldErrorMax = msgs.gErrorMax
@ -1241,8 +1259,8 @@ proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
let oldProcCon = c.p let oldProcCon = c.p
c.generics = newGenericsCache() c.generics = newGenericsCache()
try: try:
discard semExpr(c, n.sons[1]) result = semExpr(c, n, flags)
result.intVal = ord(msgs.gErrorCounter == oldErrorCount) if msgs.gErrorCounter != oldErrorCount: result = nil
except ERecoverableError: except ERecoverableError:
nil nil
# undo symbol table changes (as far as it's possible): # 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.gErrorCounter = oldErrorCount
msgs.gErrorMax = oldErrorMax 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 = proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode =
if sonsLen(n) == 3: if sonsLen(n) == 3:
# XXX ugh this is really a hack: shallowCopy() can be overloaded only # XXX ugh this is really a hack: shallowCopy() can be overloaded only
@ -1353,18 +1379,27 @@ proc semSetConstr(c: PContext, n: PNode): PNode =
addSon(result, m) addSon(result, m)
proc semTableConstr(c: PContext, n: PNode): PNode = proc semTableConstr(c: PContext, n: PNode): PNode =
# we simply transform ``{key: value, key2: value}`` to # we simply transform ``{key: value, key2, key3: value}`` to
# ``[(key, value), (key2, value2)]`` # ``[(key, value), (key2, value2), (key3, value2)]``
result = newNodeI(nkBracket, n.info) result = newNodeI(nkBracket, n.info)
var lastKey = 0
for i in 0..n.len-1: for i in 0..n.len-1:
var x = n.sons[i] var x = n.sons[i]
if x.kind == nkExprColonExpr and sonsLen(x) == 2: 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) var pair = newNodeI(nkPar, x.info)
pair.add(x[0]) pair.add(x[0])
pair.add(x[1]) pair.add(x[1])
result.add(pair) result.add(pair)
else:
illFormedAst(x) lastKey = i+1
if lastKey != n.len: illFormedAst(n)
result = semExpr(c, result) result = semExpr(c, result)
type type
@ -1507,6 +1542,57 @@ proc semMacroStmt(c: PContext, n: PNode, flags: TExprFlags,
renderTree(a, {renderNoComments})) renderTree(a, {renderNoComments}))
result = errorNode(c, n) 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 = proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result = n result = n
if gCmd == cmdIdeTools: suggestExpr(c, 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 nkTryStmt: result = semTry(c, n)
of nkBreakStmt, nkContinueStmt: result = semBreakOrContinue(c, n) of nkBreakStmt, nkContinueStmt: result = semBreakOrContinue(c, n)
of nkForStmt, nkParForStmt: result = semFor(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 nkReturnStmt: result = semReturn(c, n)
of nkAsmStmt: result = semAsm(c, n) of nkAsmStmt: result = semAsm(c, n)
of nkYieldStmt: result = semYield(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) result = newIntNodeT(sonsLen(a), n)
else: else:
result = magicCall(m, n) 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: of mAstToStr:
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n) result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
of mConStrStr: of mConStrStr:

View file

@ -261,7 +261,7 @@ proc semGenericStmt(c: PContext, n: PNode,
else: else:
a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc}, toBind) a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc}, toBind)
of nkEnumTy: of nkEnumTy:
checkMinSonsLen(n, 1) if n.sonsLen > 0:
if n.sons[0].kind != nkEmpty: if n.sons[0].kind != nkEmpty:
n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, toBind) n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, toBind)
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
@ -306,6 +306,9 @@ proc semGenericStmt(c: PContext, n: PNode,
n.sons[bodyPos] = semGenericStmtScope(c, body, flags, toBind) n.sons[bodyPos] = semGenericStmtScope(c, body, flags, toBind)
closeScope(c.tab) closeScope(c.tab)
of nkPragma, nkPragmaExpr: nil of nkPragma, nkPragmaExpr: nil
of nkExprColonExpr:
checkMinSonsLen(n, 2)
result.sons[1] = semGenericStmt(c, n.sons[1], flags, toBind)
else: else:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
result.sons[i] = semGenericStmt(c, n.sons[i], flags, toBind) result.sons[i] = semGenericStmt(c, n.sons[i], flags, toBind)

View file

@ -25,6 +25,11 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
s.flags = s.flags + {sfUsed, sfFromGeneric} s.flags = s.flags + {sfUsed, sfFromGeneric}
var t = PType(IdTableGet(pt, q.typ)) var t = PType(IdTableGet(pt, q.typ))
if t == nil: if t == nil:
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) LocalError(a.info, errCannotInstantiateX, s.name.s)
t = errorType(c) t = errorType(c)
elif t.kind == tyGenericParam: elif t.kind == tyGenericParam:
@ -163,7 +168,6 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
result.typ = newTypeS(tyProc, c) result.typ = newTypeS(tyProc, c)
rawAddSon(result.typ, nil) rawAddSon(result.typ, nil)
result.typ.callConv = fn.typ.callConv result.typ.callConv = fn.typ.callConv
ParamsTypeCheck(c, result.typ)
var oldPrc = GenericCacheGet(c, entry) var oldPrc = GenericCacheGet(c, entry)
if oldPrc == nil: if oldPrc == nil:
c.generics.generics.add(entry) c.generics.generics.add(entry)
@ -174,6 +178,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
if fn.kind != skTemplate: if fn.kind != skTemplate:
instantiateBody(c, n, result) instantiateBody(c, n, result)
sideEffectsCheck(c, result) sideEffectsCheck(c, result)
ParamsTypeCheck(c, result.typ)
else: else:
result = oldPrc result = oldPrc
popInfoContext() popInfoContext()

View file

@ -584,22 +584,20 @@ proc paramTypeClass(c: PContext, paramType: PType, procKind: TSymKind):
result.typ = newTypeS(tyTypeDesc, c) result.typ = newTypeS(tyTypeDesc, c)
result.typ.sons = paramType.sons result.typ.sons = paramType.sons
of tyDistinct: 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 = paramTypeClass(c, paramType.lastSon, procKind)
result.id = paramType.sym.name # disable the bindOnce behavior for the type class
result.id = nil
return
of tyGenericBody: of tyGenericBody:
# type Foo[T] = object # type Foo[T] = object
# proc x(a: Foo, b: Foo) # proc x(a: Foo, b: Foo)
result.typ = newTypeS(tyTypeClass, c) result.typ = newTypeS(tyTypeClass, c)
result.typ.addSonSkipIntLit(paramType) result.typ.addSonSkipIntLit(paramType)
result.id = paramType.sym.name # bindOnce by default
of tyTypeClass: of tyTypeClass:
result.typ = copyType(paramType, getCurrOwner(), false) result.typ = copyType(paramType, getCurrOwner(), false)
else: nil else: nil
# bindOnce by default
if paramType.sym != nil: result.id = paramType.sym.name
proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
paramType: PType, paramName: string, paramType: PType, paramName: string,
@ -684,8 +682,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue
for j in countup(0, length-3): for j in countup(0, length-3):
var arg = newSymG(skParam, a.sons[j], c) var arg = newSymG(skParam, a.sons[j], c)
var finalType = liftParamType(c, kind, genericParams, typ, arg.name.s, var finalType = liftParamType(c, kind, genericParams, typ,
arg.info).skipIntLit arg.name.s, arg.info).skipIntLit
arg.typ = finalType arg.typ = finalType
arg.position = counter arg.position = counter
inc(counter) inc(counter)
@ -703,6 +701,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
if skipTypes(r, {tyGenericInst}).kind != tyEmpty: if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
if r.sym == nil or sfAnon notin r.sym.flags: if r.sym == nil or sfAnon notin r.sym.flags:
r = liftParamType(c, kind, genericParams, r, "result", n.sons[0].info) r = liftParamType(c, kind, genericParams, r, "result", n.sons[0].info)
r.flags.incl tfRetType
result.sons[0] = skipIntLit(r) result.sons[0] = skipIntLit(r)
res.typ = result.sons[0] res.typ = result.sons[0]
@ -800,6 +799,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
LocalError(n.info, errTypeExpected) LocalError(n.info, errTypeExpected)
result = newOrPrevType(tyError, prev, c) result = newOrPrevType(tyError, prev, c)
of nkCallKinds: of nkCallKinds:
if n[0].kind == nkIdent:
let op = n.sons[0].ident let op = n.sons[0].ident
if op.id in {ord(wAnd), ord(wOr)} or op.s == "|": if op.id in {ord(wAnd), ord(wOr)} or op.s == "|":
var var
@ -818,6 +818,8 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
result.flags.incl(if op.id == ord(wAnd): tfAll else: tfAny) result.flags.incl(if op.id == ord(wAnd): tfAll else: tfAny)
else: else:
result = semTypeExpr(c, n) result = semTypeExpr(c, n)
else:
result = semTypeExpr(c, n)
of nkCurlyExpr: of nkCurlyExpr:
result = semTypeNode(c, n.sons[0], nil) result = semTypeNode(c, n.sons[0], nil)
if result != nil: if result != nil:

View file

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

View file

@ -257,32 +257,6 @@ proc tupleRel(c: var TCandidate, f, a: PType): TTypeRelation =
var y = a.n.sons[i].sym var y = a.n.sons[i].sym
if x.name.id != y.name.id: return isNone 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 procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
proc inconsistentVarTypes(f, a: PType): bool {.inline.} = proc inconsistentVarTypes(f, a: PType): bool {.inline.} =
result = f.kind != a.kind and (f.kind == tyVar or a.kind == tyVar) 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 result = isNone
else: nil 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 = proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
# is a subtype of f? # is a subtype of f?
result = isNone result = isNone

View file

@ -628,7 +628,7 @@ proc SameTypeOrNil*(a, b: PType, flags: TTypeCmpFlags = {}): bool =
result = SameTypeAux(a, b, c) result = SameTypeAux(a, b, c)
proc equalParam(a, b: PSym): TParamsEquality = proc equalParam(a, b: PSym): TParamsEquality =
if SameTypeOrNil(a.typ, b.typ): if SameTypeOrNil(a.typ, b.typ, {TypeDescExactMatch}):
if a.ast == b.ast: if a.ast == b.ast:
result = paramsEqual result = paramsEqual
elif a.ast != nil and b.ast != nil: elif a.ast != nil and b.ast != nil:
@ -905,6 +905,37 @@ proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]],
a = a.sons[i] a = a.sons[i]
result = a.kind == last 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 = proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
assert(kind in {skVar, skLet, skConst, skParam, skResult}) assert(kind in {skVar, skLet, skConst, skParam, skResult})
# if we have already checked the type, return true, because we stop the # if we have already checked the type, return true, because we stop the

View file

@ -2237,6 +2237,28 @@ An if expression always results in a value, so the ``else`` part is
required. ``Elif`` parts are also allowed (but unlikely to be good required. ``Elif`` parts are also allowed (but unlikely to be good
style). style).
When expression
~~~~~~~~~~~~~~~
Just like an `if expression`, but corresponding to the when statement.
Case expression
~~~~~~~~~~~~~~~
The `case expression` is again very similar to the case statement:
.. code-block:: nimrod
var favoriteFood = case animal
of "dog": "bones"
of "cat": "mice"
elif animal.endsWith"whale": "plankton"
else:
echo "I'm not sure what to serve, but everybody loves ice cream"
"ice cream"
As seen in the above example, the case expression can also introduce side
effects. When multiple statements are given for a branch, Nimrod will use
the last expression as the result value, much like in an `expr` template.
Table constructor Table constructor
~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~
@ -2244,10 +2266,10 @@ Table constructor
A `table constructor`:idx: is syntactic sugar for an array constructor: A `table constructor`:idx: is syntactic sugar for an array constructor:
.. code-block:: nimrod .. code-block:: nimrod
{"key1": "value1", "key2": "value2"} {"key1": "value1", "key2", "key3": "value2"}
# is the same as: # is the same as:
[("key1", "value1"), ("key2", "value2")] [("key1", "value1"), ("key2", "value2"), ("key3", "value")]
The empty table can be written ``{:}`` (in contrast to the empty set The empty table can be written ``{:}`` (in contrast to the empty set
@ -2940,6 +2962,13 @@ from the proc body. This is usually used with the ``auto`` type class:
.. code-block:: nimrod .. code-block:: nimrod
proc makePair(a, b): auto = (first: a, second: b) proc makePair(a, b): auto = (first: a, second: b)
The return type will be treated as additional generic param and can be
explicitly specified at call sites as any other generic param.
Future versions of nimrod may also support overloading based on the return type
of the overloads. In such settings, the expected result type at call sites may
also influence the inferred return type.
Symbol lookup in generics Symbol lookup in generics
~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~
@ -3457,15 +3486,14 @@ a type-safe wrapper for the unsafe `printf` function form C:
macro safePrintF(formatString: string{lit}, args: vararg[expr]): expr = macro safePrintF(formatString: string{lit}, args: vararg[expr]): expr =
var i = 0 var i = 0
for c in formatChars(formatString): for c in formatChars(formatString):
const FormatChars = { var expectedType = case c
'c': char, of 'c': char
'd', 'i', 'x', 'X': int, of 'd', 'i', 'x', 'X': int
'f', 'e', 'E', 'g', 'G': float, of 'f', 'e', 'E', 'g', 'G': float
's': string, of 's': string
'p': pointer, of 'p': pointer
} else: EOutOfRange
var expectedType = find(FormatChars, c, EOutOfRange)
var actualType = args[i].getType var actualType = args[i].getType
inc i inc i
@ -3642,15 +3670,20 @@ proc with no side effects:
destructor pragma destructor pragma
----------------- -----------------
`RAII`:idx:
`automatic variables`:idx:
`destructors`:idx:
The `destructor` pragma is used to mark a proc to act as a type destructor. The `destructor` pragma is used to mark a proc to act as a type destructor.
The proc must have a single parameter, having a concrete type. The proc must have a single parameter with a concrete type (the name of a
generic type is allowed too).
Destructors will be automatically invoked when a local stack variable goes Destructors will be automatically invoked when a local stack variable goes
out of scope. If a record type features a field with destructable type and out of scope.
If a record type features a field with destructable type and
the user have not provided explicit implementation, Nimrod will automatically the user have not provided explicit implementation, Nimrod will automatically
generate a destructor for the record type. generate a destructor for the record type. Nimrod will automatically insert
calls to any base class destructors in both user-defined and generated
destructors.
procvar pragma procvar pragma
-------------- --------------
@ -3658,7 +3691,6 @@ The `procvar`:idx: pragma is used to mark a proc that it can be passed to a
procedural variable. procedural variable.
compileTime pragma compileTime pragma
------------------ ------------------
The `compileTime`:idx: pragma is used to mark a proc to be used at compile The `compileTime`:idx: pragma is used to mark a proc to be used at compile

View file

@ -84,12 +84,6 @@ type
## represents a Nimrod identifier in the AST ## represents a Nimrod identifier in the AST
TNimrodSymbol {.final.} = object # hidden TNimrodSymbol {.final.} = object # hidden
TNimrodType {.final.} = object # hidden
PNimrodType* {.compilerproc.} = ref TNimrodType
## represents a Nimrod type in the compiler; currently this is not very
## useful as there is no API to deal with Nimrod types.
PNimrodSymbol* {.compilerproc.} = ref TNimrodSymbol PNimrodSymbol* {.compilerproc.} = ref TNimrodSymbol
## represents a Nimrod *symbol* in the compiler; a *symbol* is a looked-up ## represents a Nimrod *symbol* in the compiler; a *symbol* is a looked-up
## *ident*. ## *ident*.
@ -140,14 +134,14 @@ proc intVal*(n: PNimrodNode): biggestInt {.magic: "NIntVal".}
proc floatVal*(n: PNimrodNode): biggestFloat {.magic: "NFloatVal".} proc floatVal*(n: PNimrodNode): biggestFloat {.magic: "NFloatVal".}
proc symbol*(n: PNimrodNode): PNimrodSymbol {.magic: "NSymbol".} proc symbol*(n: PNimrodNode): PNimrodSymbol {.magic: "NSymbol".}
proc ident*(n: PNimrodNode): TNimrodIdent {.magic: "NIdent".} proc ident*(n: PNimrodNode): TNimrodIdent {.magic: "NIdent".}
proc typ*(n: PNimrodNode): PNimrodType {.magic: "NGetType".} proc typ*(n: PNimrodNode): typedesc {.magic: "NGetType".}
proc strVal*(n: PNimrodNode): string {.magic: "NStrVal".} proc strVal*(n: PNimrodNode): string {.magic: "NStrVal".}
proc `intVal=`*(n: PNimrodNode, val: biggestInt) {.magic: "NSetIntVal".} proc `intVal=`*(n: PNimrodNode, val: biggestInt) {.magic: "NSetIntVal".}
proc `floatVal=`*(n: PNimrodNode, val: biggestFloat) {.magic: "NSetFloatVal".} proc `floatVal=`*(n: PNimrodNode, val: biggestFloat) {.magic: "NSetFloatVal".}
proc `symbol=`*(n: PNimrodNode, val: PNimrodSymbol) {.magic: "NSetSymbol".} proc `symbol=`*(n: PNimrodNode, val: PNimrodSymbol) {.magic: "NSetSymbol".}
proc `ident=`*(n: PNimrodNode, val: TNimrodIdent) {.magic: "NSetIdent".} proc `ident=`*(n: PNimrodNode, val: TNimrodIdent) {.magic: "NSetIdent".}
proc `typ=`*(n: PNimrodNode, typ: PNimrodType) {.magic: "NSetType".} proc `typ=`*(n: PNimrodNode, typ: typedesc) {.magic: "NSetType".}
proc `strVal=`*(n: PNimrodNode, val: string) {.magic: "NSetStrVal".} proc `strVal=`*(n: PNimrodNode, val: string) {.magic: "NSetStrVal".}
proc newNimNode*(kind: TNimrodNodeKind, proc newNimNode*(kind: TNimrodNodeKind,

View file

@ -149,7 +149,7 @@ else: # UNIX-like operating system
FileSystemCaseSensitive* = true FileSystemCaseSensitive* = true
ExeExt* = "" ExeExt* = ""
ScriptExt* = "" ScriptExt* = ""
DynlibFormat* = "lib$1.so" DynlibFormat* = when defined(macosx): "lib$1.dylib" else: "lib$1.so"
when defined(macosx) or defined(bsd): when defined(macosx) or defined(bsd):
var var

View file

@ -51,9 +51,10 @@ type
`nil` {.magic: "Nil".} `nil` {.magic: "Nil".}
expr* {.magic: Expr.} ## meta type to denote an expression (for templates) expr* {.magic: Expr.} ## meta type to denote an expression (for templates)
stmt* {.magic: Stmt.} ## meta type to denote a statement (for templates) stmt* {.magic: Stmt.} ## meta type to denote a statement (for templates)
typeDesc* {.magic: TypeDesc.} ## meta type to denote typeDesc* {.magic: TypeDesc.} ## meta type to denote a type description
## a type description (for templates)
void* {.magic: "VoidType".} ## meta type to denote the absense of any type void* {.magic: "VoidType".} ## meta type to denote the absense of any type
auto* = expr
any* = distinct auto
TSignedInt* = int|int8|int16|int32|int64 TSignedInt* = int|int8|int16|int32|int64
## type class matching all signed integer types ## type class matching all signed integer types
@ -111,6 +112,11 @@ proc new*[T](a: var ref T) {.magic: "New", noSideEffect.}
## creates a new object of type ``T`` and returns a safe (traced) ## creates a new object of type ``T`` and returns a safe (traced)
## reference to it in ``a``. ## reference to it in ``a``.
proc new(T: typedesc): ref T =
## creates a new object of type ``T`` and returns a safe (traced)
## reference to it as result value
new(result)
proc internalNew*[T](a: var ref T) {.magic: "New", noSideEffect.} proc internalNew*[T](a: var ref T) {.magic: "New", noSideEffect.}
## leaked implementation detail. Do not use. ## leaked implementation detail. Do not use.
@ -538,7 +544,7 @@ proc abs*(x: int64): int64 {.magic: "AbsI64", noSideEffect.}
## checking is turned on). ## checking is turned on).
type type
IntMax32 = distinct int|int8|int16|int32 IntMax32 = int|int8|int16|int32
proc `+%` *(x, y: IntMax32): IntMax32 {.magic: "AddU", noSideEffect.} proc `+%` *(x, y: IntMax32): IntMax32 {.magic: "AddU", noSideEffect.}
proc `+%` *(x, y: Int64): Int64 {.magic: "AddU", noSideEffect.} proc `+%` *(x, y: Int64): Int64 {.magic: "AddU", noSideEffect.}
@ -1315,7 +1321,6 @@ iterator items*(a: cstring): char {.inline.} =
yield a[i] yield a[i]
inc(i) inc(i)
when not defined(booting):
iterator items*(E: typedesc[enum]): E = iterator items*(E: typedesc[enum]): E =
## iterates over the values of the enum ``E``. ## iterates over the values of the enum ``E``.
for v in low(E)..high(E): for v in low(E)..high(E):
@ -2111,7 +2116,7 @@ proc `/`*(x, y: int): float {.inline, noSideEffect.} =
## integer division that results in a float. ## integer division that results in a float.
result = toFloat(x) / toFloat(y) result = toFloat(x) / toFloat(y)
template `-|`(b, s: expr): expr = template `-|`*(b, s: expr): expr =
(if b >= 0: b else: s.len + b) (if b >= 0: b else: s.len + b)
proc `[]`*(s: string, x: TSlice[int]): string {.inline.} = proc `[]`*(s: string, x: TSlice[int]): string {.inline.} =

42
tests/compile/tisop.nim Normal file
View file

@ -0,0 +1,42 @@
import typetraits
type
TRecord = (tuple) or (object)
TFoo[T, U] = object
x: int
when T is string:
y: float
else:
y: string
when U is TRecord:
z: float
E = enum A, B, C
macro m(t: typedesc): typedesc =
if t is enum:
result = string
else:
result = int
var f: TFoo[int, int]
static: assert(f.y.type.name == "string")
when compiles(f.z):
{.error: "Foo should not have a `z` field".}
proc p(a, b) =
when a.type is int:
static: assert false
var f: TFoo[m(a.type), b.type]
static:
assert f.x.type.name == "int"
assert f.y.type.name == "float"
assert f.z.type.name == "float"
p(A, f)

View file

@ -0,0 +1,12 @@
import macros, typetraits
macro checkType(ex, expected: expr): stmt {.immediate.} =
var t = ex.typ
assert t.name == expected.strVal
proc voidProc = echo "hello"
proc intProc(a, b): int = 10
checkType(voidProc(), "void")
checkType(intProc(10, 20.0), "int")
checkType(noproc(10, 20.0), "Error Type")

View file

@ -2,8 +2,8 @@ type
TFoo[T] = object TFoo[T] = object
val: T val: T
T1 = distinct expr T1 = expr
T2 = distinct expr T2 = expr
proc takesExpr(x, y) = proc takesExpr(x, y) =
echo x, y echo x, y

View file

@ -0,0 +1,30 @@
discard """
file: "tcaseexpr1.nim"
line: 29
errormsg: "type mismatch: got (string) but expected 'int'"
line: 23
errormsg: "not all cases are covered"
"""
type
E = enum A, B, C
proc foo(x): auto =
return case x
of 1..9: "digit"
else: "number"
var r = foo(10)
var x = C
var t1 = case x:
of A: "a"
of B: "b"
var t2 = case x:
of A: 10
of B, C: "23"

View file

@ -1,6 +1,6 @@
discard """ discard """
file: "system.nim" file: "system.nim"
line: 643 line: 649
errormsg: "type mismatch" errormsg: "type mismatch"
""" """

View file

@ -1,6 +1,6 @@
discard """ discard """
file: "tcasestm.nim" file: "tcasestm.nim"
output: "ayyy" output: "ayyydd"
""" """
# Test the case statement # Test the case statement
@ -22,16 +22,18 @@ of "aa", "bb": write(stdout, "Du bist nicht mein Meister")
of "cc", "hash", "when": nil of "cc", "hash", "when": nil
of "will", "it", "finally", "be", "generated": nil of "will", "it", "finally", "be", "generated": nil
case i var z = case i
of 1..5, 8, 9: nil of 1..5, 8, 9: "aa"
of 6, 7: nil of 6, 7: "bb"
elif x == "Ha": elif x == "Ha":
nil "cc"
elif x == "yyy": elif x == "yyy":
write(stdout, x) write(stdout, x)
"dd"
else: else:
nil "zz"
echo z
#OUT ayyy #OUT ayyy

View file

@ -0,0 +1,33 @@
discard """
msg: "instantiated for string\ninstantiated for int\ninstantiated for bool"
output: "int\nseq[string]\nA\nB\n100\ntrue"
"""
import typetraits
proc plus(a, b): auto = a + b
proc makePair(a, b): auto = (first: a, second: b)
proc `+`(a, b: string): seq[string] = @[a, b]
var i = plus(10, 20)
var s = plus("A", "B")
var p = makePair("key", 100)
static: assert p[0].type is string
echo i.type.name
echo s.type.name
proc inst(a): auto =
static: echo "instantiated for ", a.type.name
result = a
echo inst("A")
echo inst("B")
echo inst(100)
echo inst(true)
# XXX: [string, tyGenericParam] is cached instead of [string, string]
# echo inst[string, string]("C")

View file

@ -2,6 +2,39 @@
News News
==== ====
2012-XX-XX Version 0.9.XX released
==================================
Version 0.8.XX has been released! Get it `here <download.html>`_.
Bugfixes
--------
Library Additions
-----------------
Changes affecting backwards compatibility
-----------------------------------------
Compiler Additions
------------------
Language Additions
------------------
- ``case expressions`` are now supported.
- table constructors now mimic more closely the syntax of case... of...
- Nimrod can now infer the return type of a proc from its body
2012-09-23 Version 0.9.0 released 2012-09-23 Version 0.9.0 released
================================= =================================