summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2019-08-27 23:19:41 +0200
committerGitHub <noreply@github.com>2019-08-27 23:19:41 +0200
commiteaebbfa785eeb8ba586fa43bcd5e240b5c9c4ad9 (patch)
tree4453e28332d2224a584f7de36c19ecbc588a2aa1
parentd564130a3b2596161847d695329ad009e693358a (diff)
parent329e169e964951b39cee863dd715277166497213 (diff)
downloadNim-eaebbfa785eeb8ba586fa43bcd5e240b5c9c4ad9.tar.gz
Fix several float range issues (supersedes #11905) (#12067)
* Fix several float range issues

* address the comments
-rw-r--r--compiler/sem.nim1
-rw-r--r--compiler/semexprs.nim3
-rw-r--r--compiler/semstmts.nim2
-rw-r--r--compiler/semtypes.nim6
-rw-r--r--compiler/sigmatch.nim7
-rw-r--r--tests/range/trange.nim11
6 files changed, 27 insertions, 3 deletions
diff --git a/compiler/sem.nim b/compiler/sem.nim
index a13fd138b..7c47dac22 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -444,6 +444,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
 
 const
   errMissingGenericParamsForTemplate = "'$1' has unspecified generic parameters"
+  errFloatToString = "cannot convert '$1' to '$2'"
 
 proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
                   flags: TExprFlags = {}): PNode =
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 57d9aae4b..765110d56 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -513,6 +513,9 @@ proc changeType(c: PContext; n: PNode, newType: PType, check: bool) =
       if value < firstOrd(c.config, newType) or value > lastOrd(c.config, newType):
         localError(c.config, n.info, "cannot convert " & $value &
                                          " to " & typeToString(newType))
+  of nkFloatLit..nkFloat64Lit:
+    if check and not floatRangeCheck(n.floatVal, newType):
+      localError(c.config, n.info, errFloatToString % [$n.floatVal, typeToString(newType)])
   else: discard
   n.typ = newType
 
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 0d9d1af39..5a9c92647 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -292,6 +292,8 @@ proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode =
       result = newFloatNode(nkFloatLit, BiggestFloat r1.intVal)
       result.info = n.info
       result.typ = typ
+      if not floatRangeCheck(result.floatVal, typ):
+        localError(c.config, n.info, errFloatToString % [$n.floatVal, typeToString(typ)])
     else:
       changeType(c, r1, typ, check=true)
       result = r1
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 4d628e6ec..16cc89e13 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -10,6 +10,8 @@
 # this module does the semantic checking of type declarations
 # included from sem.nim
 
+import math
+
 const
   errStringOrIdentNodeExpected = "string or ident node expected"
   errStringLiteralExpected = "string literal expected"
@@ -236,6 +238,10 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
     else:
       result.n.addSon semConstExpr(c, range[i])
 
+  if (result.n[0].kind in {nkFloatLit..nkFloat64Lit} and classify(result.n[0].floatVal) == fcNan) or
+      (result.n[1].kind in {nkFloatLit..nkFloat64Lit} and classify(result.n[1].floatVal) == fcNan):
+    localError(c.config, n.info, "NaN is not a valid start or end for a range")
+
   if weakLeValue(result.n[0], result.n[1]) == impNo:
     localError(c.config, n.info, "range is empty")
 
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index e4bf13e60..cec3ecb28 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -414,9 +414,10 @@ proc isConvertibleToRange(f, a: PType): bool =
     of tyUInt16: result = a.kind in {tyUInt8, tyUInt16, tyUInt}
     of tyUInt32: result = a.kind in {tyUInt8, tyUInt16, tyUInt32, tyUInt}
     else: result = false
-  elif f.kind in {tyFloat..tyFloat128} and
-       a.kind in {tyFloat..tyFloat128}:
-    result = true
+  elif f.kind in {tyFloat..tyFloat128}:
+    # `isIntLit` is correct and should be used above as well, see PR:
+    # https://github.com/nim-lang/Nim/pull/11197
+    result = isIntLit(a) or a.kind in {tyFloat..tyFloat128}
 
 proc handleFloatRange(f, a: PType): TTypeRelation =
   if a.kind == f.kind:
diff --git a/tests/range/trange.nim b/tests/range/trange.nim
index 41804d0f2..9df0e6975 100644
--- a/tests/range/trange.nim
+++ b/tests/range/trange.nim
@@ -118,3 +118,14 @@ block:
     x3 = R32(4)
 
   doAssert $x1 & $x2 & $x3 == "444"
+
+block:
+  var x1: range[0'f..1'f] = 1
+  const x2: range[0'f..1'f] = 1
+  var x5: range[0'f32..1'f32] = 1'f64
+  const x6: range[0'f32..1'f32] = 1'f64
+
+  reject:
+    const x: range[0'f..1'f] = 2'f
+  reject:
+    const x: range[0'f..1'f] = 2