changed integer promotion rules; breaks bootstrapping and lots of code

This commit is contained in:
Araq 2012-07-08 21:03:47 +02:00
commit 4fbba0a65a
42 changed files with 643 additions and 261 deletions

View file

@ -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

View file

@ -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:

View file

@ -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

View file

@ -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))

79
compiler/saturate.nim Normal file
View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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:
result = newIntNode(nkCharLit, intVal)
else:
proc newIntNodeT(intVal: BiggestInt, n: PNode): PNode =
case skipTypes(n.typ, abstractVarRange).kind
of tyInt:
result = newIntNode(nkIntLit, intVal)
result.typ = n.typ
result.typ = getIntLitType(result)
# hrm, this is not correct: 1 + high(int) shouldn't produce tyInt64 ...
#setIntLitType(result)
of tyChar:
result = newIntNode(nkCharLit, intVal)
result.typ = n.typ
else:
result = newIntNode(nkIntLit, intVal)
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

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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