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

This commit is contained in:
Araq 2012-04-01 01:01:25 +02:00
commit f788f603fe
27 changed files with 394 additions and 176 deletions

View file

@ -258,7 +258,7 @@ type
tyGenericParam, # ``a`` in the above patterns tyGenericParam, # ``a`` in the above patterns
tyDistinct, tyDistinct,
tyEnum, tyEnum,
tyOrdinal, # misnamed: should become 'tyConstraint' tyOrdinal, # integer types (including enums and boolean)
tyArray, tyArray,
tyObject, tyObject,
tyTuple, tyTuple,
@ -277,6 +277,7 @@ type
tyConst, tyMutable, tyVarargs, tyConst, tyMutable, tyVarargs,
tyIter, # unused tyIter, # unused
tyProxy # currently unused tyProxy # currently unused
tyTypeClass,
const const
tyPureObject* = tyTuple tyPureObject* = tyTuple
@ -308,6 +309,8 @@ type
tfFromGeneric # type is an instantiation of a generic; this is needed tfFromGeneric # type is an instantiation of a generic; this is needed
# because for instantiations of objects, structural # because for instantiations of objects, structural
# type equality has to be used # type equality has to be used
tfAll # type class requires all constraints to be met (default)
tfAny # type class requires any constraint to be met
TTypeFlags* = set[TTypeFlag] TTypeFlags* = set[TTypeFlag]
@ -707,6 +710,15 @@ proc `[]`*(n: PNode, i: int): PNode {.inline.} =
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!
proc linkTo*(t: PType, s: PSym): PType {.discardable.} =
t.sym = s
s.typ = t
result = t
proc linkTo*(s: PSym, t: PType): PSym {.discardable.} =
t.sym = s
s.typ = t
result = s
const # for all kind of hash tables: const # for all kind of hash tables:
GrowthFactor* = 2 # must be power of 2, > 0 GrowthFactor* = 2 # must be power of 2, > 0

View file

@ -130,6 +130,7 @@ proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
var length = sonsLen(ri) var length = sonsLen(ri)
for i in countup(1, length - 1): for i in countup(1, length - 1):
assert(sonsLen(typ) == sonsLen(typ.n)) assert(sonsLen(typ) == sonsLen(typ.n))
if ri.sons[i].typ.isCompileTimeOnly: continue
if i < sonsLen(typ): if i < sonsLen(typ):
assert(typ.n.sons[i].kind == nkSym) assert(typ.n.sons[i].kind == nkSym)
app(pl, genArg(p, ri.sons[i], typ.n.sons[i].sym)) app(pl, genArg(p, ri.sons[i], typ.n.sons[i].sym))

View file

@ -7,6 +7,8 @@
# distribution, for details about the copyright. # distribution, for details about the copyright.
# #
# included from cgen.nim
# ------------------------- Name Mangling -------------------------------- # ------------------------- Name Mangling --------------------------------
proc mangle(name: string): string = proc mangle(name: string): string =
@ -48,6 +50,9 @@ proc mangleName(s: PSym): PRope =
app(result, toRope(s.id)) app(result, toRope(s.id))
s.loc.r = result s.loc.r = result
proc isCompileTimeOnly(t: PType): bool =
result = t.kind in {tyTypedesc, tyExpr}
proc getTypeName(typ: PType): PRope = proc getTypeName(typ: PType): PRope =
if (typ.sym != nil) and ({sfImportc, sfExportc} * typ.sym.flags != {}) and if (typ.sym != nil) and ({sfImportc, sfExportc} * typ.sym.flags != {}) and
(gCmd != cmdCompileToLLVM): (gCmd != cmdCompileToLLVM):
@ -187,6 +192,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var PRope,
for i in countup(1, sonsLen(t.n) - 1): for i in countup(1, sonsLen(t.n) - 1):
if t.n.sons[i].kind != nkSym: InternalError(t.n.info, "genProcParams") if t.n.sons[i].kind != nkSym: InternalError(t.n.info, "genProcParams")
var param = t.n.sons[i].sym var param = t.n.sons[i].sym
if isCompileTimeOnly(param.typ): continue
fillLoc(param.loc, locParam, param.typ, mangleName(param), OnStack) fillLoc(param.loc, locParam, param.typ, mangleName(param), OnStack)
app(params, getParamTypeDesc(m, param.typ, check)) app(params, getParamTypeDesc(m, param.typ, check))
if ccgIntroducedPtr(param): if ccgIntroducedPtr(param):
@ -206,8 +212,8 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var PRope,
arr = arr.sons[0] arr = arr.sons[0]
if i < sonsLen(t.n) - 1: app(params, ", ") if i < sonsLen(t.n) - 1: app(params, ", ")
if (t.sons[0] != nil) and isInvalidReturnType(t.sons[0]): if (t.sons[0] != nil) and isInvalidReturnType(t.sons[0]):
if params != nil: app(params, ", ")
var arr = t.sons[0] var arr = t.sons[0]
if params != nil: app(params, ", ")
app(params, getTypeDescAux(m, arr, check)) app(params, getTypeDescAux(m, arr, check))
if (mapReturnType(t.sons[0]) != ctArray) or (gCmd == cmdCompileToLLVM): if (mapReturnType(t.sons[0]) != ctArray) or (gCmd == cmdCompileToLLVM):
app(params, "*") app(params, "*")

View file

@ -82,9 +82,11 @@ proc GetUniqueType*(key: PType): PType =
if result == nil: if result == nil:
gCanonicalTypes[k] = key gCanonicalTypes[k] = key
result = key result = key
of tyGenericParam, tyTypeClass:
InternalError("GetUniqueType")
of tyGenericInst, tyDistinct, tyOrdinal, tyMutable, tyConst, tyIter: of tyGenericInst, tyDistinct, tyOrdinal, tyMutable, tyConst, tyIter:
result = GetUniqueType(lastSon(key)) result = GetUniqueType(lastSon(key))
of tyArrayConstr, tyGenericInvokation, tyGenericBody, tyGenericParam, of tyArrayConstr, tyGenericInvokation, tyGenericBody,
tyOpenArray, tyArray, tyTuple, tySet, tyRange, tyOpenArray, tyArray, tyTuple, tySet, tyRange,
tyPtr, tyRef, tySequence, tyForward, tyVarargs, tyProxy, tyVar: tyPtr, tyRef, tySequence, tyForward, tyVarargs, tyProxy, tyVar:
# we have to do a slow linear search because types may need # we have to do a slow linear search because types may need

View file

