breaking change: 'and' and 'mod' do not produce a subrange type anymore; fixes #5854
This commit is contained in:
parent
aa526da706
commit
d7a896f19d
6 changed files with 16 additions and 131 deletions
|
|
@ -28,3 +28,6 @@
|
||||||
take ``BackwardsIndex`` indices. ``BackwardsIndex`` is produced by ``system.^``.
|
take ``BackwardsIndex`` indices. ``BackwardsIndex`` is produced by ``system.^``.
|
||||||
This means if you overload ``[]`` or ``[]=`` you need to ensure they also work
|
This means if you overload ``[]`` or ``[]=`` you need to ensure they also work
|
||||||
with ``system.BackwardsIndex`` (if applicable for the accessors).
|
with ``system.BackwardsIndex`` (if applicable for the accessors).
|
||||||
|
- ``mod`` and bitwise ``and`` do not produce ``range`` subtypes anymore. This
|
||||||
|
turned out to be more harmful than helpful and the language is simpler
|
||||||
|
without this special typing rule.
|
||||||
|
|
|
||||||
|
|
@ -550,7 +550,6 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
|
||||||
result = semfold.getConstExpr(c.module, call)
|
result = semfold.getConstExpr(c.module, call)
|
||||||
if result.isNil: result = n
|
if result.isNil: result = n
|
||||||
else: return result
|
else: return result
|
||||||
result.typ = semfold.getIntervalType(callee.magic, call)
|
|
||||||
|
|
||||||
block maybeLabelAsStatic:
|
block maybeLabelAsStatic:
|
||||||
# XXX: temporary work-around needed for tlateboundstatic.
|
# XXX: temporary work-around needed for tlateboundstatic.
|
||||||
|
|
|
||||||
|
|
@ -137,116 +137,6 @@ proc makeRangeF(typ: PType, first, last: BiggestFloat): PType =
|
||||||
result.n = n
|
result.n = n
|
||||||
addSonSkipIntLit(result, skipTypes(typ, {tyRange}))
|
addSonSkipIntLit(result, skipTypes(typ, {tyRange}))
|
||||||
|
|
||||||
proc getIntervalType*(m: TMagic, n: PNode): PType =
|
|
||||||
# Nim requires interval arithmetic for ``range`` types. Lots of tedious
|
|
||||||
# work but the feature is very nice for reducing explicit conversions.
|
|
||||||
const ordIntLit = {nkIntLit..nkUInt64Lit}
|
|
||||||
result = n.typ
|
|
||||||
|
|
||||||
template commutativeOp(opr: untyped) =
|
|
||||||
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: untyped) =
|
|
||||||
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)
|
|
||||||
if a.n[0].floatVal <= 0.0:
|
|
||||||
result = makeRangeF(a, 0.0, abs(getFloat(a.n.sons[0])))
|
|
||||||
else:
|
|
||||||
result = makeRangeF(a, abs(getFloat(a.n.sons[1])),
|
|
||||||
abs(getFloat(a.n.sons[0])))
|
|
||||||
of mAbsI:
|
|
||||||
let a = n.sons[1].typ
|
|
||||||
if isIntRange(a):
|
|
||||||
if a.n[0].intVal <= 0:
|
|
||||||
result = makeRange(a, 0, `|abs|`(getInt(a.n.sons[0])))
|
|
||||||
else:
|
|
||||||
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, mAddU:
|
|
||||||
commutativeOp(`|+|`)
|
|
||||||
of mMulI, mMulU:
|
|
||||||
commutativeOp(`|*|`)
|
|
||||||
of mSubI, mSubU:
|
|
||||||
binaryOp(`|-|`)
|
|
||||||
of mBitandI:
|
|
||||||
# since uint64 is still not even valid for 'range' (since it's no ordinal
|
|
||||||
# yet), we exclude it from the list (see bug #1638) for now:
|
|
||||||
var a = n.sons[1]
|
|
||||||
var b = n.sons[2]
|
|
||||||
# symmetrical:
|
|
||||||
if b.kind notin ordIntLit: swap(a, b)
|
|
||||||
if b.kind in ordIntLit:
|
|
||||||
let x = b.intVal|+|1
|
|
||||||
if (x and -x) == x and x >= 0:
|
|
||||||
result = makeRange(n.typ, 0, b.intVal)
|
|
||||||
of mModU:
|
|
||||||
let a = n.sons[1]
|
|
||||||
let b = n.sons[2]
|
|
||||||
if b.kind in ordIntLit:
|
|
||||||
if b.intVal >= 0:
|
|
||||||
result = makeRange(n.typ, 0, b.intVal-1)
|
|
||||||
else:
|
|
||||||
result = makeRange(n.typ, b.intVal+1, 0)
|
|
||||||
of mModI:
|
|
||||||
# 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(n.typ, -(b.intVal-1), b.intVal-1)
|
|
||||||
else:
|
|
||||||
result = makeRange(n.typ, b.intVal+1, -(b.intVal+1))
|
|
||||||
of mDivI, mDivU:
|
|
||||||
binaryOp(`|div|`)
|
|
||||||
of mMinI:
|
|
||||||
commutativeOp(min)
|
|
||||||
of mMaxI:
|
|
||||||
commutativeOp(max)
|
|
||||||
else: discard
|
|
||||||
|
|
||||||
discard """
|
|
||||||
mShlI,
|
|
||||||
mShrI, mAddF64, mSubF64, mMulF64, mDivF64, mMaxF64, mMinF64
|
|
||||||
"""
|
|
||||||
|
|
||||||
proc evalIs(n, a: PNode): PNode =
|
proc evalIs(n, a: PNode): PNode =
|
||||||
# XXX: This should use the standard isOpImpl
|
# XXX: This should use the standard isOpImpl
|
||||||
internalAssert a.kind == nkSym and a.sym.kind == skType
|
internalAssert a.kind == nkSym and a.sym.kind == skType
|
||||||
|
|
|
||||||
|
|
@ -137,25 +137,6 @@ determined). Assignments from the base type to one of its subrange types
|
||||||
|
|
||||||
A subrange type has the same size as its base type (``int`` in the example).
|
A subrange type has the same size as its base type (``int`` in the example).
|
||||||
|
|
||||||
Nim requires `interval arithmetic`:idx: for subrange types over a set
|
|
||||||
of built-in operators that involve constants: ``x %% 3`` is of
|
|
||||||
type ``range[0..2]``. The following built-in operators for integers are
|
|
||||||
affected by this rule: ``-``, ``+``, ``*``, ``min``, ``max``, ``succ``,
|
|
||||||
``pred``, ``mod``, ``div``, ``%%``, ``and`` (bitwise ``and``).
|
|
||||||
|
|
||||||
Bitwise ``and`` only produces a ``range`` if one of its operands is a
|
|
||||||
constant *x* so that (x+1) is a power of two.
|
|
||||||
(Bitwise ``and`` is then a ``%%`` operation.)
|
|
||||||
|
|
||||||
This means that the following code is accepted:
|
|
||||||
|
|
||||||
.. code-block:: nim
|
|
||||||
case (x and 3) + 7
|
|
||||||
of 7: echo "A"
|
|
||||||
of 8: echo "B"
|
|
||||||
of 9: echo "C"
|
|
||||||
of 10: echo "D"
|
|
||||||
# note: no ``else`` required as (x and 3) + 7 has the type: range[7..10]
|
|
||||||
|
|
||||||
|
|
||||||
Pre-defined floating point types
|
Pre-defined floating point types
|
||||||
|
|
|
||||||
13
tests/arithm/tsubrange.nim
Normal file
13
tests/arithm/tsubrange.nim
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
discard """
|
||||||
|
output: '''1'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
# bug #5854
|
||||||
|
type
|
||||||
|
n16* = range[0'i16..high(int16)]
|
||||||
|
|
||||||
|
var level: n16 = 1
|
||||||
|
let maxLevel: n16 = 1
|
||||||
|
|
||||||
|
level = min(level + 2, maxLevel)
|
||||||
|
echo level
|
||||||
1
todo.txt
1
todo.txt
|
|
@ -2,7 +2,6 @@ version 1.0 battle plan
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
- make FlowVar compatible to Futures
|
- make FlowVar compatible to Futures
|
||||||
- remove 'mod x' type rule
|
|
||||||
- fix "high priority" bugs
|
- fix "high priority" bugs
|
||||||
- try to fix as many compiler crashes as reasonable
|
- try to fix as many compiler crashes as reasonable
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue