summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rwxr-xr-xcompiler/ast.nim3
-rwxr-xr-xcompiler/ccgexprs.nim5
-rwxr-xr-xcompiler/ecmasgen.nim3
-rwxr-xr-xcompiler/magicsys.nim55
-rw-r--r--compiler/saturate.nim79
-rwxr-xr-xcompiler/semcall.nim14
-rwxr-xr-xcompiler/semdata.nim5
-rwxr-xr-xcompiler/semexprs.nim61
-rwxr-xr-xcompiler/semfold.nim161
-rw-r--r--compiler/semmagic.nim6
-rwxr-xr-xcompiler/semtypes.nim3
-rwxr-xr-xcompiler/sigmatch.nim59
-rwxr-xr-xcompiler/transf.nim1
-rwxr-xr-xcompiler/types.nim12
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