summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2013-04-12 16:24:58 +0200
committerAraq <rumpf_a@web.de>2013-04-12 16:24:58 +0200
commit3cb3813eed378d753807a07f434234ce2d4c5159 (patch)
tree7c108fb992666e0833eb6050f53977628fa9534b /compiler
parentf5db2de696af7e33fdcbcf96f2be577c1e9a52e2 (diff)
downloadNim-3cb3813eed378d753807a07f434234ce2d4c5159.tar.gz
fixes #287; bugfix: subrange checking is performed again
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ccgexprs.nim10
-rw-r--r--compiler/sem.nim2
-rw-r--r--compiler/semexprs.nim25
-rw-r--r--compiler/semfold.nim19
-rw-r--r--compiler/semstmts.nim6
-rw-r--r--compiler/sigmatch.nim21
-rw-r--r--compiler/transf.nim11
-rw-r--r--compiler/types.nim4
8 files changed, 69 insertions, 29 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 426f1b813..6a2ffe752 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -1331,8 +1331,14 @@ proc genInOp(p: BProc, e: PNode, d: var TLoc) =
   var a, b, x, y: TLoc
   if (e.sons[1].Kind == nkCurly) and fewCmps(e.sons[1]):
     # a set constructor but not a constant set:
-    # do not emit the set, but generate a bunch of comparisons
-    initLocExpr(p, e.sons[2], a)
+    # do not emit the set, but generate a bunch of comparisons; and if we do
+    # so, we skip the unnecessary range check: This is a semantical extension
+    # that code now relies on. :-/ XXX
+    let ea = if e.sons[2].kind in {nkChckRange, nkChckRange64}: 
+               e.sons[2].sons[0]
+             else:
+               e.sons[2]
+    initLocExpr(p, ea, a)
     initLoc(b, locExpr, e.typ, OnUnknown)
     b.r = toRope("(")
     var length = sonsLen(e.sons[1])
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 60ece4b30..805af9e31 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -27,7 +27,7 @@ proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
 proc semProcBody(c: PContext, n: PNode): PNode
 
 proc fitNode(c: PContext, formal: PType, arg: PNode): PNode
-proc changeType(n: PNode, newType: PType)
+proc changeType(n: PNode, newType: PType, check: bool)
 
 proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode
 proc semTypeNode(c: PContext, n: PNode, prev: PType): PType
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index bf07f843e..45b43e682 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -354,11 +354,11 @@ proc overloadedCallOpr(c: PContext, n: PNode): PNode =
     for i in countup(0, sonsLen(n) - 1): addSon(result, n.sons[i])
     result = semExpr(c, result)
 
-proc changeType(n: PNode, newType: PType) = 
+proc changeType(n: PNode, newType: PType, check: bool) = 
   case n.kind
   of nkCurly, nkBracket: 
     for i in countup(0, sonsLen(n) - 1): 
-      changeType(n.sons[i], elemType(newType))
+      changeType(n.sons[i], elemType(newType), check)
   of nkPar: 
     if newType.kind != tyTuple: 
       InternalError(n.info, "changeType: no tuple type for constructor")
@@ -373,15 +373,21 @@ proc changeType(n: PNode, newType: PType) =
         if f == nil: 
           internalError(m.info, "changeType(): invalid identifier")
           return
-        changeType(n.sons[i].sons[1], f.typ)
+        changeType(n.sons[i].sons[1], f.typ, check)
     else:
       for i in countup(0, sonsLen(n) - 1):
         var m = n.sons[i]
         var a = newNodeIT(nkExprColonExpr, m.info, newType.sons[i])
         addSon(a, newSymNode(newType.n.sons[i].sym))
         addSon(a, m)
-        changeType(m, newType.sons[i])
+        changeType(m, newType.sons[i], check)
         n.sons[i] = a
+  of nkCharLit..nkUInt64Lit:
+    if check:
+      let value = n.intVal
+      if value < firstOrd(newType) or value > lastOrd(newType):
+        LocalError(n.info, errGenerated, "cannot convert " & $value &
+                                         " to " & typeToString(newType))
   else: nil
   n.typ = newType
 
