diff --git a/compiler/evals.nim b/compiler/evals.nim index f7d94e4c0..151adf690 100644 --- a/compiler/evals.nim +++ b/compiler/evals.nim @@ -906,17 +906,15 @@ proc evalParseStmt(c: PEvalContext, n: PNode): PNode = result = parseString(code.getStrValue, code.info.toFilename, code.info.line.int) #result.typ = newType(tyStmt, c.module) - -proc evalTypeTrait*(trait, operand: PNode, context: PSym): PNode = - InternalAssert operand.kind == nkSym - let typ = operand.sym.typ.skipTypes({tyTypeDesc}) +proc evalTypeTrait*(trait, operand: PNode, context: PSym): PNode = + let typ = operand.typ.skipTypes({tyTypeDesc}) case trait.sym.name.s.normalize of "name": result = newStrNode(nkStrLit, typ.typeToString(preferName)) result.typ = newType(tyString, context) result.info = trait.info - of "arity": + of "arity": result = newIntNode(nkIntLit, typ.n.len-1) result.typ = newType(tyInt, context) result.info = trait.info @@ -1330,7 +1328,7 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode = if gNestedEvals <= 0: stackTrace(c, n.info, errTooManyIterations) case n.kind of nkSym: result = evalSym(c, n, flags) - of nkType..nkNilLit: + of nkType..nkNilLit, nkTypeOfExpr: # nkStrLit is VERY common in the traces, so we should avoid # the 'copyNode' here. result = n #.copyNode diff --git a/compiler/sem.nim b/compiler/sem.nim index 67d400ac5..4b4a3da50 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -158,16 +158,15 @@ proc IsOpImpl(c: PContext, n: PNode): PNode proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, semCheck: bool = true): PNode -when false: - proc symFromType(t: PType, info: TLineInfo): PSym = - if t.sym != nil: return t.sym - result = newSym(skType, getIdent"AnonType", t.owner, info) - result.flags.incl sfAnon - result.typ = t +proc symFromType(t: PType, info: TLineInfo): PSym = + if t.sym != nil: return t.sym + result = newSym(skType, getIdent"AnonType", t.owner, info) + result.flags.incl sfAnon + result.typ = t - proc symNodeFromType(c: PContext, t: PType, info: TLineInfo): PNode = - result = newSymNode(symFromType(t, info), info) - result.typ = makeTypeDesc(c, t) +proc symNodeFromType(c: PContext, t: PType, info: TLineInfo): PNode = + result = newSymNode(symFromType(t, info), info) + result.typ = makeTypeDesc(c, t) proc createEvalContext(c: PContext, mode: TEvalMode): PEvalContext = result = newEvalContext(c.module, mode) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index fde09400d..6294fb3c9 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -301,10 +301,10 @@ proc semOf(c: PContext, n: PNode): PNode = proc isOpImpl(c: PContext, n: PNode): PNode = InternalAssert n.sonsLen == 3 and - n[1].kind == nkSym and n[1].sym.kind == skType and + n[1].typ != nil and n[1].typ.kind == tyTypeDesc and n[2].kind in {nkStrLit..nkTripleStrLit, nkType} - let t1 = n[1].sym.typ.skipTypes({tyTypeDesc}) + let t1 = n[1].typ.skipTypes({tyTypeDesc}) if n[2].kind in {nkStrLit..nkTripleStrLit}: case n[2].strVal.normalize @@ -1942,7 +1942,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = # type parameters: partial generic specialization n.sons[0] = semSymGenericInstantiation(c, n.sons[0], s) result = explicitGenericInstantiation(c, n, s) - else: + elif s != nil and s.kind in {skType}: + result = symNodeFromType(c, semTypeNode(c, n, nil), n.info) + else: result = semArrayAccess(c, n, flags) of nkCurlyExpr: result = semExpr(c, buildOverloadedSubscripts(n, getIdent"{}"), flags) diff --git a/compiler/semfold.nim b/compiler/semfold.nim index ddbe3053c..5e5403c28 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -588,8 +588,9 @@ proc getConstExpr(m: PSym, n: PNode): PNode = result = newSymNodeTypeDesc(s, n.info) of skGenericParam: if s.typ.kind == tyStatic: - result = s.typ.n - result.typ = s.typ.sons[0] + if s.typ.n != nil: + result = s.typ.n + result.typ = s.typ.sons[0] else: result = newSymNodeTypeDesc(s, n.info) else: nil diff --git a/compiler/seminst.nim b/compiler/seminst.nim index ba26635a1..969ff2d59 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -198,14 +198,31 @@ proc fixupProcType(c: PContext, genericType: PType, case genericType.kind of tyGenericParam, tyTypeClasses: result = inst.concreteTypes[genericType.sym.position] + of tyTypeDesc: result = inst.concreteTypes[genericType.sym.position] if tfUnresolved in genericType.flags: result = result.sons[0] + of tyStatic: result = inst.concreteTypes[genericType.sym.position] + of tyGenericInst: result = fixupProcType(c, result.lastSon, inst) + + of tyObject: + var recList = genericType.n + for i in 0 .. 1000: InternalError(fn.ast.info, "nesting too deep") inc(c.InstCounter) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 4c667e27e..b97cde63a 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -34,10 +34,9 @@ proc semInstantiationInfo(c: PContext, n: PNode): PNode = proc semTypeTraits(c: PContext, n: PNode): PNode = checkMinSonsLen(n, 2) - internalAssert n.sons[1].kind == nkSym - let typArg = n.sons[1].sym - if typArg.kind == skType or - (typArg.kind == skParam and typArg.typ.sonsLen > 0): + internalAssert n.sons[1].typ.kind == tyTypeDesc + let typArg = n.sons[1].typ + if typArg.sonsLen > 0: # This is either a type known to sem or a typedesc # param to a regular proc (again, known at instantiation) result = evalTypeTrait(n[0], n[1], GetCurrOwner()) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index a1805fdec..33e942844 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1039,8 +1039,12 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, # for DLL generation it is annoying to check for sfImportc! if sfBorrow in s.flags: LocalError(n.sons[bodyPos].info, errImplOfXNotAllowed, s.name.s) - if n.sons[genericParamsPos].kind == nkEmpty: - ParamsTypeCheck(c, s.typ) + let usePseudoGenerics = kind in {skMacro, skTemplate} + # Macros and Templates can have generic parameters, but they are + # only used for overload resolution (there is no instantiation of + # the symbol, so we must process the body now) + if n.sons[genericParamsPos].kind == nkEmpty or usePseudoGenerics: + if not usePseudoGenerics: ParamsTypeCheck(c, s.typ) pushProcCon(c, s) maybeAddResult(c, s, n) if sfImportc notin s.flags: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 1251a25c0..29fad0059 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -594,12 +594,7 @@ let typedescId = getIdent"typedesc" proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, paramType: PType, paramName: string, info: TLineInfo, anon = false): PType = - if procKind in {skMacro, skTemplate}: - # generic param types in macros and templates affect overload - # resolution, but don't work as generic params when it comes - # to proc instantiation. We don't need to lift such params here. - return - + proc addImplicitGenericImpl(typeClass: PType, typId: PIdent): PType = let finalTypId = if typId != nil: typId else: getIdent(paramName & ":type") @@ -620,7 +615,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, s.position = genericParams.len genericParams.addSon(newSymNode(s)) result = typeClass - + # XXX: There are codegen errors if this is turned into a nested proc template liftingWalk(typ: PType, anonFlag = false): expr = liftParamType(c, procKind, genericParams, typ, paramName, info, anonFlag) @@ -635,20 +630,25 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, case paramType.kind: of tyAnything: result = addImplicitGeneric(newTypeS(tyGenericParam, c)) + of tyStatic: # proc(a: expr{string}, b: expr{nkLambda}) # overload on compile time values and AST trees result = addImplicitGeneric(c.newTypeWithSons(tyStatic, paramType.sons)) + result.flags.incl tfHasStatic + of tyTypeDesc: if tfUnresolved notin paramType.flags: # naked typedescs are not bindOnce types if paramType.sonsLen == 0 and paramTypId != nil and paramTypId.id == typedescId.id: paramTypId = nil result = addImplicitGeneric(c.newTypeWithSons(tyTypeDesc, paramType.sons)) + of tyDistinct: if paramType.sonsLen == 1: # disable the bindOnce behavior for the type class result = liftingWalk(paramType.sons[0], true) + of tySequence, tySet, tyArray, tyOpenArray: # XXX: this is a bit strange, but proc(s: seq) # produces tySequence(tyGenericParam, null). @@ -657,7 +657,8 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, # Maybe there is another better place to associate # the seq type class with the seq identifier. if paramType.lastSon == nil: - let typ = c.newTypeWithSons(tyTypeClass, @[newTypeS(paramType.kind, c)]) + let typ = c.newTypeWithSons(tyBuiltInTypeClass, + @[newTypeS(paramType.kind, c)]) result = addImplicitGeneric(typ) else: for i in 0 .. 0: argType.skipTypes({tyTypeDesc}) diff --git a/tests/compile/tloops.nim b/tests/compile/tloops.nim index 2b1765b00..f6f939769 100644 --- a/tests/compile/tloops.nim +++ b/tests/compile/tloops.nim @@ -1,67 +1,67 @@ -# Test nested loops and some other things - -proc andTest() = - var a = 0 == 5 and 6 == 6 - -proc incx(x: var int) = # is built-in proc - x = x + 1 - -proc decx(x: var int) = - x = x - 1 - -proc First(y: var int) = - var x: int - i_ncx(x) - if x == 10: - y = 0 - else: - if x == 0: - incx(x) - else: - x=11 - -proc TestLoops() = - var i, j: int - while i >= 0: - if i mod 3 == 0: - break - i = i + 1 - while j == 13: - j = 13 - break - break - - while True: - break - - -proc Foo(n: int): int = - var - a, old: int - b, c: bool - F_irst(a) - if a == 10: - a = 30 - elif a == 11: - a = 22 - elif a == 12: - a = 23 - elif b: - old = 12 - else: - a = 40 - - # - b = false or 2 == 0 and 3 == 9 - a = 0 + 3 * 5 + 6 + 7 + +8 # 36 - while b: - a = a + 3 - a = a + 5 - write(stdout, "Hello!") - - -# We should come till here :-) -discard Foo(345) +# Test nested loops and some other things + +proc andTest() = + var a = 0 == 5 and 6 == 6 + +proc incx(x: var int) = # is built-in proc + x = x + 1 + +proc decx(x: var int) = + x = x - 1 + +proc First(y: var int) = + var x: int + i_ncx(x) + if x == 10: + y = 0 + else: + if x == 0: + incx(x) + else: + x=11 + +proc TestLoops() = + var i, j: int + while i >= 0: + if i mod 3 == 0: + break + i = i + 1 + while j == 13: + j = 13 + break + break + + while True: + break + + +proc Foo(n: int): int = + var + a, old: int + b, c: bool + F_irst(a) + if a == 10: + a = 30 + elif a == 11: + a = 22 + elif a == 12: + a = 23 + elif b: + old = 12 + else: + a = 40 + + # + b = false or 2 == 0 and 3 == 9 + a = 0 + 3 * 5 + 6 + 7 + +8 # 36 + while b: + a = a + 3 + a = a + 5 + write(stdout, "Hello!") + + +# We should come till here :-) +discard Foo(345) # test the new type symbol lookup feature: diff --git a/tests/run/tmemoization.nim b/tests/run/tmemoization.nim index b59ff44ea..180acd89b 100644 --- a/tests/run/tmemoization.nim +++ b/tests/run/tmemoization.nim @@ -1,6 +1,6 @@ discard """ - msg: "test 1\ntest 2" - output: "TEST 1\nTEST 2\nTEST 2" + msg: "test 1\ntest 2\ntest 3" + output: "TEST 1\nTEST 2\nTEST 3" """ import strutils @@ -10,8 +10,8 @@ proc foo(s: static[string]): string = const R = s.toUpper return R - + echo foo("test 1") echo foo("test 2") -echo foo("test " & $2) +echo foo("test " & $3) diff --git a/tests/run/tstaticparams.nim b/tests/run/tstaticparams.nim index 23d644bce..b1377443b 100644 --- a/tests/run/tstaticparams.nim +++ b/tests/run/tstaticparams.nim @@ -10,9 +10,9 @@ type TBar[T; I: static[int]] = object data: array[I, T] - #TA1[T; I: static[int]] = array[I, T] - #TA2[T; I: static[int]] = array[0..I, T] - TA3[T; I: static[int]] = array[I-1, T] + TA1[T; I: static[int]] = array[I, T] + # TA2[T; I: static[int]] = array[0..I, T] + # TA3[T; I: static[int]] = array[I-1, T] proc takeFoo(x: TFoo) = echo "abracadabra" @@ -25,7 +25,7 @@ var y: TBar[float, 4] echo high(y.data) var - t1: TA1 - t2: TA2 - t3: TA3 + t1: TA1[float, 1] + # t2: TA2[string, 4] + # t3: TA3[int, 10] diff --git a/tests/run/ttypetraits.nim b/tests/run/ttypetraits.nim index 9a4a7d0d3..4344855eb 100644 --- a/tests/run/ttypetraits.nim +++ b/tests/run/ttypetraits.nim @@ -1,6 +1,6 @@ discard """ msg: "int\nstring\nTBar[int]" - output: "int\nstring\nTBar[int]\nint\nrange 0..2\nstring" + output: "int\nstring\nTBar[int]\nint\nrange 0..2(int)\nstring" """ import typetraits diff --git a/tests/run/tusingstatement.nim b/tests/run/tusingstatement.nim index b9d466377..a33aced4c 100644 --- a/tests/run/tusingstatement.nim +++ b/tests/run/tusingstatement.nim @@ -8,25 +8,11 @@ import # This macro mimics the using statement from C# # -# XXX: -# It doen't match the C# version exactly yet. -# In particular, it's not recursive, which prevents it from dealing -# with exceptions thrown from the variable initializers when multiple. -# variables are used. +# It's kept only as a test for the macro system +# Nimrod's destructors offer a mechanism for automatic +# disposal of resources. # -# Also, since nimrod relies less on exceptions in general, a more -# idiomatic definition could be: -# var x = init() -# if opened(x): -# try: -# body -# finally: -# close(x) -# -# `opened` here could be an overloaded proc which any type can define. -# A common practice can be returing an Optional[Resource] obj for which -# `opened` is defined to `optional.hasValue` -macro using(e: expr): stmt {.immediate.} = +macro autoClose(e: expr): stmt {.immediate.} = let e = callsite() if e.len != 3: error "Using statement: unexpected number of arguments. Got " & @@ -97,7 +83,7 @@ proc close(r: var TResource) = proc use(r: var TResource) = write(stdout, "Using " & r.field & ".") -using(r = openResource("test")): +autoClose(r = openResource("test")): use r