diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index e02a380040..7b24e86db5 100755 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -489,6 +489,13 @@ proc genEqProc(p: BProc, e: PNode, d: var TLoc) = else: putIntoDest(p, d, e.typ, ropef("($1 == $2)", [rdLoc(a), rdLoc(b)])) +proc genIsNil(p: BProc, e: PNode, d: var TLoc) = + let t = skipTypes(e.sons[1].typ, abstractRange) + if t.kind == tyProc and t.callConv == ccClosure: + unaryExpr(p, e, d, "$1.ClPrc == 0") + else: + unaryExpr(p, e, d, "$1 == 0") + proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) = const unArithTab: array[mNot..mToBiggestInt, string] = ["!($1)", # Not @@ -1419,7 +1426,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mEqStr: genStrEquals(p, e, d) of mLeStr: binaryExpr(p, e, d, "(#cmpStrings($1, $2) <= 0)") of mLtStr: binaryExpr(p, e, d, "(#cmpStrings($1, $2) < 0)") - of mIsNil: unaryExpr(p, e, d, "$1 == 0") + of mIsNil: genIsNil(p, e, d) of mIntToStr: genDollar(p, e, d, "#nimIntToStr($1)") of mInt64ToStr: genDollar(p, e, d, "#nimInt64ToStr($1)") of mBoolToStr: genDollar(p, e, d, "#nimBoolToStr($1)") diff --git a/compiler/evals.nim b/compiler/evals.nim index dd975eb917..1f79466ef9 100755 --- a/compiler/evals.nim +++ b/compiler/evals.nim @@ -900,16 +900,15 @@ proc evalTypeTrait*(n: PNode, context: PSym): PNode = ## XXX: This should be pretty much guaranteed to be true # by the type traits procs' signatures, but until the # code is more mature it doesn't hurt to be extra safe - internalAssert n.sons.len >= 2 and + internalAssert n.sons.len >= 2 and n.sons[1].kind == nkSym and n.sons[1].sym.typ.kind == tyTypeDesc let typ = n.sons[1].sym.typ.skipTypes({tyTypeDesc}) - case n.sons[0].sym.name.s + case n.sons[0].sym.name.s.normalize of "name": result = newStrNode(nkStrLit, typ.typeToString(preferExported)) result.typ = newType(tyString, context) result.info = n.info - else: internalAssert false diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 803dcdcfe7..a0e7c329ca 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -262,11 +262,12 @@ proc semOf(c: PContext, n: PNode): PNode = proc semIs(c: PContext, n: PNode): PNode = if sonsLen(n) == 3: - var a = semTypeNode(c, n[1], nil) - var b = semTypeNode(c, n[2], nil) n.typ = getSysType(tyBool) + let a = semTypeNode(c, n[1], nil) n.sons[1] = newNodeIT(nkType, n[1].info, a) - n.sons[2] = newNodeIT(nkType, n[2].info, b) + if n[2].kind notin {nkStrLit..nkTripleStrLit}: + let b = semTypeNode(c, n[2], nil) + n.sons[2] = newNodeIT(nkType, n[2].info, b) result = n else: GlobalError(n.info, errXExpectsTwoArguments, "is") diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 30061f6ebe..748a0a1540 100755 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -604,9 +604,15 @@ proc getConstExpr(m: PSym, n: PNode): PNode = result = magicCall(m, n) of mIs: # BUGFIX: don't evaluate this too early: ``T is void`` - if not containsGenericType(n[1].typ) and - not containsGenericType(n[2].typ): - result = newIntNodeT(ord(sameType(n[1].typ, n[2].typ)), n) + if not containsGenericType(n[1].typ): + if n[2].kind in {nkStrLit..nkTripleStrLit}: + case n[2].strVal.normalize + of "closure": + let t = skipTypes(n[1].typ, abstractRange) + result = newIntNodeT(ord(t.kind == tyProc and + t.callConv == ccClosure), n) + elif not containsGenericType(n[2].typ): + result = newIntNodeT(ord(sameType(n[1].typ, n[2].typ)), n) of mAstToStr: result = newStrNodeT(renderTree(n[1], {renderNoComments}), n) of mConStrStr: diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index 7d4613f504..1249ff73b7 100755 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -67,6 +67,13 @@ proc hash*(x: Pointer): THash {.inline.} = else: result = (cast[THash](x)) shr 3 # skip the alignment +proc hash*[T: proc](x: T): THash {.inline.} = + ## efficient hashing of proc vars; closures are supported too. + when T is "closure": + result = hash(rawProc(x)) !& hash(rawEnv(x)) + else: + result = hash(pointer(x)) + proc hash*(x: int): THash {.inline.} = ## efficient hashing of integers result = x diff --git a/lib/system.nim b/lib/system.nim index dbbe75a57f..b6b695d9b0 100755 --- a/lib/system.nim +++ b/lib/system.nim @@ -1348,6 +1348,7 @@ proc isNil*(x: string): bool {.noSideEffect, magic: "IsNil".} proc isNil*[T](x: ptr T): bool {.noSideEffect, magic: "IsNil".} proc isNil*(x: pointer): bool {.noSideEffect, magic: "IsNil".} proc isNil*(x: cstring): bool {.noSideEffect, magic: "IsNil".} +proc isNil*[T: proc](x: T): bool {.noSideEffect, magic: "IsNil".} ## Fast check whether `x` is nil. This is sometimes more efficient than ## ``== nil``. diff --git a/todo.txt b/todo.txt index 4fa8b999ed..a23fe92507 100755 --- a/todo.txt +++ b/todo.txt @@ -17,7 +17,6 @@ New pragmas: - fix evals.nim with closures - implement "closure tuple consists of a single 'ref'" optimization - make closure default calling convention for proc types - - fix '==' for closures - document 'do' notation - rethink the syntax: distinction between expr and stmt is unfortunate;