@@ -461,7 +467,7 @@ proc fixAbstractType(c: PContext, n: PNode) =
       elif skipTypes(it.sons[1].typ, abstractVar).kind in
           {tyNil, tyArrayConstr, tyTuple, tySet}: 
         var s = skipTypes(it.typ, abstractVar)
-        changeType(it.sons[1], s)
+        changeType(it.sons[1], s, check=true)
         n.sons[i] = it.sons[1]
     of nkBracket: 
       # an implicitely constructed array (passed to an open array):
@@ -560,11 +566,12 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
     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:
+      var a = getConstExpr(c.module, n.sons[i])
+      if a == nil:
         allConst = false
-        call.add(n.sons[i])
+        a = n.sons[i]
+        if a.kind == nkHiddenStdConv: a = a.sons[1]
+      call.add(a)
     if allConst:
       result = semfold.getConstExpr(c.module, call)
       if result.isNil: result = n
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index d304ddd3c..8142b5e03 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -458,21 +458,28 @@ proc getAppType(n: PNode): PNode =
   else:
     result = newStrNodeT("console", n)
 
-proc foldConv*(n, a: PNode): PNode = 
+proc rangeCheck(n: PNode, value: biggestInt) =
+  if value < firstOrd(n.typ) or value > lastOrd(n.typ):
+    LocalError(n.info, errGenerated, "cannot convert " & $value &
+                                     " to " & typeToString(n.typ))
+
+proc foldConv*(n, a: PNode; check = false): PNode = 
   # XXX range checks?
   case skipTypes(n.typ, abstractRange).kind
   of tyInt..tyInt64: 
     case skipTypes(a.typ, abstractRange).kind
-    of tyFloat..tyFloat64: result = newIntNodeT(system.toInt(getFloat(a)), n)
+    of tyFloat..tyFloat64:
+      result = newIntNodeT(system.toInt(getFloat(a)), n)
     of tyChar: result = newIntNodeT(getOrdValue(a), n)
     else: 
       result = a
       result.typ = n.typ
-  of tyFloat..tyFloat64: 
+    if check: rangeCheck(n, result.intVal)
+  of tyFloat..tyFloat64:
     case skipTypes(a.typ, abstractRange).kind
     of tyInt..tyInt64, tyEnum, tyBool, tyChar: 
       result = newFloatNodeT(toFloat(int(getOrdValue(a))), n)
-    else: 
+    else:
       result = a
       result.typ = n.typ
   of tyOpenArray, tyVarargs, tyProc: 
@@ -694,8 +701,8 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
     result.typ = n.typ
   of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkCast: 
     var a = getConstExpr(m, n.sons[1])
-    if a == nil: return 
-    result = foldConv(n, a)
+    if a == nil: return
+    result = foldConv(n, a, check=n.kind == nkHiddenStdConv)
   of nkBracketExpr: result = foldArrayAccess(m, n)
   of nkDotExpr: result = foldFieldAccess(m, n)
   else:
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 2f5620bb4..9e9de7260 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -166,10 +166,10 @@ proc semCase(c: PContext, n: PNode): PNode =
 proc fitRemoveHiddenConv(c: PContext, typ: Ptype, n: PNode): PNode = 
   result = fitNode(c, typ, n)
   if result.kind in {nkHiddenStdConv, nkHiddenSubConv}: 
-    changeType(result.sons[1], typ)
+    changeType(result.sons[1], typ, check=true)
     result = result.sons[1]
-  elif not sameType(result.typ, typ): 
-    changeType(result, typ)
+  elif not sameType(result.typ, typ):
+    changeType(result, typ, check=false)
 
 proc findShadowedVar(c: PContext, v: PSym): PSym =
   for i in countdown(c.tab.tos - 2, ModuleTablePos+1):
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index f479267a0..ddda493ee 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -362,6 +362,22 @@ proc matchTypeClass(c: var TCandidate, f, a: PType): TTypeRelation =
   result = if matchTypeClass(c.bindings, f, a): isGeneric
            else: isNone
 
+proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} =
+  let
+    a0 = firstOrd(a)
+    a1 = lastOrd(a)
+    f0 = firstOrd(f)
+    f1 = lastOrd(f)
+  if a0 == f0 and a1 == f1:
+    result = isEqual
+  elif a0 >= f0 and a1 <= f1:
+    result = isConvertible
+  elif a0 <= f1 and f0 <= a1:
+    # X..Y and C..D overlap iff (X <= D and C <= Y)
+    result = isConvertible
+  else:
+    result = isNone
+
 proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation = 
   # is a subtype of f?
   result = isNone
@@ -386,6 +402,8 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
       result = typeRel(c, base(f), base(a))
       # bugfix: accept integer conversions here
       #if result < isGeneric: result = isNone
+      if result notin {isNone, isGeneric}:
+        result = typeRangeRel(f, a)
     elif skipTypes(f, {tyRange}).kind == a.kind:
       result = isIntConv
     elif isConvertibleToRange(skipTypes(f, {tyRange}), a):
@@ -704,7 +722,8 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
     result = implicitConv(nkHiddenSubConv, f, copyTree(arg), m, c)
   of isSubrange:
     inc(m.subtypeMatches)
-    result = copyTree(arg)
+    #result = copyTree(arg)
+    result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
   of isGeneric:
     inc(m.genericMatches)
     if m.calleeSym != nil and m.calleeSym.kind in {skMacro, skTemplate}:
diff --git a/compiler/transf.nim b/compiler/transf.nim
index 679f7d12f..058143cdd 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -323,10 +323,10 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
   of tyInt..tyInt64, tyEnum, tyChar, tyBool, tyUInt8..tyUInt32: 
     # we don't include uint and uint64 here as these are no ordinal types ;-)
     if not isOrdinalType(source):
-      # XXX int64 -> float conversion?
+      # float -> int conversions. ugh.
       result = transformSons(c, n)
-    elif firstOrd(dest) <= firstOrd(source) and
-        lastOrd(source) <= lastOrd(dest): 
+    elif firstOrd(n.typ) <= firstOrd(n.sons[1].typ) and
+        lastOrd(n.sons[1].typ) <= lastOrd(n.typ): 
       # BUGFIX: simply leave n as it is; we need a nkConv node,
       # but no range check:
       result = transformSons(c, n)
@@ -334,13 +334,14 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
       # generate a range check:
       if dest.kind == tyInt64 or source.kind == tyInt64: 
         result = newTransNode(nkChckRange64, n, 3)
-      else: 
+      else:
         result = newTransNode(nkChckRange, n, 3)
       dest = skipTypes(n.typ, abstractVar)
       result[0] = transform(c, n.sons[1])
       result[1] = newIntTypeNode(nkIntLit, firstOrd(dest), source).PTransNode
       result[2] = newIntTypeNode(nkIntLit, lastOrd(dest), source).PTransNode
-  of tyFloat..tyFloat128: 
+  of tyFloat..tyFloat128:
+    # XXX int64 -> float conversion?
     if skipTypes(n.typ, abstractVar).kind == tyRange: 
       result = newTransNode(nkChckRangeF, n, 3)
       dest = skipTypes(n.typ, abstractVar)
diff --git a/compiler/types.nim b/compiler/types.nim
index 0bd7e2679..4b528d9a2 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -485,8 +485,8 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
     add(result, ']')
   of tyPtr, tyRef, tyVar, tyMutable, tyConst: 
     result = typeToStr[t.kind] & typeToString(t.sons[0])
-  of tyRange: 
-    result = "range " & rangeToStr(t.n)
+  of tyRange:
+    result = "range " & rangeToStr(t.n) & "(" & typeToString(t.sons[0]) & ")"
   of tyProc:
     result = if tfIterator in t.flags: "iterator (" else: "proc ("
     for i in countup(1, sonsLen(t) - 1):