diff options
author | Araq <rumpf_a@web.de> | 2012-04-01 01:01:25 +0200 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2012-04-01 01:01:25 +0200 |
commit | f788f603feed91a1740e30852a56a2a6fda0ac05 (patch) | |
tree | 38c2dbb34a704bd97fe790d2f135a4346e617109 | |
parent | 3ef9f54cc128e8a4875803c5b686aedc06a397d1 (diff) | |
parent | 8d698b2bdd63cb7390a418d9ebb3ee7fdc7ea3b5 (diff) | |
download | Nim-f788f603feed91a1740e30852a56a2a6fda0ac05.tar.gz |
Merge branch 'master' of github.com:Araq/Nimrod
-rwxr-xr-x | compiler/ast.nim | 14 | ||||
-rw-r--r-- | compiler/ccgcalls.nim | 1 | ||||
-rwxr-xr-x | compiler/ccgtypes.nim | 8 | ||||
-rwxr-xr-x | compiler/ccgutils.nim | 4 | ||||
-rwxr-xr-x | compiler/cgen.nim | 1 | ||||
-rwxr-xr-x | compiler/ecmasgen.nim | 2 | ||||
-rwxr-xr-x | compiler/evals.nim | 15 | ||||
-rw-r--r-- | compiler/idgen.nim | 7 | ||||
-rwxr-xr-x | compiler/lookups.nim | 7 | ||||
-rwxr-xr-x | compiler/msgs.nim | 5 | ||||
-rwxr-xr-x | compiler/options.nim | 3 | ||||
-rwxr-xr-x | compiler/sem.nim | 2 | ||||
-rwxr-xr-x | compiler/semdata.nim | 10 | ||||
-rwxr-xr-x | compiler/semexprs.nim | 44 | ||||
-rwxr-xr-x | compiler/seminst.nim | 4 | ||||
-rwxr-xr-x | compiler/semtempl.nim | 61 | ||||
-rwxr-xr-x | compiler/semtypes.nim | 151 | ||||
-rwxr-xr-x | compiler/semtypinst.nim | 1 | ||||
-rwxr-xr-x | compiler/sigmatch.nim | 83 | ||||
-rwxr-xr-x | compiler/transf.nim | 2 | ||||
-rwxr-xr-x | compiler/types.nim | 19 | ||||
-rwxr-xr-x | lib/system.nim | 28 | ||||
-rw-r--r-- | tests/compile/tgensym.nim | 12 | ||||
-rw-r--r-- | tests/compile/ttypeclasses.nim | 34 | ||||
-rw-r--r-- | tests/run/tmemoization.nim | 17 | ||||
-rw-r--r-- | tests/run/ttypedesc1.nim | 35 | ||||
-rw-r--r-- | tests/run/utypeclasses.nim (renamed from tests/run/uexpr.nim) | 0 |
27 files changed, 394 insertions, 176 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 7fd92d8fc..897501ee5 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -258,7 +258,7 @@ type tyGenericParam, # ``a`` in the above patterns tyDistinct, tyEnum, - tyOrdinal, # misnamed: should become 'tyConstraint' + tyOrdinal, # integer types (including enums and boolean) tyArray, tyObject, tyTuple, @@ -277,6 +277,7 @@ type tyConst, tyMutable, tyVarargs, tyIter, # unused tyProxy # currently unused + tyTypeClass, const tyPureObject* = tyTuple @@ -308,6 +309,8 @@ type tfFromGeneric # type is an instantiation of a generic; this is needed # because for instantiations of objects, structural # 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] @@ -707,6 +710,15 @@ proc `[]`*(n: PNode, i: int): PNode {.inline.} = var emptyNode* = newNode(nkEmpty) # 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: GrowthFactor* = 2 # must be power of 2, > 0 diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 072b2f9fb..cb6014626 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -130,6 +130,7 @@ proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) = var length = sonsLen(ri) for i in countup(1, length - 1): assert(sonsLen(typ) == sonsLen(typ.n)) + if ri.sons[i].typ.isCompileTimeOnly: continue if i < sonsLen(typ): assert(typ.n.sons[i].kind == nkSym) app(pl, genArg(p, ri.sons[i], typ.n.sons[i].sym)) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 8c211186f..6195ff2f4 100755 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -7,6 +7,8 @@ # distribution, for details about the copyright. # +# included from cgen.nim + # ------------------------- Name Mangling -------------------------------- proc mangle(name: string): string = @@ -48,6 +50,9 @@ proc mangleName(s: PSym): PRope = app(result, toRope(s.id)) s.loc.r = result +proc isCompileTimeOnly(t: PType): bool = + result = t.kind in {tyTypedesc, tyExpr} + proc getTypeName(typ: PType): PRope = if (typ.sym != nil) and ({sfImportc, sfExportc} * typ.sym.flags != {}) and (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): if t.n.sons[i].kind != nkSym: InternalError(t.n.info, "genProcParams") var param = t.n.sons[i].sym + if isCompileTimeOnly(param.typ): continue fillLoc(param.loc, locParam, param.typ, mangleName(param), OnStack) app(params, getParamTypeDesc(m, param.typ, check)) if ccgIntroducedPtr(param): @@ -206,8 +212,8 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var PRope, arr = arr.sons[0] if i < sonsLen(t.n) - 1: app(params, ", ") if (t.sons[0] != nil) and isInvalidReturnType(t.sons[0]): - if params != nil: app(params, ", ") var arr = t.sons[0] + if params != nil: app(params, ", ") app(params, getTypeDescAux(m, arr, check)) if (mapReturnType(t.sons[0]) != ctArray) or (gCmd == cmdCompileToLLVM): app(params, "*") diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim index 610fcb39b..12795358a 100755 --- a/compiler/ccgutils.nim +++ b/compiler/ccgutils.nim @@ -82,9 +82,11 @@ proc GetUniqueType*(key: PType): PType = if result == nil: gCanonicalTypes[k] = key result = key + of tyGenericParam, tyTypeClass: + InternalError("GetUniqueType") of tyGenericInst, tyDistinct, tyOrdinal, tyMutable, tyConst, tyIter: result = GetUniqueType(lastSon(key)) - of tyArrayConstr, tyGenericInvokation, tyGenericBody, tyGenericParam, + of tyArrayConstr, tyGenericInvokation, tyGenericBody, tyOpenArray, tyArray, tyTuple, tySet, tyRange, tyPtr, tyRef, tySequence, tyForward, tyVarargs, tyProxy, tyVar: # we have to do a slow linear search because types may need diff --git a/compiler/cgen.nim b/compiler/cgen.nim index d85d3fe53..a56053f79 100755 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -606,6 +606,7 @@ proc genProcAux(m: BModule, prc: PSym) = res.loc.s = OnUnknown for i in countup(1, sonsLen(prc.typ.n) - 1): var param = prc.typ.n.sons[i].sym + if param.typ.isCompileTimeOnly: continue assignParam(p, param) closureSetup(p, prc) genStmts(p, prc.getBody) # modifies p.locals, p.init, etc. diff --git a/compiler/ecmasgen.nim b/compiler/ecmasgen.nim index 5307ea7d1..6499f7a6f 100755 --- a/compiler/ecmasgen.nim +++ b/compiler/ecmasgen.nim @@ -111,7 +111,7 @@ proc mapType(typ: PType): TEcmasTypeKind = result = etyObject of tyNil: result = etyNull of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvokation, tyNone, - tyForward, tyEmpty, tyExpr, tyStmt, tyTypeDesc: + tyForward, tyEmpty, tyExpr, tyStmt, tyTypeDesc, tyTypeClass: result = etyNone of tyProc: result = etyProc of tyCString: result = etyString diff --git a/compiler/evals.nim b/compiler/evals.nim index 72c37a5d9..84d3023a5 100755 --- a/compiler/evals.nim +++ b/compiler/evals.nim @@ -16,7 +16,7 @@ import strutils, magicsys, lists, options, ast, astalgo, trees, treetab, nimsets, msgs, os, condsyms, idents, renderer, types, passes, semfold, transf, - parser, ropes, rodread + parser, ropes, rodread, idgen type PStackFrame* = ref TStackFrame @@ -843,6 +843,7 @@ proc evalParseStmt(c: PEvalContext, n: PNode): PNode = result.typ = newType(tyStmt, c.module) proc evalTemplateAux*(templ, actual: PNode, sym: PSym): PNode = + inc genSymBaseId case templ.kind of nkSym: var p = templ.sym @@ -866,26 +867,29 @@ proc evalTemplateArgs(n: PNode, s: PSym): PNode = of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: a = sonsLen(n) else: a = 0 - var f = sonsLen(s.typ) + var f = s.typ.sonsLen if a > f: GlobalError(n.info, errWrongNumberOfArguments) result = copyNode(n) for i in countup(1, f - 1): 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) -var evalTemplateCounter = 0 +var evalTemplateCounter* = 0 # to prevent endless recursion in templates instantation -proc evalTemplate(n: PNode, sym: PSym): PNode = +proc evalTemplate*(n: PNode, sym: PSym): PNode = inc(evalTemplateCounter) if evalTemplateCounter > 100: GlobalError(n.info, errTemplateInstantiationTooNested) + result = n # replace each param by the corresponding node: var args = evalTemplateArgs(n, sym) result = evalTemplateAux(sym.getBody, args, sym) - + dec(evalTemplateCounter) proc evalExpandToAst(c: PEvalContext, original: PNode): PNode = @@ -1312,6 +1316,7 @@ proc evalMacroCall*(c: PEvalContext, n: PNode, sym: PSym): PNode = if evalTemplateCounter > 100: GlobalError(n.info, errTemplateInstantiationTooNested) + inc genSymBaseId var s = newStackFrame() s.call = n setlen(s.params, 2) diff --git a/compiler/idgen.nim b/compiler/idgen.nim index 6dc19474d..d2e322796 100644 --- a/compiler/idgen.nim +++ b/compiler/idgen.nim @@ -11,7 +11,7 @@ import idents, strutils, os, options -var gFrontEndId, gBackendId*: int +var gFrontEndId, gBackendId*, genSymBaseId*: int const debugIds* = false @@ -25,7 +25,7 @@ proc registerID*(id: PIdObj) = when debugIDs: if id.id == -1 or ContainsOrIncl(usedIds, id.id): InternalError("ID already used: " & $id.id) - + proc getID*(): int {.inline.} = result = gFrontEndId inc(gFrontEndId) @@ -34,6 +34,9 @@ proc backendId*(): int {.inline.} = result = gBackendId inc(gBackendId) +proc genSym*(basename: string): PIdent = + result = getIdent(basename & $genSymBaseId) + proc setId*(id: int) {.inline.} = gFrontEndId = max(gFrontEndId, id + 1) diff --git a/compiler/lookups.nim b/compiler/lookups.nim index ee77b3633..62f4a3391 100755 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -11,7 +11,7 @@ import intsets, ast, astalgo, idents, semdata, types, msgs, options, rodread, - renderer + renderer, wordrecg, idgen proc considerAcc*(n: PNode): PIdent = case n.kind @@ -21,6 +21,11 @@ proc considerAcc*(n: PNode): PIdent = case n.len of 0: GlobalError(n.info, errIdentifierExpected, renderTree(n)) 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: var id = "" for i in 0.. <n.len: diff --git a/compiler/msgs.nim b/compiler/msgs.nim index ef4a0a4cf..df9064ab2 100755 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -662,3 +662,8 @@ proc InternalError*(info: TLineInfo, errMsg: string) = proc InternalError*(errMsg: string) = writeContext(UnknownLineInfo()) rawMessage(errInternal, errMsg) + +template AssertNotNil*(e: expr): expr = + if(e == nil): InternalError($InstantiationInfo()) + e + diff --git a/compiler/options.nim b/compiler/options.nim index ff51ad66c..edea2288d 100755 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -219,3 +219,6 @@ proc binaryStrSearch*(x: openarray[string], y: string): int = return mid result = - 1 +# Can we keep this? I'm using it all the time +template nimdbg*: expr = c.filename.endsWith"nimdbg.nim" + diff --git a/compiler/sem.nim b/compiler/sem.nim index 7d296dbfc..e27f20503 100755 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -91,7 +91,7 @@ proc semConstExpr(c: PContext, n: PNode): PNode = proc semAndEvalConstExpr(c: PContext, n: PNode): PNode = result = semConstExpr(c, n) - + include seminst, semcall proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode = diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 49ab20290..80aed2fd4 100755 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -180,14 +180,16 @@ proc addToLib(lib: PLib, sym: PSym) = sym.annex = lib proc makePtrType(c: PContext, baseType: PType): PType = - if (baseType == nil): InternalError("makePtrType") result = newTypeS(tyPtr, c) - addSon(result, baseType) + addSon(result, baseType.AssertNotNil) proc makeVarType(c: PContext, baseType: PType): PType = - if (baseType == nil): InternalError("makeVarType") 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 = result = newType(kind, getCurrOwner()) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 147f38abb..0282c6c53 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -10,10 +10,12 @@ # this module does the semantic checking for expressions # included from sem.nim +proc semExprOrTypedesc(c: PContext, n: PNode): PNode + proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode = markUsed(n, s) pushInfoContext(n.info) - result = evalTemplate(c, n, s) + result = evalTemplate(n, s) if semCheck: result = semAfterMacroCall(c, result, s) 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 sfGlobal in s.flags: 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 c.p.owner.typ != nil and not IsGenericRoutine(s.owner): c.p.owner.typ.callConv = ccClosure @@ -111,7 +115,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = else: markUsed(n, s) result = newSymNode(s, n.info) - + proc checkConversionBetweenObjects(info: TLineInfo, castDest, src: PType) = var diff = inheritanceDiff(castDest, src) if diff == high(int): @@ -247,16 +251,31 @@ proc semIs(c: PContext, n: PNode): PNode = else: 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) = for i in countup(1, sonsLen(n) - 1): var a = n.sons[i] if a.kind == nkExprEqExpr and sonsLen(a) == 2: var info = 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 else: - n.sons[i] = semExprWithType(c, a, {efAllowType}) + n.sons[i] = semExprOrTypedesc(c, a) proc overloadedCallOpr(c: PContext, n: PNode): PNode = # 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] else: result = nil #GlobalError(n.sons[0].info, errCircumNeedsPointer) - + proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = ## returns nil if not a built-in subscript operator; also called for the ## checking of assignments @@ -833,7 +852,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = result.add(x[0]) return 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}) case arr.kind of tyArray, tyOpenArray, tyArrayConstr, tySequence, tyString, tyCString: @@ -848,6 +867,11 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = result = n result.typ = elemType(arr) #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: checkSonsLen(n, 2) n.sons[0] = makeDeref(n.sons[0]) @@ -1024,7 +1048,7 @@ proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym, markUsed(n, expandedSym) 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 n.sons[0] = newSymNode(magicSym, n.info) @@ -1287,6 +1311,12 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = of nkBind: Message(n.info, warnDeprecated, "bind") 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: # check if it is an expression macro: checkMinSonsLen(n, 1) diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 9ec78488b..85c68923c 100755 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -20,7 +20,7 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable, if a.kind != nkSym: InternalError(a.info, "instantiateGenericParamList; no symbol") 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()) s.info = q.info s.flags = s.flags + {sfUsed, sfFromGeneric} @@ -107,8 +107,6 @@ proc sideEffectsCheck(c: PContext, s: PSym) = s.ast.sons[genericParamsPos].kind == nkEmpty: c.threadEntries.add(s) -template nimdbg: expr = c.filename.endsWith"nimdbg.nim" - proc applyConcreteTypesToSig(genericProc: PSym, concTypes: seq[PType]): PType = # XXX: This is intended to replace the use of semParamList in generateInstance. # The results of semParamList's analysis are already encoded in the original diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index 2600d80cb..b0debc75b 100755 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -9,67 +9,6 @@ # 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 = var a: PSym diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index ee3595989..38cf19406 100755 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -180,6 +180,8 @@ proc semTypeIdent(c: PContext, n: PNode): PSym = result = qualifiedLookup(c, n, {checkAmbiguity, checkUndeclared}) if result != nil: 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.typ.kind != tyGenericParam: # 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) 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) = if kind == skMacro and param.typ.kind in {tyTypeDesc, tyExpr, tyStmt}: let nn = getSysSym"PNimrodNode" @@ -515,8 +481,43 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) = else: addDecl(c, param) -proc isTypeClass(c: PContext, t: PType): bool = - return t.kind in {tyExpr} +proc paramTypeClass(c: PContext, paramType: PType, procKind: TSymKind): + 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, prev: PType, kind: TSymKind): PType = @@ -546,9 +547,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, hasDefault = a.sons[length-1].kind != nkEmpty if hasType: - typ = paramType(c, a.sons[length-2], genericParams, cl) - #if matchType(typ, [(tyVar, 0)], tyGenericInvokation): - # debug a.sons[length-2][0][1] + typ = semTypeNode(c, a.sons[length-2], nil) + if hasDefault: def = semExprWithType(c, a.sons[length-1]) # 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 for j in countup(0, length-3): var arg = newSymS(skParam, a.sons[j], c) - arg.typ = typ - if kind notin {skTemplate, skMacro} and isTypeClass(c, typ): - let typeClassParamId = getIdent(":tcls_" & $i & "_" & $j) + var endingType = typ + var (typeClass, paramTypId) = paramTypeClass(c, typ, kind) + if typeClass != nil: + if paramTypId == nil: paramTypId = getIdent(arg.name.s & ":type") if genericParams == nil: # genericParams is nil when the proc is being instantiated # the resolved type will be in scope then - var s = SymtabGet(c.tab, typeClassParamId) - arg.typ = s.typ + endingType = SymtabGet(c.tab, paramTypId).AssertNotNil.typ else: - var s = newSym(skType, typeClassParamId, getCurrOwner()) - s.typ = newTypeS(tyGenericParam, c) - s.typ.sym = s - s.position = genericParams.len - genericParams.addSon(newSymNode(s)) - arg.typ = s.typ + block addImplicitGeneric: + # is this a bindOnce type class already present in the param list? + for i in countup(0, genericParams.len - 1): + if genericParams.sons[i].sym.name == paramTypId: + endingType = genericParams.sons[i].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 inc(counter) if def != nil and def.kind != nkEmpty: arg.ast = copyTree(def) if ContainsOrIncl(check, arg.name.id): LocalError(a.sons[j].info, errAttemptToRedefine, arg.name.s) addSon(result.n, newSymNode(arg)) - addSon(result, typ) + addSon(result, endingType) addParamOrResult(c, arg, kind) - if n.sons[0].kind != nkEmpty: - var r = paramType(c, n.sons[0], genericParams, cl) + if n.sons[0].kind != nkEmpty: + var r = semTypeNode(c, n.sons[0], nil) # turn explicit 'void' return type into 'nil' because the rest of the # compiler only checks for 'nil': if skipTypes(r, {tyGenericInst}).kind != tyEmpty: result.sons[0] = r res.typ = result.sons[0] - #if matchType(result, [(tyProc, 1), (tyVar, 0)], tyGenericInvokation): - # debug result proc semStmtListType(c: PContext, n: PNode, prev: PType): PType = 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) 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 # results in GlobalError if the macro expands to something different + var sym = expectMacroOrTemplateCall(c, n) markUsed(n, sym) case sym.kind of skMacro: @@ -678,7 +685,7 @@ proc semExpandToType(c: PContext, n: PNode, sym: PSym): PType = else: 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 if gCmd == cmdIdeTools: suggestExpr(c, n) 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) else: GlobalError(n.info, errTypeExpected) of nkCallKinds: - # expand macros and templates - var expandedSym = expectMacroOrTemplateCall(c, n) - result = semExpandToType(c, n, expandedSym) + let op = n.sons[0].ident.id + if op in {ord(wAnd), ord(wOr)}: + 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: var whenResult = semWhen(c, n, false) if whenResult.kind == nkStmtList: whenResult.kind = nkStmtListType @@ -794,7 +819,7 @@ proc processMagicType(c: PContext, m: PSym) = else: GlobalError(m.info, errTypeExpected) proc newConstraint(c: PContext, k: TTypeKind): PType = - result = newTypeS(tyOrdinal, c) + result = newTypeS(tyTypeClass, c) result.addSon(newTypeS(k, c)) proc semGenericConstraints(c: PContext, n: PNode, result: PType) = diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 903506a72..0c44205de 100755 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -202,6 +202,7 @@ proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType = result = t if t == nil: return case t.kind + of tyTypeClass: nil of tyGenericParam: result = lookupTypeVar(cl, t) if result.kind == tyGenericInvokation: diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 3db88569f..da804c2cb 100755 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -35,7 +35,7 @@ type TTypeRelation* = enum # order is important! isNone, isConvertible, isIntConv, isSubtype, - isGeneric, + isGeneric isEqual 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 if x.name.id != y.name.id: return isNone -proc constraintRel(mapping: var TIdTable, f, a: PType): TTypeRelation = - result = isNone - if f.kind == a.kind: result = isGeneric +proc matchTypeClass(mapping: var TIdTable, f, a: PType): TTypeRelation = + for i in countup(0, f.sonsLen - 1): + 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 inconsistentVarTypes(f, a: PType): bool {.inline.} = 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) if a.kind == tyGenericInst and skipTypes(f, {tyVar}).kind notin { - tyGenericBody, tyGenericInvokation, tyGenericParam}: + tyGenericBody, tyGenericInvokation, + tyGenericParam, tyTypeClass }: return typeRel(mapping, f, lastSon(a)) if a.kind == tyVar and f.kind != tyVar: 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]) if result < isGeneric: result = isNone else: nil - of tyOrdinal: - if f.sons[0].kind != tyGenericParam: - # some constraint: - result = constraintRel(mapping, f.sons[0], a) - elif isOrdinalType(a): + of tyOrdinal: + if isOrdinalType(a): var x = if a.kind == tyOrdinal: a.sons[0] else: a result = typeRel(mapping, f.sons[0], x) if result < isGeneric: result = isNone @@ -415,7 +435,7 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation = of tyGenericBody: let ff = lastSon(f) if ff != nil: result = typeRel(mapping, ff, a) - of tyGenericInvokation: + of tyGenericInvokation: assert(f.sons[0].kind == tyGenericBody) if a.kind == tyGenericInvokation: #InternalError("typeRel: tyGenericInvokation -> tyGenericInvokation") @@ -463,7 +483,19 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation = result = isGeneric else: 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 else: internalError("typeRel(" & $f.kind & ')') @@ -506,9 +538,34 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType, inc(m.convMatches) return + proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType, 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 of isConvertible: inc(m.convMatches) diff --git a/compiler/transf.nim b/compiler/transf.nim index 0fa4883ea..ff42ff592 100755 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -429,7 +429,7 @@ proc transformConv(c: PTransf, n: PNode): PTransNode = result = generateThunk(c, x, dest).ptransnode else: result = transformSons(c, n) - of tyGenericParam, tyOrdinal: + of tyGenericParam, tyOrdinal, tyTypeClass: result = transform(c, n.sons[1]) # happens sometimes for generated assignments, etc. else: diff --git a/compiler/types.nim b/compiler/types.nim index efdc30dbf..3f7c2c820 100755 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -50,13 +50,13 @@ proc enumHasHoles*(t: PType): bool const abstractPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyDistinct, tyOrdinal, tyConst, tyMutable} - abstractVar* = {tyVar, tyGenericInst, tyDistinct, tyOrdinal, + abstractVar* = {tyVar, tyGenericInst, tyDistinct, tyOrdinal, tyConst, tyMutable} abstractRange* = {tyGenericInst, tyRange, tyDistinct, tyOrdinal, tyConst, tyMutable} abstractVarRange* = {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal, tyConst, tyMutable} - abstractInst* = {tyGenericInst, tyDistinct, tyOrdinal, tyConst, tyMutable} + abstractInst* = {tyGenericInst, tyDistinct, tyConst, tyMutable, tyOrdinal} 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", "uint", "uint8", "uint16", "uint32", "uint64", "bignum", "const ", - "!", "varargs[$1]", "iter[$1]", "proxy[$1]"] + "!", "varargs[$1]", "iter[$1]", "proxy[$1]", "TypeClass" ] var t = typ result = "" 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] if a.kind != b.kind: return false case a.Kind - of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString, - tyInt..tyBigNum, tyExpr, tyStmt, tyTypeDesc: + of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString, + tyInt..tyBigNum, tyStmt: result = true + of tyExpr: + result = ExprStructuralEquivalent(a.n, b.n) of tyObject: IfFastObjectTypeCheckFailed(a, b): CycleCheck() @@ -748,8 +750,9 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = result = sameTuple(a, b, c) of tyGenericInst: result = sameTypeAux(lastSon(a), lastSon(b), c) of tyGenericParam, tyGenericInvokation, tyGenericBody, tySequence, - tyOrdinal, tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr, - tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter: + tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr, + tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter, + tyOrdinal, tyTypeDesc, tyTypeClass: if sonsLen(a) == sonsLen(b): CycleCheck() result = true @@ -845,7 +848,7 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool = result = typeAllowedAux(marker, t.sons[0], skResult) of tyExpr, tyStmt, tyTypeDesc: result = true - of tyGenericBody, tyGenericParam, tyForward, tyNone, tyGenericInvokation: + of tyGenericBody, tyGenericParam, tyForward, tyNone, tyGenericInvokation, tyTypeClass: result = false #InternalError('shit found'); of tyEmpty, tyNil: result = kind == skConst diff --git a/lib/system.nim b/lib/system.nim index e14a0962b..91b43432c 100755 --- a/lib/system.nim +++ b/lib/system.nim @@ -2177,7 +2177,7 @@ proc InstantiationInfo*(index = -1): tuple[filename: string, line: int] {. ## This is only useful for advanced meta programming. See the implementation ## of `assert` for an example. -proc raiseAssert(msg: string) {.noinline.} = +proc raiseAssert*(msg: string) {.noinline.} = raise newException(EAssertionFailed, msg) template assert*(cond: bool, msg = "") = @@ -2186,7 +2186,7 @@ template assert*(cond: bool, msg = "") = ## raises an ``EAssertionFailure`` exception. However, the compiler may ## not generate any code at all for ``assert`` if it is advised to do so. ## Use ``assert`` for debugging purposes only. - bind raiseAssert, InstantiationInfo + bind InstantiationInfo when compileOption("assertions"): {.line.}: if not cond: @@ -2195,11 +2195,33 @@ template assert*(cond: bool, msg = "") = template doAssert*(cond: bool, msg = "") = ## same as `assert` but is always turned on and not affected by the ## ``--assertions`` command line switch. - bind raiseAssert, InstantiationInfo + bind InstantiationInfo {.line: InstantiationInfo().}: if not cond: 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.} = ## marks a sequence `s` as `shallow`:idx:. Subsequent assignments will not diff --git a/tests/compile/tgensym.nim b/tests/compile/tgensym.nim new file mode 100644 index 000000000..3c0405136 --- /dev/null +++ b/tests/compile/tgensym.nim @@ -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 + diff --git a/tests/compile/ttypeclasses.nim b/tests/compile/ttypeclasses.nim new file mode 100644 index 000000000..e22ede1dc --- /dev/null +++ b/tests/compile/ttypeclasses.nim @@ -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) + diff --git a/tests/run/tmemoization.nim b/tests/run/tmemoization.nim new file mode 100644 index 000000000..10db1fcf1 --- /dev/null +++ b/tests/run/tmemoization.nim @@ -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) + diff --git a/tests/run/ttypedesc1.nim b/tests/run/ttypedesc1.nim new file mode 100644 index 000000000..9c960a809 --- /dev/null +++ b/tests/run/ttypedesc1.nim @@ -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 + diff --git a/tests/run/uexpr.nim b/tests/run/utypeclasses.nim index 06bab375e..06bab375e 100644 --- a/tests/run/uexpr.nim +++ b/tests/run/utypeclasses.nim |