@ -606,6 +606,7 @@ proc genProcAux(m: BModule, prc: PSym) =
res.loc.s = OnUnknown res.loc.s = OnUnknown
for i in countup(1, sonsLen(prc.typ.n) - 1): for i in countup(1, sonsLen(prc.typ.n) - 1):
var param = prc.typ.n.sons[i].sym var param = prc.typ.n.sons[i].sym
if param.typ.isCompileTimeOnly: continue
assignParam(p, param) assignParam(p, param)
closureSetup(p, prc) closureSetup(p, prc)
genStmts(p, prc.getBody) # modifies p.locals, p.init, etc. genStmts(p, prc.getBody) # modifies p.locals, p.init, etc.

View file

@ -111,7 +111,7 @@ proc mapType(typ: PType): TEcmasTypeKind =
result = etyObject result = etyObject
of tyNil: result = etyNull of tyNil: result = etyNull
of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvokation, tyNone, of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvokation, tyNone,
tyForward, tyEmpty, tyExpr, tyStmt, tyTypeDesc: tyForward, tyEmpty, tyExpr, tyStmt, tyTypeDesc, tyTypeClass:
result = etyNone result = etyNone
of tyProc: result = etyProc of tyProc: result = etyProc
of tyCString: result = etyString of tyCString: result = etyString

View file

@ -16,7 +16,7 @@
import import
strutils, magicsys, lists, options, ast, astalgo, trees, treetab, nimsets, strutils, magicsys, lists, options, ast, astalgo, trees, treetab, nimsets,
msgs, os, condsyms, idents, renderer, types, passes, semfold, transf, msgs, os, condsyms, idents, renderer, types, passes, semfold, transf,
parser, ropes, rodread parser, ropes, rodread, idgen
type type
PStackFrame* = ref TStackFrame PStackFrame* = ref TStackFrame
@ -843,6 +843,7 @@ proc evalParseStmt(c: PEvalContext, n: PNode): PNode =
result.typ = newType(tyStmt, c.module) result.typ = newType(tyStmt, c.module)
proc evalTemplateAux*(templ, actual: PNode, sym: PSym): PNode = proc evalTemplateAux*(templ, actual: PNode, sym: PSym): PNode =
inc genSymBaseId
case templ.kind case templ.kind
of nkSym: of nkSym:
var p = templ.sym var p = templ.sym
@ -866,26 +867,29 @@ proc evalTemplateArgs(n: PNode, s: PSym): PNode =
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
a = sonsLen(n) a = sonsLen(n)
else: a = 0 else: a = 0
var f = sonsLen(s.typ) var f = s.typ.sonsLen
if a > f: GlobalError(n.info, errWrongNumberOfArguments) if a > f: GlobalError(n.info, errWrongNumberOfArguments)
result = copyNode(n) result = copyNode(n)
for i in countup(1, f - 1): for i in countup(1, f - 1):
var arg = if i < a: n.sons[i] else: copyTree(s.typ.n.sons[i].sym.ast) var arg = if i < a: n.sons[i] else: copyTree(s.typ.n.sons[i].sym.ast)
if arg == nil or arg.kind == nkEmpty:
LocalError(n.info, errWrongNumberOfArguments)
addSon(result, arg) addSon(result, arg)
var evalTemplateCounter = 0 var evalTemplateCounter* = 0
# to prevent endless recursion in templates instantation # to prevent endless recursion in templates instantation
proc evalTemplate(n: PNode, sym: PSym): PNode = proc evalTemplate*(n: PNode, sym: PSym): PNode =
inc(evalTemplateCounter) inc(evalTemplateCounter)
if evalTemplateCounter > 100: if evalTemplateCounter > 100:
GlobalError(n.info, errTemplateInstantiationTooNested) GlobalError(n.info, errTemplateInstantiationTooNested)
result = n
# replace each param by the corresponding node: # replace each param by the corresponding node:
var args = evalTemplateArgs(n, sym) var args = evalTemplateArgs(n, sym)
result = evalTemplateAux(sym.getBody, args, sym) result = evalTemplateAux(sym.getBody, args, sym)
dec(evalTemplateCounter) dec(evalTemplateCounter)
proc evalExpandToAst(c: PEvalContext, original: PNode): PNode = proc evalExpandToAst(c: PEvalContext, original: PNode): PNode =
@ -1312,6 +1316,7 @@ proc evalMacroCall*(c: PEvalContext, n: PNode, sym: PSym): PNode =
if evalTemplateCounter > 100: if evalTemplateCounter > 100:
GlobalError(n.info, errTemplateInstantiationTooNested) GlobalError(n.info, errTemplateInstantiationTooNested)
inc genSymBaseId
var s = newStackFrame() var s = newStackFrame()
s.call = n s.call = n
setlen(s.params, 2) setlen(s.params, 2)

View file

@ -11,7 +11,7 @@
import idents, strutils, os, options import idents, strutils, os, options
var gFrontEndId, gBackendId*: int var gFrontEndId, gBackendId*, genSymBaseId*: int
const const
debugIds* = false debugIds* = false
@ -25,7 +25,7 @@ proc registerID*(id: PIdObj) =
when debugIDs: when debugIDs:
if id.id == -1 or ContainsOrIncl(usedIds, id.id): if id.id == -1 or ContainsOrIncl(usedIds, id.id):
InternalError("ID already used: " & $id.id) InternalError("ID already used: " & $id.id)
proc getID*(): int {.inline.} = proc getID*(): int {.inline.} =
result = gFrontEndId result = gFrontEndId
inc(gFrontEndId) inc(gFrontEndId)
@ -34,6 +34,9 @@ proc backendId*(): int {.inline.} =
result = gBackendId result = gBackendId
inc(gBackendId) inc(gBackendId)
proc genSym*(basename: string): PIdent =
result = getIdent(basename & $genSymBaseId)
proc setId*(id: int) {.inline.} = proc setId*(id: int) {.inline.} =
gFrontEndId = max(gFrontEndId, id + 1) gFrontEndId = max(gFrontEndId, id + 1)

View file

@ -11,7 +11,7 @@
import import
intsets, ast, astalgo, idents, semdata, types, msgs, options, rodread, intsets, ast, astalgo, idents, semdata, types, msgs, options, rodread,
renderer renderer, wordrecg, idgen
proc considerAcc*(n: PNode): PIdent = proc considerAcc*(n: PNode): PIdent =
case n.kind case n.kind
@ -21,6 +21,11 @@ proc considerAcc*(n: PNode): PIdent =
case n.len case n.len
of 0: GlobalError(n.info, errIdentifierExpected, renderTree(n)) of 0: GlobalError(n.info, errIdentifierExpected, renderTree(n))
of 1: result = considerAcc(n.sons[0]) of 1: result = considerAcc(n.sons[0])
of 2:
if n[0].ident.id == ord(wStar):
result = genSym(n[1].ident.s)
else:
result = getIdent(n[0].ident.s & n[1].ident.s)
else: else:
var id = "" var id = ""
for i in 0.. <n.len: for i in 0.. <n.len:

View file

@ -662,3 +662,8 @@ proc InternalError*(info: TLineInfo, errMsg: string) =
proc InternalError*(errMsg: string) = proc InternalError*(errMsg: string) =
writeContext(UnknownLineInfo()) writeContext(UnknownLineInfo())
rawMessage(errInternal, errMsg) rawMessage(errInternal, errMsg)
template AssertNotNil*(e: expr): expr =
if(e == nil): InternalError($InstantiationInfo())
e

View file

@ -219,3 +219,6 @@ proc binaryStrSearch*(x: openarray[string], y: string): int =
return mid return mid
result = - 1 result = - 1
# Can we keep this? I'm using it all the time
template nimdbg*: expr = c.filename.endsWith"nimdbg.nim"

View file

@ -91,7 +91,7 @@ proc semConstExpr(c: PContext, n: PNode): PNode =
proc semAndEvalConstExpr(c: PContext, n: PNode): PNode = proc semAndEvalConstExpr(c: PContext, n: PNode): PNode =
result = semConstExpr(c, n) result = semConstExpr(c, n)
include seminst, semcall include seminst, semcall
proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode = proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode =

View file

@ -180,14 +180,16 @@ proc addToLib(lib: PLib, sym: PSym) =
sym.annex = lib sym.annex = lib
proc makePtrType(c: PContext, baseType: PType): PType = proc makePtrType(c: PContext, baseType: PType): PType =
if (baseType == nil): InternalError("makePtrType")
result = newTypeS(tyPtr, c) result = newTypeS(tyPtr, c)
addSon(result, baseType) addSon(result, baseType.AssertNotNil)
proc makeVarType(c: PContext, baseType: PType): PType = proc makeVarType(c: PContext, baseType: PType): PType =
if (baseType == nil): InternalError("makeVarType")
result = newTypeS(tyVar, c) result = newTypeS(tyVar, c)
addSon(result, baseType) addSon(result, baseType.AssertNotNil)
proc makeTypeDesc*(c: PContext, typ: PType): PType =
result = newTypeS(tyTypeDesc, c)
result.addSon(typ.AssertNotNil)
proc newTypeS(kind: TTypeKind, c: PContext): PType = proc newTypeS(kind: TTypeKind, c: PContext): PType =
result = newType(kind, getCurrOwner()) result = newType(kind, getCurrOwner())

View file

@ -10,10 +10,12 @@
# this module does the semantic checking for expressions # this module does the semantic checking for expressions
# included from sem.nim # included from sem.nim
proc semExprOrTypedesc(c: PContext, n: PNode): PNode
proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode = proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode =
markUsed(n, s) markUsed(n, s)
pushInfoContext(n.info) pushInfoContext(n.info)
result = evalTemplate(c, n, s) result = evalTemplate(n, s)
if semCheck: result = semAfterMacroCall(c, result, s) if semCheck: result = semAfterMacroCall(c, result, s)
popInfoContext() popInfoContext()
@ -93,6 +95,8 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
# if a proc accesses a global variable, it is not side effect free: # if a proc accesses a global variable, it is not side effect free:
if sfGlobal in s.flags: if sfGlobal in s.flags:
incl(c.p.owner.flags, sfSideEffect) incl(c.p.owner.flags, sfSideEffect)
elif s.kind == skParam and s.typ.kind == tyExpr:
return s.typ.n
elif s.owner != c.p.owner and s.owner.kind != skModule and elif s.owner != c.p.owner and s.owner.kind != skModule and
c.p.owner.typ != nil and not IsGenericRoutine(s.owner): c.p.owner.typ != nil and not IsGenericRoutine(s.owner):
c.p.owner.typ.callConv = ccClosure c.p.owner.typ.callConv = ccClosure
@ -111,7 +115,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
else: else:
markUsed(n, s) markUsed(n, s)
result = newSymNode(s, n.info) result = newSymNode(s, n.info)
proc checkConversionBetweenObjects(info: TLineInfo, castDest, src: PType) = proc checkConversionBetweenObjects(info: TLineInfo, castDest, src: PType) =
var diff = inheritanceDiff(castDest, src) var diff = inheritanceDiff(castDest, src)
if diff == high(int): if diff == high(int):
@ -247,16 +251,31 @@ proc semIs(c: PContext, n: PNode): PNode =
else: else:
GlobalError(n.info, errXExpectsTwoArguments, "is") GlobalError(n.info, errXExpectsTwoArguments, "is")
proc semExprOrTypedesc(c: PContext, n: PNode): PNode =
# XXX: Currently, semExprWithType will return the same type
# for nodes such as (100) or (int).
# This is inappropriate. The type of the first expression
# should be "int", while the type of the second one should
# be typeDesc(int).
# Ideally, this should be fixed in semExpr, but right now
# there are probably users that depend on the present behavior.
# XXX: Investigate current uses of efAllowType and fix them to
# work with tyTypeDesc.
result = semExprWithType(c, n, {efAllowType})
if result.kind == nkSym and result.sym.kind == skType and
result.typ.kind != tyTypeDesc:
result.typ = makeTypeDesc(c, result.typ)
proc semOpAux(c: PContext, n: PNode) = proc semOpAux(c: PContext, n: PNode) =
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
var a = n.sons[i] var a = n.sons[i]
if a.kind == nkExprEqExpr and sonsLen(a) == 2: if a.kind == nkExprEqExpr and sonsLen(a) == 2:
var info = a.sons[0].info var info = a.sons[0].info
a.sons[0] = newIdentNode(considerAcc(a.sons[0]), info) a.sons[0] = newIdentNode(considerAcc(a.sons[0]), info)
a.sons[1] = semExprWithType(c, a.sons[1], {efAllowType}) a.sons[1] = semExprOrTypedesc(c, a.sons[1])
a.typ = a.sons[1].typ a.typ = a.sons[1].typ
else: else:
n.sons[i] = semExprWithType(c, a, {efAllowType}) n.sons[i] = semExprOrTypedesc(c, a)
proc overloadedCallOpr(c: PContext, n: PNode): PNode = proc overloadedCallOpr(c: PContext, n: PNode): PNode =
# quick check if there is *any* () operator overloaded: # quick check if there is *any* () operator overloaded:
@ -822,7 +841,7 @@ proc semDeref(c: PContext, n: PNode): PNode =
of tyRef, tyPtr: n.typ = t.sons[0] of tyRef, tyPtr: n.typ = t.sons[0]
else: result = nil else: result = nil
#GlobalError(n.sons[0].info, errCircumNeedsPointer) #GlobalError(n.sons[0].info, errCircumNeedsPointer)
proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
## returns nil if not a built-in subscript operator; also called for the ## returns nil if not a built-in subscript operator; also called for the
## checking of assignments ## checking of assignments
@ -833,7 +852,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
result.add(x[0]) result.add(x[0])
return return
checkMinSonsLen(n, 2) checkMinSonsLen(n, 2)
n.sons[0] = semExprWithType(c, n.sons[0], flags - {efAllowType}) n.sons[0] = semExprOrTypedesc(c, n.sons[0])
var arr = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyPtr, tyRef}) var arr = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyPtr, tyRef})
case arr.kind case arr.kind
of tyArray, tyOpenArray, tyArrayConstr, tySequence, tyString, tyCString: of tyArray, tyOpenArray, tyArrayConstr, tySequence, tyString, tyCString:
@ -848,6 +867,11 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
result = n result = n
result.typ = elemType(arr) result.typ = elemType(arr)
#GlobalError(n.info, errIndexTypesDoNotMatch) #GlobalError(n.info, errIndexTypesDoNotMatch)
of tyTypeDesc:
result = n.sons[0] # The result so far is a tyTypeDesc bound to
# a tyGenericBody. The line below will substitute
# it with the instantiated type.
result.typ.sons[0] = semTypeNode(c, n, nil).linkTo(result.sym)
of tyTuple: of tyTuple:
checkSonsLen(n, 2) checkSonsLen(n, 2)
n.sons[0] = makeDeref(n.sons[0]) n.sons[0] = makeDeref(n.sons[0])
@ -1024,7 +1048,7 @@ proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym,
markUsed(n, expandedSym) markUsed(n, expandedSym)
for i in countup(1, macroCall.len-1): for i in countup(1, macroCall.len-1):
macroCall.sons[i] = semExprWithType(c, macroCall[i], {efAllowType}) macroCall.sons[i] = semExprWithType(c, macroCall[i], {})
# Preserve the magic symbol in order to be handled in evals.nim # Preserve the magic symbol in order to be handled in evals.nim
n.sons[0] = newSymNode(magicSym, n.info) n.sons[0] = newSymNode(magicSym, n.info)
@ -1287,6 +1311,12 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
of nkBind: of nkBind:
Message(n.info, warnDeprecated, "bind") Message(n.info, warnDeprecated, "bind")
result = semExpr(c, n.sons[0], flags) result = semExpr(c, n.sons[0], flags)
of nkTypeOfExpr:
var typ = semTypeNode(c, n, nil)
if typ.sym == nil:
typ = copyType(typ, typ.owner, true)
typ.linkTo(newSym(skType, getIdent"typedesc", typ.owner))
result = newSymNode(typ.sym, n.info)
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
# check if it is an expression macro: # check if it is an expression macro:
checkMinSonsLen(n, 1) checkMinSonsLen(n, 1)

