diff options
Diffstat (limited to 'compiler')
-rwxr-xr-x | compiler/ast.nim | 3 | ||||
-rwxr-xr-x | compiler/ccgexprs.nim | 5 | ||||
-rwxr-xr-x | compiler/ecmasgen.nim | 3 | ||||
-rwxr-xr-x | compiler/magicsys.nim | 55 | ||||
-rw-r--r-- | compiler/saturate.nim | 79 | ||||
-rwxr-xr-x | compiler/semcall.nim | 14 | ||||
-rwxr-xr-x | compiler/semdata.nim | 5 | ||||
-rwxr-xr-x | compiler/semexprs.nim | 61 | ||||
-rwxr-xr-x | compiler/semfold.nim | 161 | ||||
-rw-r--r-- | compiler/semmagic.nim | 6 | ||||
-rwxr-xr-x | compiler/semtypes.nim | 3 | ||||
-rwxr-xr-x | compiler/sigmatch.nim | 59 | ||||
-rwxr-xr-x | compiler/transf.nim | 1 | ||||
-rwxr-xr-x | compiler/types.nim | 12 |
14 files changed, 397 insertions, 70 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 511d6f116..e3528dece 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -224,7 +224,8 @@ type sfMainModule, # module is the main module sfSystemModule, # module is the system module sfNoReturn, # proc never returns (an exit proc) - sfAddrTaken, # the variable's address is taken (ex- or implicitely) + sfAddrTaken, # the variable's address is taken (ex- or implicitely); + # *OR*: a proc is indirectly called (used as first class) sfCompilerProc, # proc is a compiler proc, that is a C proc that is # needed for the code generator sfProcvar, # proc can be passed to a proc var diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 1e1bf8072..78a107bbb 100755 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1037,8 +1037,9 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) = InitLocExpr(p, e.sons[1], a) var t = skipTypes(e.sons[1].typ, abstractVarRange) case t.kind - of tyInt..tyInt64: - putIntoDest(p, d, e.typ, ropecg(p.module, "#reprInt($1)", [rdLoc(a)])) + of tyInt..tyInt64, tyUInt..tyUInt64: + putIntoDest(p, d, e.typ, + ropecg(p.module, "#reprInt((NI64)$1)", [rdLoc(a)])) of tyFloat..tyFloat128: putIntoDest(p, d, e.typ, ropecg(p.module, "#reprFloat($1)", [rdLoc(a)])) of tyBool: diff --git a/compiler/ecmasgen.nim b/compiler/ecmasgen.nim index 30a697d8e..9b3601ae4 100755 --- a/compiler/ecmasgen.nim +++ b/compiler/ecmasgen.nim @@ -1066,7 +1066,8 @@ proc createVar(p: var TProc, typ: PType, indirect: bool): PRope = result = nil proc isIndirect(v: PSym): bool = - result = (sfAddrTaken in v.flags) and (mapType(v.typ) != etyObject) + result = (sfAddrTaken in v.flags) and (mapType(v.typ) != etyObject) and + v.kind notin {skProc, skConverter, skMethod, skIterator} proc genVarInit(p: var TProc, v: PSym, n: PNode, r: var TCompRes) = var diff --git a/compiler/magicsys.nim b/compiler/magicsys.nim index 09c99c027..fcfc35ff1 100755 --- a/compiler/magicsys.nim +++ b/compiler/magicsys.nim @@ -74,24 +74,51 @@ proc getSysType(kind: TTypeKind): PType = InternalError("wanted: " & $kind & " got: " & $result.kind) if result == nil: InternalError("type not found: " & $kind) -when false: - var - intTypeCache: array[-5..64, PType] +var + intTypeCache: array[-5..64, PType] - proc getIntLitType*(literal: PNode): PType = - # we cache some common integer literal types for performance: - let value = literal.intVal - if value >= low(intTypeCache) and value <= high(intTypeCache): - result = intTypeCache[value.int] - if result == nil: - let ti = getSysType(tyInt) - result = copyType(ti, ti.owner, false) - result.n = literal - intTypeCache[value.int] = result - else: +proc getIntLitType*(literal: PNode): PType = + # we cache some common integer literal types for performance: + let value = literal.intVal + if value >= low(intTypeCache) and value <= high(intTypeCache): + result = intTypeCache[value.int] + if result == nil: let ti = getSysType(tyInt) result = copyType(ti, ti.owner, false) result.n = literal + intTypeCache[value.int] = result + else: + let ti = getSysType(tyInt) + result = copyType(ti, ti.owner, false) + result.n = literal + +proc setIntLitType*(result: PNode) = + let i = result.intVal + case platform.IntSize + of 8: result.typ = getIntLitType(result) + of 4: + if i >= low(int32) and i <= high(int32): + result.typ = getIntLitType(result) + else: + result.typ = getSysType(tyInt64) + of 2: + if i >= low(int16) and i <= high(int16): + result.typ = getIntLitType(result) + elif i >= low(int32) and i <= high(int32): + result.typ = getSysType(tyInt32) + else: + result.typ = getSysType(tyInt64) + of 1: + # 8 bit CPUs are insane ... + if i >= low(int8) and i <= high(int8): + result.typ = getIntLitType(result) + elif i >= low(int16) and i <= high(int16): + result.typ = getSysType(tyInt16) + elif i >= low(int32) and i <= high(int32): + result.typ = getSysType(tyInt32) + else: + result.typ = getSysType(tyInt64) + else: InternalError(result.info, "invalid int size") proc getCompilerProc(name: string): PSym = var ident = getIdent(name, hashIgnoreStyle(name)) diff --git a/compiler/saturate.nim b/compiler/saturate.nim new file mode 100644 index 000000000..e0968843b --- /dev/null +++ b/compiler/saturate.nim @@ -0,0 +1,79 @@ +# +# +# The Nimrod Compiler +# (c) Copyright 2012 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Saturated arithmetic routines. XXX Make part of the stdlib? + +proc `|+|`*(a, b: biggestInt): biggestInt = + ## saturated addition. + result = a +% b + if (result xor a) >= 0'i64 or (result xor b) >= 0'i64: + return result + if a < 0 or b < 0: + result = low(result) + else: + result = high(result) + +proc `|-|`*(a, b: biggestInt): biggestInt = + result = a -% b + if (result xor a) >= 0'i64 or (result xor not b) >= 0'i64: + return result + if b > 0: + result = low(result) + else: + result = high(result) + +proc `|abs|`*(a: biggestInt): biggestInt = + if a != low(a): + if a >= 0: result = a + else: result = -a + else: + result = low(a) + +proc `|div|`*(a, b: biggestInt): biggestInt = + # (0..5) div (0..4) == (0..5) div (1..4) == (0 div 4) .. (5 div 1) + if b == 0'i64: + # make the same as ``div 1``: + result = a + elif a == low(a) and b == -1'i64: + result = high(result) + else: + result = a div b + +proc `|mod|`*(a, b: biggestInt): biggestInt = + if b == 0'i64: + result = a + else: + result = a mod b + +proc `|*|`*(a, b: biggestInt): biggestInt = + var + resAsFloat, floatProd: float64 + result = a *% b + floatProd = toBiggestFloat(a) # conversion + floatProd = floatProd * toBiggestFloat(b) + resAsFloat = toBiggestFloat(result) + + # Fast path for normal case: small multiplicands, and no info + # is lost in either method. + if resAsFloat == floatProd: return result + + # Somebody somewhere lost info. Close enough, or way off? Note + # that a != 0 and b != 0 (else resAsFloat == floatProd == 0). + # The difference either is or isn't significant compared to the + # true value (of which floatProd is a good approximation). + + # abs(diff)/abs(prod) <= 1/32 iff + # 32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough" + if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd): + return result + + if floatProd >= 0.0: + result = high(result) + else: + result = low(result) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index f0c9f42b0..8ba582a33 100755 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -18,8 +18,8 @@ proc sameMethodDispatcher(a, b: PSym): bool = if aa.kind == nkSym and bb.kind == nkSym and aa.sym == bb.sym: result = true -proc resolveOverloads(c: PContext, n, orig: PNode, - filter: TSymKinds): TCandidate = +proc resolveOverloads(c: PContext, n, orig: PNode, + filter: TSymKinds): TCandidate = var initialBinding: PNode var f = n.sons[0] if f.kind == nkBracketExpr: @@ -67,9 +67,17 @@ proc resolveOverloads(c: PContext, n, orig: PNode, not sameMethodDispatcher(best.calleeSym, alt.calleeSym): if best.state != csMatch: InternalError(n.info, "x.state is not csMatch") + #writeMatches(best) + #writeMatches(alt) + var args = "(" + for i in countup(1, sonsLen(n) - 1): + if i > 1: add(args, ", ") + add(args, typeToString(n.sons[i].typ)) + add(args, ")") + LocalError(n.Info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [ getProcHeader(best.calleeSym), getProcHeader(alt.calleeSym), - best.calleeSym.Name.s]) + args]) proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode = assert x.state == csMatch diff --git a/compiler/semdata.nim b/compiler/semdata.nim index c28c8c7a1..9eff8c4f4 100755 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -213,6 +213,11 @@ proc markUsed*(n: PNode, s: PSym) = if sfDeprecated in s.flags: Message(n.info, warnDeprecated, s.name.s) if sfError in s.flags: LocalError(n.info, errWrongSymbolX, s.name.s) +proc markIndirect*(c: PContext, s: PSym) = + if s.kind in {skProc, skConverter, skMethod, skIterator}: + incl(s.flags, sfAddrTaken) + # XXX add to 'c' for global analysis + proc useSym*(sym: PSym): PNode = result = newSymNode(sym) markUsed(result, sym) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 22af8b4e0..7aa723c52 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -74,8 +74,10 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = smoduleId != c.module.id and smoduleId != c.friendModule.id: LocalError(n.info, errXCannotBePassedToProcVar, s.name.s) result = symChoice(c, n, s) - if result.kind == nkSym and isGenericRoutine(result.sym): - LocalError(n.info, errInstantiateXExplicitely, s.name.s) + if result.kind == nkSym: + markIndirect(c, result.sym) + if isGenericRoutine(result.sym): + LocalError(n.info, errInstantiateXExplicitely, s.name.s) of skConst: markUsed(n, s) case skipTypes(s.typ, abstractInst).kind @@ -129,10 +131,11 @@ proc checkConversionBetweenObjects(info: TLineInfo, castDest, src: PType) = if diff == high(int): GlobalError(info, errGenerated, MsgKindToString(errIllegalConvFromXtoY) % [ src.typeToString, castDest.typeToString]) - + +const + IntegralTypes = {tyBool, tyEnum, tyChar, tyInt..tyUInt64} + proc checkConvertible(info: TLineInfo, castDest, src: PType) = - const - IntegralTypes = {tyBool, tyEnum, tyChar, tyInt..tyUInt64} if sameType(castDest, src) and castDest.sym == src.sym: # don't annoy conversions that may be needed on another processor: if castDest.kind notin {tyInt..tyUInt64, tyNil}: @@ -177,8 +180,8 @@ proc isCastable(dst, src: PType): bool = result = false else: result = (ds >= ss) or - (skipTypes(dst, abstractInst).kind in {tyInt..tyFloat128}) or - (skipTypes(src, abstractInst).kind in {tyInt..tyFloat128}) + (skipTypes(dst, abstractInst).kind in IntegralTypes) or + (skipTypes(src, abstractInst).kind in IntegralTypes) proc semConv(c: PContext, n: PNode, s: PSym): PNode = if sonsLen(n) != 2: GlobalError(n.info, errConvNeedsOneArg) @@ -190,10 +193,12 @@ proc semConv(c: PContext, n: PNode, s: PSym): PNode = if op.kind != nkSymChoice: checkConvertible(result.info, result.typ, op.typ) else: - for i in countup(0, sonsLen(op) - 1): - if sameType(result.typ, op.sons[i].typ): - markUsed(n, op.sons[i].sym) - return op.sons[i] + for i in countup(0, sonsLen(op) - 1): + let it = op.sons[i] + if sameType(result.typ, it.typ): + markUsed(n, it.sym) + markIndirect(c, it.sym) + return it localError(n.info, errUseQualifier, op.sons[0].sym.name.s) proc semCast(c: PContext, n: PNode): PNode = @@ -222,7 +227,7 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode = n.typ = getSysType(tyInt) of tyArrayConstr, tyArray: n.typ = n.sons[1].typ.sons[0] # indextype - of tyInt..tyInt64, tyChar, tyBool, tyEnum: + of tyInt..tyInt64, tyChar, tyBool, tyEnum, tyUInt8, tyUInt16, tyUInt32: n.typ = n.sons[1].typ else: GlobalError(n.info, errInvalidArgForX, opToStr[m]) result = n @@ -498,6 +503,24 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode = if n.kind notin nkCallKinds or n.sons[0].kind != nkSym: return var callee = n.sons[0].sym + # constant folding that is necessary for correctness of semantic pass: + if callee.magic != mNone and callee.magic in ctfeWhitelist and n.typ != nil: + var call = newNodeIT(nkCall, n.info, n.typ) + call.add(n.sons[0]) + var allConst = true + for i in 1 .. < n.len: + let a = getConstExpr(c.module, n.sons[i]) + if a != nil: call.add(a) + else: + allConst = false + call.add(n.sons[i]) + if allConst: + result = semfold.getConstExpr(c.module, call) + if result.isNil: result = n + else: return result + result.typ = semfold.getIntervalType(callee.magic, call) + + # optimization pass: not necessary for correctness of the semantic pass if {sfNoSideEffect, sfCompileTime} * callee.flags != {} and {sfForward, sfImportc} * callee.flags == {}: if sfCompileTime notin callee.flags and @@ -901,7 +924,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = if skipTypes(n.sons[1].typ, {tyGenericInst, tyRange, tyOrdinal}).kind in {tyInt..tyInt64}: var idx = getOrdValue(n.sons[1]) - if (idx >= 0) and (idx < sonsLen(arr)): n.typ = arr.sons[int(idx)] + if idx >= 0 and idx < sonsLen(arr): n.typ = arr.sons[int(idx)] else: GlobalError(n.info, errInvalidIndexValueForTuple) else: GlobalError(n.info, errIndexTypesDoNotMatch) @@ -1301,15 +1324,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = nil of nkNilLit: result.typ = getSysType(tyNil) - of nkIntLit: - # XXX this is stupid: - if result.typ == nil: - let i = result.intVal - if i >= low(int32) and i <= high(int32): - result.typ = getSysType(tyInt) - else: - result.typ = getSysType(tyInt64) - of nkInt8Lit: + of nkIntLit: + if result.typ == nil: setIntLitType(result) + of nkInt8Lit: if result.typ == nil: result.typ = getSysType(tyInt8) of nkInt16Lit: if result.typ == nil: result.typ = getSysType(tyInt16) diff --git a/compiler/semfold.nim b/compiler/semfold.nim index ce9e03513..061a29fad 100755 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -13,7 +13,7 @@ import strutils, lists, options, ast, astalgo, trees, treetab, nimsets, times, nversion, platform, math, msgs, os, condsyms, idents, renderer, types, - commands, magicsys + commands, magicsys, saturate proc getConstExpr*(m: PSym, n: PNode): PNode # evaluates the constant expression or returns nil if it is no constant @@ -26,12 +26,19 @@ proc newStrNodeT*(strVal: string, n: PNode): PNode # implementation -proc newIntNodeT(intVal: BiggestInt, n: PNode): PNode = - if skipTypes(n.typ, abstractVarRange).kind == tyChar: +proc newIntNodeT(intVal: BiggestInt, n: PNode): PNode = + case skipTypes(n.typ, abstractVarRange).kind + of tyInt: + result = newIntNode(nkIntLit, intVal) + result.typ = getIntLitType(result) + # hrm, this is not correct: 1 + high(int) shouldn't produce tyInt64 ... + #setIntLitType(result) + of tyChar: result = newIntNode(nkCharLit, intVal) - else: + result.typ = n.typ + else: result = newIntNode(nkIntLit, intVal) - result.typ = n.typ + result.typ = n.typ result.info = n.info proc newFloatNodeT(floatVal: BiggestFloat, n: PNode): PNode = @@ -67,6 +74,150 @@ proc ordinalValToString(a: PNode): string = else: result = $x +proc isFloatRange(t: PType): bool {.inline.} = + result = t.kind == tyRange and t.sons[0].kind in {tyFloat..tyFloat128} + +proc isIntRange(t: PType): bool {.inline.} = + result = t.kind == tyRange and t.sons[0].kind in { + tyInt..tyInt64, tyUInt8..tyUInt32} + +proc pickIntRange(a, b: PType): PType = + if isIntRange(a): result = a + elif isIntRange(b): result = b + else: result = a + +proc isIntRangeOrLit(t: PType): bool = + result = isIntRange(t) or isIntLit(t) + +proc pickMinInt(n: PNode): biggestInt = + if n.kind in {nkIntLit..nkUInt64Lit}: + result = n.intVal + elif isIntLit(n.typ): + result = n.typ.n.intVal + elif isIntRange(n.typ): + result = firstOrd(n.typ) + else: + InternalError(n.info, "pickMinInt") + +proc pickMaxInt(n: PNode): biggestInt = + if n.kind in {nkIntLit..nkUInt64Lit}: + result = n.intVal + elif isIntLit(n.typ): + result = n.typ.n.intVal + elif isIntRange(n.typ): + result = lastOrd(n.typ) + else: + InternalError(n.info, "pickMaxInt") + +proc makeRange(typ: PType, first, last: biggestInt): PType = + var n = newNode(nkRange) + addSon(n, newIntNode(nkIntLit, min(first, last))) + addSon(n, newIntNode(nkIntLit, max(first, last))) + result = newType(tyRange, typ.owner) + result.n = n + addSon(result, skipTypes(typ, {tyRange})) + +proc makeRangeF(typ: PType, first, last: biggestFloat): PType = + var n = newNode(nkRange) + addSon(n, newFloatNode(nkFloatLit, min(first.float, last.float))) + addSon(n, newFloatNode(nkFloatLit, max(first.float, last.float))) + result = newType(tyRange, typ.owner) + result.n = n + addSon(result, skipTypes(typ, {tyRange})) + +proc getIntervalType*(m: TMagic, n: PNode): PType = + # Nimrod requires interval arithmetic for ``range`` types. Lots of tedious + # work but the feature is very nice for reducing explicit conversions. + result = n.typ + + template commutativeOp(opr: expr) {.immediate.} = + let a = n.sons[1] + let b = n.sons[2] + if isIntRangeOrLit(a.typ) and isIntRangeOrLit(b.typ): + result = makeRange(pickIntRange(a.typ, b.typ), + opr(pickMinInt(a), pickMinInt(b)), + opr(pickMaxInt(a), pickMaxInt(b))) + + template binaryOp(opr: expr) {.immediate.} = + let a = n.sons[1] + let b = n.sons[2] + if isIntRange(a.typ) and b.kind in {nkIntLit..nkUInt64Lit}: + result = makeRange(a.typ, + opr(pickMinInt(a), pickMinInt(b)), + opr(pickMaxInt(a), pickMaxInt(b))) + + case m + of mUnaryMinusI, mUnaryMinusI64: + let a = n.sons[1].typ + if isIntRange(a): + # (1..3) * (-1) == (-3.. -1) + result = makeRange(a, 0|-|lastOrd(a), 0|-|firstOrd(a)) + of mUnaryMinusF64: + let a = n.sons[1].typ + if isFloatRange(a): + result = makeRangeF(a, -getFloat(a.n.sons[1]), + -getFloat(a.n.sons[0])) + of mAbsF64: + let a = n.sons[1].typ + if isFloatRange(a): + # abs(-5.. 1) == (1..5) + result = makeRangeF(a, abs(getFloat(a.n.sons[1])), + abs(getFloat(a.n.sons[0]))) + of mAbsI, mAbsI64: + let a = n.sons[1].typ + if isIntRange(a): + result = makeRange(a, `|abs|`(getInt(a.n.sons[1])), + `|abs|`(getInt(a.n.sons[0]))) + of mSucc: + let a = n.sons[1].typ + let b = n.sons[2].typ + if isIntRange(a) and isIntLit(b): + # (-5.. 1) + 6 == (-5 + 6)..(-1 + 6) + result = makeRange(a, pickMinInt(n.sons[1]) |+| pickMinInt(n.sons[2]), + pickMaxInt(n.sons[1]) |+| pickMaxInt(n.sons[2])) + of mPred: + let a = n.sons[1].typ + let b = n.sons[2].typ + if isIntRange(a) and isIntLit(b): + result = makeRange(a, pickMinInt(n.sons[1]) |-| pickMinInt(n.sons[2]), + pickMaxInt(n.sons[1]) |-| pickMaxInt(n.sons[2])) + of mAddI, mAddI64, mAddU, mAddU64: + commutativeOp(`|+|`) + of mMulI, mMulI64, mMulU, mMulU64: + commutativeOp(`|*|`) + of mSubI, mSubI64, mSubU, mSubU64: + binaryOp(`|-|`) + of mBitandI, mBitandI64: + var a = n.sons[1] + var b = n.sons[2] + # symmetrical: + if b.kind notin {nkIntLit..nkUInt64Lit}: swap(a, b) + if b.kind in {nkIntLit..nkUInt64Lit}: + let x = b.intVal|+|1 + if (x and -x) == x and x >= 0: + result = makeRange(a.typ, 0, b.intVal) + of mModI, mModI64, mModU, mModU64: + # so ... if you ever wondered about modulo's signedness; this defines it: + let a = n.sons[1] + let b = n.sons[2] + if b.kind in {nkIntLit..nkUInt64Lit}: + if b.intVal >= 0: + result = makeRange(a.typ, 0, b.intVal-1) + else: + result = makeRange(a.typ, b.intVal+1, 0) + of mDivI, mDivI64, mDivU, mDivU64: + binaryOp(`|div|`) + of mMinI, mMinI64: + commutativeOp(min) + of mMaxI, mMaxI64: + commutativeOp(max) + else: nil + +discard """ + mShlI, mShlI64, + mShrI, mShrI64, mAddF64, mSubF64, mMulF64, mDivF64, mMaxF64, mMinF64 +""" + proc evalOp(m: TMagic, n, a, b, c: PNode): PNode = # b and c may be nil result = nil diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index b7e890e67..e3cc7d610 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -40,6 +40,11 @@ proc semTypeTraits(c: PContext, n: PNode): PNode = # pass unmodified to evals result = n +proc semOrd(c: PContext, n: PNode): PNode = + result = n + result.typ = makeRangeType(c, firstOrd(n.sons[1].typ), + lastOrd(n.sons[1].typ), n.info) + proc magicsAfterOverloadResolution(c: PContext, n: PNode, flags: TExprFlags): PNode = case n[0].sym.magic @@ -49,5 +54,6 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, result = newStrNodeT(renderTree(n[1], {renderNoComments}), n) result.typ = getSysType(tyString) of mInstantiationInfo: result = semInstantiationInfo(c, n) + of mOrd: result = semOrd(c, n) else: result = n diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index c437ce2b5..10722d853 100755 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -132,7 +132,8 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType = var a = semConstExpr(c, n[1]) var b = semConstExpr(c, n[2]) if not sameType(a.typ, b.typ): GlobalError(n.info, errPureTypeMismatch) - if a.typ.kind notin {tyInt..tyInt64,tyEnum,tyBool,tyChar,tyFloat..tyFloat128}: + if a.typ.kind notin {tyInt..tyInt64,tyEnum,tyBool,tyChar,tyFloat..tyFloat128, + tyUInt8..tyUInt32}: GlobalError(n.info, errOrdinalTypeExpected) if enumHasHoles(a.typ): GlobalError(n.info, errEnumXHasHoles, a.typ.sym.name.s) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 6819bb37f..4a7ba9587 100755 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -34,8 +34,13 @@ type # for example TTypeRelation* = enum # order is important! - isNone, isConvertible, isIntConv, isSubtype, - isGeneric + isNone, isConvertible, + isIntConv, + isSubtype, + isSubrange, # subrange of the wanted type; no type conversion + # but apart from that counts as ``isSubtype`` + isGeneric, + isFromIntLit, # conversion *from* int literal; proven safe isEqual proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} = @@ -56,10 +61,6 @@ proc initCandidate*(c: var TCandidate, callee: PType) = proc put(t: var TIdTable, key, val: PType) {.inline.} = IdTablePut(t, key, val) - when false: - if val.kind == tyObject and isDefined"testme" and - IdentEq(val.sym.name, "TTable"): - assert false proc initCandidate*(c: var TCandidate, callee: PSym, binding: PNode, calleeScope = -1) = initCandidateAux(c, callee.typ) @@ -100,7 +101,7 @@ proc cmpCandidates*(a, b: TCandidate): int = if (a.calleeScope != -1) and (b.calleeScope != -1): result = a.calleeScope - b.calleeScope -proc writeMatches(c: TCandidate) = +proc writeMatches*(c: TCandidate) = Writeln(stdout, "exact matches: " & $c.exactMatches) Writeln(stdout, "subtype matches: " & $c.subtypeMatches) Writeln(stdout, "conv matches: " & $c.convMatches) @@ -160,15 +161,25 @@ proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation = if a.kind == f.kind: result = isEqual else: - var k = skipTypes(a, {tyRange}).kind - if k == f.kind: result = isSubtype - elif k == tyInt and f.kind in {tyRange, tyInt8..tyUInt64}: - # and a.n != nil and a.n.intVal >= firstOrd(f) and - # a.n.intVal <= lastOrd(f): + let ab = skipTypes(a, {tyRange}) + let k = ab.kind + if k == f.kind: result = isSubrange + elif k == tyInt and f.kind in {tyRange, tyInt8..tyInt64, + tyUInt..tyUInt64} and + isIntLit(ab) and ab.n.intVal >= firstOrd(f) and + ab.n.intVal <= lastOrd(f): # integer literal in the proper range; we want ``i16 + 4`` to stay an # ``int16`` operation so we declare the ``4`` pseudo-equal to int16 + result = isFromIntLit + elif f.kind == tyInt and k in {tyInt8..tyInt32}: result = isIntConv - elif k >= min and k <= max: result = isConvertible + elif k >= min and k <= max: + result = isConvertible + elif a.kind == tyRange and a.sons[0].kind in {tyInt..tyInt64, + tyUInt8..tyUInt32} and + a.n[0].intVal >= firstOrd(f) and + a.n[1].intVal <= lastOrd(f): + result = isConvertible else: result = isNone #elif f.kind == tyInt and k in {tyInt..tyInt32}: result = isIntConv #elif f.kind == tyUInt and k in {tyUInt..tyUInt32}: result = isIntConv @@ -186,10 +197,10 @@ proc handleFloatRange(f, a: PType): TTypeRelation = if a.kind == f.kind: result = isEqual else: - var k = skipTypes(a, {tyRange}).kind - if k == f.kind: result = isSubtype - elif k == tyInt and f.kind >= tyFloat and f.kind <= tyFloat128: - result = isIntConv + let ab = skipTypes(a, {tyRange}) + var k = ab.kind + if k == f.kind: result = isSubrange + elif isIntLit(ab): result = isConvertible elif k >= tyFloat and k <= tyFloat128: result = isConvertible else: result = isNone @@ -229,7 +240,7 @@ proc tupleRel(mapping: var TIdTable, f, a: PType): TTypeRelation = 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 + var match = son.kind == skipTypes(a, {tyRange}).kind if not match: case son.kind @@ -584,12 +595,17 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType, of isConvertible: inc(m.convMatches) result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c) - of isIntConv: + of isIntConv: + # too lazy to introduce another ``*matches`` field, so we conflate + # ``isIntConv`` and ``isIntLit`` here: inc(m.intConvMatches) result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c) of isSubtype: inc(m.subtypeMatches) result = implicitConv(nkHiddenSubConv, f, copyTree(arg), m, c) + of isSubrange: + inc(m.subtypeMatches) + result = copyTree(arg) of isGeneric: inc(m.genericMatches) if m.calleeSym != nil and m.calleeSym.kind in {skMacro, skTemplate}: @@ -601,6 +617,11 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType, if skipTypes(result.typ, abstractVar).kind in {tyTuple}: result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c) # BUGFIX: use ``result.typ`` and not `f` here + of isFromIntLit: + # too lazy to introduce another ``*matches`` field, so we conflate + # ``isIntConv`` and ``isIntLit`` here: + inc(m.intConvMatches, 256) + result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c) of isEqual: inc(m.exactMatches) result = copyTree(arg) diff --git a/compiler/transf.nim b/compiler/transf.nim index bf6354665..3c3ae12c9 100755 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -734,7 +734,6 @@ proc transform(c: PTransf, n: PNode): PTransNode = # we inline constants if they are not complex constants: if cnst != nil and not dontInlineConstant(n, cnst): result = PTransNode(cnst) # do not miss an optimization - warnNarrowingConversion(result.pnode) proc processTransf(context: PPassContext, n: PNode): PNode = # Note: For interactive mode we cannot call 'passes.skipCodegen' and skip diff --git a/compiler/types.nim b/compiler/types.nim index 9b4b869e4..8005ba806 100755 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -102,6 +102,9 @@ proc getOrdValue(n: PNode): biggestInt = LocalError(n.info, errOrdinalTypeExpected) result = 0 +proc isIntLit*(t: PType): bool {.inline.} = + result = t.n != nil and t.n.kind == nkIntLit + proc isCompatibleToCString(a: PType): bool = if a.kind == tyArray: if (firstOrd(a.sons[0]) == 0) and @@ -400,8 +403,15 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string = result = "" if t == nil: return if prefer == preferName and t.sym != nil and sfAnon notin t.sym.flags: + if t.kind == tyInt and isIntLit(t): + return t.sym.Name.s & "(" & $t.n.intVal & ")" return t.sym.Name.s case t.Kind + of tyInt: + if not isIntLit(t): + result = typeToStr[t.kind] + else: + result = "intLit(" & $t.n.intVal & ")" of tyGenericBody, tyGenericInst, tyGenericInvokation: result = typeToString(t.sons[0]) & '[' for i in countup(1, sonsLen(t) -1 -ord(t.kind != tyGenericInvokation)): @@ -536,7 +546,7 @@ proc lastOrd(t: PType): biggestInt = of tyUInt8: result = 0xFF of tyUInt16: result = 0xFFFF of tyUInt32: result = 0xFFFFFFFF - of tyUInt64: result = -1 + of tyUInt64: result = 0x7FFFFFFFFFFFFFFF'i64 of tyEnum: assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym) result = t.n.sons[sonsLen(t.n) - 1].sym.position |