mirror of
https://github.com/nim-lang/Nim.git
synced 2026-07-19 07:21:19 +00:00
fixes #287; bugfix: subrange checking is performed again
This commit is contained in:
@@ -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])
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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}:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -103,5 +103,5 @@ On UNIX
|
||||
* ``bin/nimrod c koch``
|
||||
* ``./koch boot -d:release``
|
||||
|
||||
Installation on UNIX can then be done with ``koch install``.
|
||||
Installation on UNIX can then be done with ``koch install [dir]``.
|
||||
|
||||
|
||||
19
tests/compile/tmatrix1.nim
Normal file
19
tests/compile/tmatrix1.nim
Normal file
@@ -0,0 +1,19 @@
|
||||
discard """
|
||||
output: "right proc called"
|
||||
"""
|
||||
|
||||
type
|
||||
TMatrixNM*[M, N, T] = object
|
||||
aij*: array[M, array[N, T]]
|
||||
TMatrix2x2*[T] = TMatrixNM[range[0..1], range[0..1], T]
|
||||
TMatrix3x3*[T] = TMatrixNM[range[0..2], range[0..2], T]
|
||||
|
||||
proc test*[T] (matrix: TMatrix2x2[T]) =
|
||||
echo "wrong proc called"
|
||||
|
||||
proc test*[T] (matrix: TMatrix3x3[T]) =
|
||||
echo "right proc called"
|
||||
|
||||
var matrix: TMatrix3x3[float]
|
||||
|
||||
matrix.test
|
||||
21
tests/reject/tsubrange.nim
Normal file
21
tests/reject/tsubrange.nim
Normal file
@@ -0,0 +1,21 @@
|
||||
discard """
|
||||
line: 20
|
||||
errormsg: "cannot convert 60 to TRange"
|
||||
"""
|
||||
|
||||
type
|
||||
TRange = range[0..40]
|
||||
|
||||
proc p(r: TRange) =
|
||||
nil
|
||||
|
||||
var
|
||||
r: TRange
|
||||
y = 50
|
||||
r = y
|
||||
|
||||
p y
|
||||
|
||||
const
|
||||
myConst: TRange = 60
|
||||
|
||||
19
tests/run/tsubrange.nim
Normal file
19
tests/run/tsubrange.nim
Normal file
@@ -0,0 +1,19 @@
|
||||
discard """
|
||||
file: "tsubrange.nim"
|
||||
outputsub: "value 50 out of range [EOutOfRange]"
|
||||
exitcode: "1"
|
||||
"""
|
||||
|
||||
type
|
||||
TRange = range[0..40]
|
||||
|
||||
proc p(r: TRange) =
|
||||
nil
|
||||
|
||||
var
|
||||
r: TRange
|
||||
y = 50
|
||||
r = y
|
||||
|
||||
#p y
|
||||
|
||||
17
tests/run/tsubrange2.nim
Normal file
17
tests/run/tsubrange2.nim
Normal file
@@ -0,0 +1,17 @@
|
||||
discard """
|
||||
file: "tsubrange2.nim"
|
||||
outputsub: "value 50 out of range [EOutOfRange]"
|
||||
exitcode: "1"
|
||||
"""
|
||||
|
||||
type
|
||||
TRange = range[0..40]
|
||||
|
||||
proc p(r: TRange) =
|
||||
nil
|
||||
|
||||
var
|
||||
r: TRange
|
||||
y = 50
|
||||
p y
|
||||
|
||||
3
todo.txt
3
todo.txt
@@ -13,7 +13,6 @@ Bugs
|
||||
====
|
||||
|
||||
- docgen: sometimes effects are listed twice
|
||||
- even the easiest range checking is not performed anymore
|
||||
- 'result' is not properly cleaned for NRVO
|
||||
- instantiated generics are listed in error messages
|
||||
- sneaking with qualifiedLookup() is really broken!
|
||||
@@ -23,6 +22,7 @@ Bugs
|
||||
- osproc execProcesses can deadlock if all processes fail (as experienced
|
||||
in c++ mode)
|
||||
- bootstrapping does not work in C++ mode
|
||||
- result = result shr 8 for the "system()" wrapper
|
||||
|
||||
|
||||
version 0.9.4
|
||||
@@ -54,7 +54,6 @@ version 0.9.X
|
||||
- improve the compiler as a service
|
||||
- better support for macros that rewrite procs
|
||||
- macros need access to types and symbols (partially implemented)
|
||||
- result = result shr 8 for the "system()" wrapper
|
||||
- rethink the syntax/grammar:
|
||||
* parser is not strict enough with newlines
|
||||
* change comment handling in the AST
|
||||
|
||||
Reference in New Issue
Block a user