View file

@ -20,7 +20,7 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
if a.kind != nkSym: if a.kind != nkSym:
InternalError(a.info, "instantiateGenericParamList; no symbol") InternalError(a.info, "instantiateGenericParamList; no symbol")
var q = a.sym var q = a.sym
if q.typ.kind notin {tyTypeDesc, tyGenericParam}: continue if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyTypeClass, tyExpr}: continue
var s = newSym(skType, q.name, getCurrOwner()) var s = newSym(skType, q.name, getCurrOwner())
s.info = q.info s.info = q.info
s.flags = s.flags + {sfUsed, sfFromGeneric} s.flags = s.flags + {sfUsed, sfFromGeneric}
@ -107,8 +107,6 @@ proc sideEffectsCheck(c: PContext, s: PSym) =
s.ast.sons[genericParamsPos].kind == nkEmpty: s.ast.sons[genericParamsPos].kind == nkEmpty:
c.threadEntries.add(s) c.threadEntries.add(s)
template nimdbg: expr = c.filename.endsWith"nimdbg.nim"
proc applyConcreteTypesToSig(genericProc: PSym, concTypes: seq[PType]): PType = proc applyConcreteTypesToSig(genericProc: PSym, concTypes: seq[PType]): PType =
# XXX: This is intended to replace the use of semParamList in generateInstance. # XXX: This is intended to replace the use of semParamList in generateInstance.
# The results of semParamList's analysis are already encoded in the original # The results of semParamList's analysis are already encoded in the original

View file

@ -9,67 +9,6 @@
# included from sem.nim # included from sem.nim
proc isExpr(n: PNode): bool =
# returns true if ``n`` looks like an expression
case n.kind
of nkIdent..nkNilLit:
result = true
of nkCall..pred(nkAsgn):
for i in countup(0, sonsLen(n) - 1):
if not isExpr(n.sons[i]):
return false
result = true
else: result = false
proc isTypeDesc(n: PNode): bool =
# returns true if ``n`` looks like a type desc
case n.kind
of nkIdent, nkSym, nkType:
result = true
of nkDotExpr, nkBracketExpr:
for i in countup(0, sonsLen(n) - 1):
if not isTypeDesc(n.sons[i]):
return false
result = true
of nkTypeOfExpr..nkEnumTy:
result = true
else: result = false
var evalTemplateCounter: int = 0
# to prevend endless recursion in templates instantation
proc evalTemplateArgs(c: PContext, n: PNode, s: PSym): PNode =
var
f, a: int
arg: PNode
f = sonsLen(s.typ)
# if the template has zero arguments, it can be called without ``()``
# `n` is then a nkSym or something similar
case n.kind
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
a = sonsLen(n)
else: a = 0
if a > f: LocalError(n.info, errWrongNumberOfArguments)
result = copyNode(n)
for i in countup(1, f - 1):
if i < a: arg = n.sons[i]
else: arg = copyTree(s.typ.n.sons[i].sym.ast)
if arg == nil or arg.kind == nkEmpty:
LocalError(n.info, errWrongNumberOfArguments)
addSon(result, arg)
proc evalTemplate*(c: PContext, n: PNode, sym: PSym): PNode =
var args: PNode
inc(evalTemplateCounter)
if evalTemplateCounter <= 100:
# replace each param by the corresponding node:
args = evalTemplateArgs(c, n, sym)
result = evalTemplateAux(sym.getBody, args, sym)
dec(evalTemplateCounter)
else:
GlobalError(n.info, errTemplateInstantiationTooNested)
result = n
proc symChoice(c: PContext, n: PNode, s: PSym): PNode = proc symChoice(c: PContext, n: PNode, s: PSym): PNode =
var var
a: PSym a: PSym

View file

@ -180,6 +180,8 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
result = qualifiedLookup(c, n, {checkAmbiguity, checkUndeclared}) result = qualifiedLookup(c, n, {checkAmbiguity, checkUndeclared})
if result != nil: if result != nil:
markUsed(n, result) markUsed(n, result)
if result.kind == skParam and result.typ.kind == tyTypeDesc:
return result.typ.sons[0].sym
if result.kind != skType: GlobalError(n.info, errTypeExpected) if result.kind != skType: GlobalError(n.info, errTypeExpected)
if result.typ.kind != tyGenericParam: if result.typ.kind != tyGenericParam:
# XXX get rid of this hack! # XXX get rid of this hack!
@ -470,42 +472,6 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
result.n = newNodeI(nkRecList, n.info) result.n = newNodeI(nkRecList, n.info)
semRecordNodeAux(c, n.sons[2], check, pos, result.n, result.sym) semRecordNodeAux(c, n.sons[2], check, pos, result.n, result.sym)
proc addTypeVarsOfGenericBody(c: PContext, t: PType, genericParams: PNode,
cl: var TIntSet): PType =
result = t
if t == nil: return
if ContainsOrIncl(cl, t.id): return
case t.kind
of tyGenericBody:
result = newTypeS(tyGenericInvokation, c)
addSon(result, t)
for i in countup(0, sonsLen(t) - 2):
if t.sons[i].kind != tyGenericParam:
InternalError("addTypeVarsOfGenericBody")
# do not declare ``TKey`` twice:
#if not ContainsOrIncl(cl, t.sons[i].sym.ident.id):
var s = copySym(t.sons[i].sym)
s.position = sonsLen(genericParams)
if s.typ == nil or s.typ.kind != tyGenericParam:
InternalError("addTypeVarsOfGenericBody 2")
addDecl(c, s)
addSon(genericParams, newSymNode(s))
addSon(result, t.sons[i])
of tyGenericInst:
var L = sonsLen(t) - 1
t.sons[L] = addTypeVarsOfGenericBody(c, t.sons[L], genericParams, cl)
of tyGenericInvokation:
for i in countup(1, sonsLen(t) - 1):
t.sons[i] = addTypeVarsOfGenericBody(c, t.sons[i], genericParams, cl)
else:
for i in countup(0, sonsLen(t) - 1):
t.sons[i] = addTypeVarsOfGenericBody(c, t.sons[i], genericParams, cl)
proc paramType(c: PContext, n, genericParams: PNode, cl: var TIntSet): PType =
result = semTypeNode(c, n, nil)
if genericParams != nil and sonsLen(genericParams) == 0:
result = addTypeVarsOfGenericBody(c, result, genericParams, cl)
proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) = proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
if kind == skMacro and param.typ.kind in {tyTypeDesc, tyExpr, tyStmt}: if kind == skMacro and param.typ.kind in {tyTypeDesc, tyExpr, tyStmt}:
let nn = getSysSym"PNimrodNode" let nn = getSysSym"PNimrodNode"
@ -515,8 +481,43 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
else: else:
addDecl(c, param) addDecl(c, param)
proc isTypeClass(c: PContext, t: PType): bool = proc paramTypeClass(c: PContext, paramType: PType, procKind: TSymKind):
return t.kind in {tyExpr} tuple[typ: PType, id: PIdent] =
# if typ is not-nil, the param should be turned into a generic param
# if id is not nil, the generic param will bind just once (see below)
case paramType.kind:
of tyExpr:
if procKind notin {skTemplate, skMacro}:
if paramType.sonsLen == 0:
# proc(a, b: expr)
# no constraints, treat like generic param
result.typ = newTypeS(tyGenericParam, c)
else:
# proc(a: expr{string}, b: expr{nkLambda})
# overload on compile time values and AST trees
result.typ = newTypeS(tyExpr, c)
result.typ.sons = paramType.sons
of tyTypeDesc:
if procKind notin {skTemplate, skMacro}:
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
of tyGenericBody:
# type Foo[T] = object
# proc x(a: Foo, b: Foo)
result.typ = newTypeS(tyTypeClass, c)
result.typ.addSon(paramType)
result.id = paramType.sym.name # bindOnce by default
of tyTypeClass:
result.typ = copyType(paramType, getCurrOwner(), false)
else: nil
proc semProcTypeNode(c: PContext, n, genericParams: PNode, proc semProcTypeNode(c: PContext, n, genericParams: PNode,
prev: PType, kind: TSymKind): PType = prev: PType, kind: TSymKind): PType =
@ -546,9 +547,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
hasDefault = a.sons[length-1].kind != nkEmpty hasDefault = a.sons[length-1].kind != nkEmpty
if hasType: if hasType:
typ = paramType(c, a.sons[length-2], genericParams, cl) typ = semTypeNode(c, a.sons[length-2], nil)
#if matchType(typ, [(tyVar, 0)], tyGenericInvokation):
# debug a.sons[length-2][0][1]
if hasDefault: if hasDefault:
def = semExprWithType(c, a.sons[length-1]) def = semExprWithType(c, a.sons[length-1])
# check type compability between def.typ and typ: # check type compability between def.typ and typ:
@ -566,40 +566,46 @@ 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 = newSymS(skParam, a.sons[j], c) var arg = newSymS(skParam, a.sons[j], c)
arg.typ = typ var endingType = typ
if kind notin {skTemplate, skMacro} and isTypeClass(c, typ): var (typeClass, paramTypId) = paramTypeClass(c, typ, kind)
let typeClassParamId = getIdent(":tcls_" & $i & "_" & $j) if typeClass != nil:
if paramTypId == nil: paramTypId = getIdent(arg.name.s & ":type")
if genericParams == nil: if genericParams == nil:
# genericParams is nil when the proc is being instantiated # genericParams is nil when the proc is being instantiated
# the resolved type will be in scope then # the resolved type will be in scope then
var s = SymtabGet(c.tab, typeClassParamId) endingType = SymtabGet(c.tab, paramTypId).AssertNotNil.typ
arg.typ = s.typ
else: else:
var s = newSym(skType, typeClassParamId, getCurrOwner()) block addImplicitGeneric:
s.typ = newTypeS(tyGenericParam, c) # is this a bindOnce type class already present in the param list?
s.typ.sym = s for i in countup(0, genericParams.len - 1):
s.position = genericParams.len if genericParams.sons[i].sym.name == paramTypId:
genericParams.addSon(newSymNode(s)) endingType = genericParams.sons[i].typ
arg.typ = s.typ break addImplicitGeneric
var s = newSym(skType, paramTypId, getCurrOwner())
s.typ = typeClass
s.typ.sym = s
s.position = genericParams.len
genericParams.addSon(newSymNode(s))
endingType = typeClass
arg.typ = endingType
arg.position = counter arg.position = counter
inc(counter) inc(counter)
if def != nil and def.kind != nkEmpty: arg.ast = copyTree(def) if def != nil and def.kind != nkEmpty: arg.ast = copyTree(def)
if ContainsOrIncl(check, arg.name.id): if ContainsOrIncl(check, arg.name.id):
LocalError(a.sons[j].info, errAttemptToRedefine, arg.name.s) LocalError(a.sons[j].info, errAttemptToRedefine, arg.name.s)
addSon(result.n, newSymNode(arg)) addSon(result.n, newSymNode(arg))
addSon(result, typ) addSon(result, endingType)
addParamOrResult(c, arg, kind) addParamOrResult(c, arg, kind)
if n.sons[0].kind != nkEmpty: if n.sons[0].kind != nkEmpty:
var r = paramType(c, n.sons[0], genericParams, cl) var r = semTypeNode(c, n.sons[0], nil)
# turn explicit 'void' return type into 'nil' because the rest of the # turn explicit 'void' return type into 'nil' because the rest of the
# compiler only checks for 'nil': # compiler only checks for 'nil':
if skipTypes(r, {tyGenericInst}).kind != tyEmpty: if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
result.sons[0] = r result.sons[0] = r
res.typ = result.sons[0] res.typ = result.sons[0]
#if matchType(result, [(tyProc, 1), (tyVar, 0)], tyGenericInvokation):
# debug result
proc semStmtListType(c: PContext, n: PNode, prev: PType): PType = proc semStmtListType(c: PContext, n: PNode, prev: PType): PType =
checkMinSonsLen(n, 1) checkMinSonsLen(n, 1)
@ -666,9 +672,10 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
if s.ast == nil: GlobalError(n.info, errCannotInstantiateX, s.name.s) if s.ast == nil: GlobalError(n.info, errCannotInstantiateX, s.name.s)
result = instGenericContainer(c, n, result) result = instGenericContainer(c, n, result)
proc semExpandToType(c: PContext, n: PNode, sym: PSym): PType = proc semTypeFromMacro(c: PContext, n: PNode): PType =
# Expands a macro or template until a type is returned # Expands a macro or template until a type is returned
# results in GlobalError if the macro expands to something different # results in GlobalError if the macro expands to something different
var sym = expectMacroOrTemplateCall(c, n)
markUsed(n, sym) markUsed(n, sym)
case sym.kind case sym.kind
of skMacro: of skMacro:
@ -678,7 +685,7 @@ proc semExpandToType(c: PContext, n: PNode, sym: PSym): PType =
else: else:
GlobalError(n.info, errXisNoMacroOrTemplate, n.renderTree) GlobalError(n.info, errXisNoMacroOrTemplate, n.renderTree)
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
result = nil result = nil
if gCmd == cmdIdeTools: suggestExpr(c, n) if gCmd == cmdIdeTools: suggestExpr(c, n)
case n.kind case n.kind
@ -691,9 +698,27 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev) if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
else: GlobalError(n.info, errTypeExpected) else: GlobalError(n.info, errTypeExpected)
of nkCallKinds: of nkCallKinds:
# expand macros and templates let op = n.sons[0].ident.id
var expandedSym = expectMacroOrTemplateCall(c, n) if op in {ord(wAnd), ord(wOr)}:
result = semExpandToType(c, n, expandedSym) var
t1 = semTypeNode(c, n.sons[1], nil)
t2 = semTypeNode(c, n.sons[2], nil)
if t1 == nil: GlobalError(n.sons[1].info, errTypeExpected)
elif t2 == nil: GlobalError(n.sons[2].info, errTypeExpected)
else:
result = newTypeS(tyTypeClass, c)
result.addSon(t1)
result.addSon(t2)
result.flags.incl(if op == ord(wAnd): tfAll else: tfAny)
else:
result = semTypeFromMacro(c, n)
of nkCurlyExpr:
result = semTypeNode(c, n.sons[0], nil)
if result != nil:
result = copyType(result, getCurrOwner(), false)
for i in countup(1, n.len - 1):
result.addSon(semTypeNode(c, n.sons[i], nil))
of nkWhenStmt: of nkWhenStmt:
var whenResult = semWhen(c, n, false) var whenResult = semWhen(c, n, false)
if whenResult.kind == nkStmtList: whenResult.kind = nkStmtListType if whenResult.kind == nkStmtList: whenResult.kind = nkStmtListType
@ -794,7 +819,7 @@ proc processMagicType(c: PContext, m: PSym) =
else: GlobalError(m.info, errTypeExpected) else: GlobalError(m.info, errTypeExpected)
proc newConstraint(c: PContext, k: TTypeKind): PType = proc newConstraint(c: PContext, k: TTypeKind): PType =
result = newTypeS(tyOrdinal, c) result = newTypeS(tyTypeClass, c)
result.addSon(newTypeS(k, c)) result.addSon(newTypeS(k, c))
proc semGenericConstraints(c: PContext, n: PNode, result: PType) = proc semGenericConstraints(c: PContext, n: PNode, result: PType) =

View file

@ -202,6 +202,7 @@ proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
result = t result = t
if t == nil: return if t == nil: return
case t.kind case t.kind
of tyTypeClass: nil
of tyGenericParam: of tyGenericParam:
result = lookupTypeVar(cl, t) result = lookupTypeVar(cl, t)
if result.kind == tyGenericInvokation: if result.kind == tyGenericInvokation:

View file

@ -35,7 +35,7 @@ type
TTypeRelation* = enum # order is important! TTypeRelation* = enum # order is important!
isNone, isConvertible, isIntConv, isSubtype, isNone, isConvertible, isIntConv, isSubtype,
isGeneric, isGeneric
isEqual isEqual
proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} = proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} =
@ -208,10 +208,32 @@ proc tupleRel(mapping: var TIdTable, 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 constraintRel(mapping: var TIdTable, f, a: PType): TTypeRelation = proc matchTypeClass(mapping: var TIdTable, f, a: PType): TTypeRelation =
result = isNone for i in countup(0, f.sonsLen - 1):
if f.kind == a.kind: result = isGeneric let son = f.sons[i]
var match = son.kind == a.kind
if not match:
case son.kind
of tyGenericBody:
if a.kind == tyGenericInst and a.sons[0] == son:
match = true
put(mapping, f, a)
of tyTypeClass:
match = matchTypeClass(mapping, son, a) == isGeneric
else: nil
if tfAny in f.flags:
if match == true:
return isGeneric
else:
if match == false:
return isNone
# if the loop finished without returning, either all constraints matched
# or none of them matched.
result = if tfAny in f.flags: isNone else: isGeneric
proc procTypeRel(mapping: var TIdTable, f, a: PType): TTypeRelation = proc procTypeRel(mapping: var TIdTable, 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)
@ -261,7 +283,8 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
assert(a != nil) assert(a != nil)
if a.kind == tyGenericInst and if a.kind == tyGenericInst and
skipTypes(f, {tyVar}).kind notin { skipTypes(f, {tyVar}).kind notin {
tyGenericBody, tyGenericInvokation, tyGenericParam}: tyGenericBody, tyGenericInvokation,
tyGenericParam, tyTypeClass }:
return typeRel(mapping, f, lastSon(a)) return typeRel(mapping, f, lastSon(a))
if a.kind == tyVar and f.kind != tyVar: if a.kind == tyVar and f.kind != tyVar:
return typeRel(mapping, f, a.sons[0]) return typeRel(mapping, f, a.sons[0])
@ -340,11 +363,8 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
result = typeRel(mapping, f.sons[0], a.sons[0]) result = typeRel(mapping, f.sons[0], a.sons[0])
if result < isGeneric: result = isNone if result < isGeneric: result = isNone
else: nil else: nil
of tyOrdinal: of tyOrdinal:
if f.sons[0].kind != tyGenericParam: if isOrdinalType(a):
# some constraint:
result = constraintRel(mapping, f.sons[0], a)
elif isOrdinalType(a):
var x = if a.kind == tyOrdinal: a.sons[0] else: a var x = if a.kind == tyOrdinal: a.sons[0] else: a
result = typeRel(mapping, f.sons[0], x) result = typeRel(mapping, f.sons[0], x)
if result < isGeneric: result = isNone if result < isGeneric: result = isNone
@ -415,7 +435,7 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
of tyGenericBody: of tyGenericBody:
let ff = lastSon(f) let ff = lastSon(f)
if ff != nil: result = typeRel(mapping, ff, a) if ff != nil: result = typeRel(mapping, ff, a)
of tyGenericInvokation: of tyGenericInvokation:
assert(f.sons[0].kind == tyGenericBody) assert(f.sons[0].kind == tyGenericBody)
if a.kind == tyGenericInvokation: if a.kind == tyGenericInvokation:
#InternalError("typeRel: tyGenericInvokation -> tyGenericInvokation") #InternalError("typeRel: tyGenericInvokation -> tyGenericInvokation")
@ -463,7 +483,19 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
result = isGeneric result = isGeneric
else: else:
result = typeRel(mapping, x, a) # check if it fits result = typeRel(mapping, x, a) # check if it fits
of tyExpr, tyStmt, tyTypeDesc: of tyTypeClass:
result = matchTypeClass(mapping, f, a)
if result == isGeneric: put(mapping, f, a)
of tyTypeDesc:
if a.kind == tyTypeDesc:
if f.sonsLen == 0:
result = isGeneric
else:
result = matchTypeClass(mapping, f, a.sons[0])
if result == isGeneric: put(mapping, f, a)
else:
result = isNone
of tyExpr, tyStmt:
result = isGeneric result = isGeneric
else: internalError("typeRel(" & $f.kind & ')') else: internalError("typeRel(" & $f.kind & ')')
@ -506,9 +538,34 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
inc(m.convMatches) inc(m.convMatches)
return return
proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType, proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
arg, argOrig: PNode): PNode = arg, argOrig: PNode): PNode =
var r = typeRel(m.bindings, f, a) var r: TTypeRelation
if f.kind == tyExpr:
if f.sonsLen == 0:
r = isGeneric
else:
let match = matchTypeClass(m.bindings, f, a)
if match != isGeneric: r = isNone
else:
# XXX: Ideally, this should happen much earlier somewhere near
# semOpAux, but to do that, we need to be able to query the
# overload set to determine whether compile-time value is expected
# for the param before entering the full-blown sigmatch algorithm.
# This is related to the immediate pragma since querying the
# overload set could help there too.
var evaluated = c.semConstExpr(c, arg)
if evaluated != nil:
r = isGeneric
arg.typ = newTypeS(tyExpr, c)
arg.typ.n = evaluated
if r == isGeneric:
put(m.bindings, f, arg.typ)
else:
r = typeRel(m.bindings, f, a)
case r case r
of isConvertible: of isConvertible:
inc(m.convMatches) inc(m.convMatches)

View file

@ -429,7 +429,7 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
result = generateThunk(c, x, dest).ptransnode result = generateThunk(c, x, dest).ptransnode
else: else:
result = transformSons(c, n) result = transformSons(c, n)
of tyGenericParam, tyOrdinal: of tyGenericParam, tyOrdinal, tyTypeClass:
result = transform(c, n.sons[1]) result = transform(c, n.sons[1])
# happens sometimes for generated assignments, etc. # happens sometimes for generated assignments, etc.
else: else:

View file

@ -50,13 +50,13 @@ proc enumHasHoles*(t: PType): bool
const const
abstractPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyDistinct, tyOrdinal, abstractPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyDistinct, tyOrdinal,
tyConst, tyMutable} tyConst, tyMutable}
abstractVar* = {tyVar, tyGenericInst, tyDistinct, tyOrdinal, abstractVar* = {tyVar, tyGenericInst, tyDistinct, tyOrdinal,
tyConst, tyMutable} tyConst, tyMutable}
abstractRange* = {tyGenericInst, tyRange, tyDistinct, tyOrdinal, abstractRange* = {tyGenericInst, tyRange, tyDistinct, tyOrdinal,
tyConst, tyMutable} tyConst, tyMutable}
abstractVarRange* = {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal, abstractVarRange* = {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal,
tyConst, tyMutable} tyConst, tyMutable}
abstractInst* = {tyGenericInst, tyDistinct, tyOrdinal, tyConst, tyMutable} abstractInst* = {tyGenericInst, tyDistinct, tyConst, tyMutable, tyOrdinal}
skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyConst, tyMutable} skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyConst, tyMutable}
@ -383,7 +383,7 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
"int16", "int32", "int64", "float", "float32", "float64", "float128", "int16", "int32", "int64", "float", "float32", "float64", "float128",
"uint", "uint8", "uint16", "uint32", "uint64", "bignum", "const ", "uint", "uint8", "uint16", "uint32", "uint64", "bignum", "const ",
"!", "varargs[$1]", "iter[$1]", "proxy[$1]"] "!", "varargs[$1]", "iter[$1]", "proxy[$1]", "TypeClass" ]
var t = typ var t = typ
result = "" result = ""
if t == nil: return if t == nil: return
@ -729,9 +729,11 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
while a.kind == tyDistinct: a = a.sons[0] while a.kind == tyDistinct: a = a.sons[0]
if a.kind != b.kind: return false if a.kind != b.kind: return false
case a.Kind case a.Kind
of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString, of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString,
tyInt..tyBigNum, tyExpr, tyStmt, tyTypeDesc: tyInt..tyBigNum, tyStmt:
result = true result = true
of tyExpr:
result = ExprStructuralEquivalent(a.n, b.n)
of tyObject: of tyObject:
IfFastObjectTypeCheckFailed(a, b): IfFastObjectTypeCheckFailed(a, b):
CycleCheck() CycleCheck()
@ -748,8 +750,9 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
result = sameTuple(a, b, c) result = sameTuple(a, b, c)
of tyGenericInst: result = sameTypeAux(lastSon(a), lastSon(b), c) of tyGenericInst: result = sameTypeAux(lastSon(a), lastSon(b), c)
of tyGenericParam, tyGenericInvokation, tyGenericBody, tySequence, of tyGenericParam, tyGenericInvokation, tyGenericBody, tySequence,
tyOrdinal, tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr, tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr,
tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter: tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter,
tyOrdinal, tyTypeDesc, tyTypeClass:
if sonsLen(a) == sonsLen(b): if sonsLen(a) == sonsLen(b):
CycleCheck() CycleCheck()
result = true result = true
@ -845,7 +848,7 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
result = typeAllowedAux(marker, t.sons[0], skResult) result = typeAllowedAux(marker, t.sons[0], skResult)
of tyExpr, tyStmt, tyTypeDesc: of tyExpr, tyStmt, tyTypeDesc:
result = true result = true
of tyGenericBody, tyGenericParam, tyForward, tyNone, tyGenericInvokation: of tyGenericBody, tyGenericParam, tyForward, tyNone, tyGenericInvokation, tyTypeClass:
result = false #InternalError('shit found'); result = false #InternalError('shit found');
of tyEmpty, tyNil: of tyEmpty, tyNil:
result = kind == skConst result = kind == skConst

View file

@ -2177,7 +2177,7 @@ proc InstantiationInfo*(index = -1): tuple[filename: string, line: int] {.
## This is only useful for advanced meta programming. See the implementation ## This is only useful for advanced meta programming. See the implementation
## of `assert` for an example. ## of `assert` for an example.
proc raiseAssert(msg: string) {.noinline.} = proc raiseAssert*(msg: string) {.noinline.} =
raise newException(EAssertionFailed, msg) raise newException(EAssertionFailed, msg)
template assert*(cond: bool, msg = "") = template assert*(cond: bool, msg = "") =
@ -2186,7 +2186,7 @@ template assert*(cond: bool, msg = "") =
## raises an ``EAssertionFailure`` exception. However, the compiler may ## raises an ``EAssertionFailure`` exception. However, the compiler may
## not generate any code at all for ``assert`` if it is advised to do so. ## not generate any code at all for ``assert`` if it is advised to do so.
## Use ``assert`` for debugging purposes only. ## Use ``assert`` for debugging purposes only.
bind raiseAssert, InstantiationInfo bind InstantiationInfo
when compileOption("assertions"): when compileOption("assertions"):
{.line.}: {.line.}:
if not cond: if not cond:
@ -2195,11 +2195,33 @@ template assert*(cond: bool, msg = "") =
template doAssert*(cond: bool, msg = "") = template doAssert*(cond: bool, msg = "") =
## same as `assert` but is always turned on and not affected by the ## same as `assert` but is always turned on and not affected by the
## ``--assertions`` command line switch. ## ``--assertions`` command line switch.
bind raiseAssert, InstantiationInfo bind InstantiationInfo
{.line: InstantiationInfo().}: {.line: InstantiationInfo().}:
if not cond: if not cond:
raiseAssert(astToStr(cond) & ' ' & msg) raiseAssert(astToStr(cond) & ' ' & msg)
template onFailedAssert*(msg: expr, code: stmt): stmt =
## Sets an assertion failure handler that will intercept any assert statements
## following `onFailedAssert` in the current lexical scope.
## Can be defined multiple times in a single function.
##
## .. code-block:: nimrod
##
## proc example(x: int): TErrorCode =
## onFailedAssert(msg):
## log msg
## return E_FAIL
##
## assert(...)
##
## onFailedAssert(msg):
## raise newException(EMyException, msg)
##
## assert(...)
##
template raiseAssert(msgIMPL: string): stmt =
let `msg` = msgIMPL
code
proc shallow*[T](s: var seq[T]) {.noSideEffect, inline.} = proc shallow*[T](s: var seq[T]) {.noSideEffect, inline.} =
## marks a sequence `s` as `shallow`:idx:. Subsequent assignments will not ## marks a sequence `s` as `shallow`:idx:. Subsequent assignments will not

12
tests/compile/tgensym.nim Normal file
View file

@ -0,0 +1,12 @@
template hygienic(val: expr) =
var `*x` = val
stdout.write `*x`
var x = 100
hygienic 1
hygienic 2
hygienic 3
echo x

View file

@ -0,0 +1,34 @@
type
TFoo[T] = object
val: T
T1 = distinct expr
T2 = distinct expr
proc takesExpr(x, y) =
echo x, y
proc same(x, y: T1) =
echo x, y
proc takesFoo(x, y: TFoo) =
echo x.val, y.val
proc takes2Types(x,y: T1, z: T2) =
echo x, y, z
takesExpr(1, 2)
takesExpr(1, "xxx")
takesExpr[bool, int](true, 0)
same(1, 2)
same("test", "test")
var f: TFoo[int]
f.val = 10
takesFoo(f, f)
takes2Types(1, 1, "string")
takes2Types[string, int]("test", "test", 1)

View file

@ -0,0 +1,17 @@
discard """
msg: "test 1\ntest 2"
output: "TEST 1\nTEST 2\nTEST 2"
"""
import strutils
proc foo(s: expr{string}): string =
static: echo s
const R = s.toUpper
return R
echo foo("test 1")
echo foo("test 2")
echo foo("test " & $2)

35
tests/run/ttypedesc1.nim Normal file
View file

@ -0,0 +1,35 @@
import unittest
type
TFoo[T, U] = object
x: T
y: U
proc foo(T: typedesc{float}, a: expr): string =
result = "float " & $(a.len > 5)
proc foo(T: typedesc{TFoo}, a: int): string =
result = "TFoo " & $(a)
proc foo(T: typedesc{int or bool}): string =
var a: T
a = 10
result = "int or bool " & ($a)
template foo(T: typedesc{seq}): expr = "seq"
test "types can be used as proc params":
check foo(TFoo[int, float], 1000) == "TFoo 1000"
var f = 10.0
check foo(float, "long string") == "float true"
check foo(type(f), [1, 2, 3]) == "float false"
check foo(int) == "int or bool 10"
check foo(seq[int]) == "seq"
check foo(seq[TFoo[bool, string]]) == "seq"
when false:
proc foo(T: typedesc{seq}, s: T) = nil