fixes #287; bugfix: subrange checking is performed again

This commit is contained in:
Araq 2013-04-12 16:24:58 +02:00
commit 3cb3813eed
14 changed files with 147 additions and 32 deletions

View file

@ -1331,8 +1331,14 @@ proc genInOp(p: BProc, e: PNode, d: var TLoc) =
var a, b, x, y: TLoc var a, b, x, y: TLoc
if (e.sons[1].Kind == nkCurly) and fewCmps(e.sons[1]): if (e.sons[1].Kind == nkCurly) and fewCmps(e.sons[1]):
# a set constructor but not a constant set: # a set constructor but not a constant set:
# do not emit the set, but generate a bunch of comparisons # do not emit the set, but generate a bunch of comparisons; and if we do
initLocExpr(p, e.sons[2], a) # 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) initLoc(b, locExpr, e.typ, OnUnknown)
b.r = toRope("(") b.r = toRope("(")
var length = sonsLen(e.sons[1]) var length = sonsLen(e.sons[1])

View file

@ -27,7 +27,7 @@ proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
proc semProcBody(c: PContext, n: PNode): PNode proc semProcBody(c: PContext, n: PNode): PNode
proc fitNode(c: PContext, formal: PType, arg: 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 semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType proc semTypeNode(c: PContext, n: PNode, prev: PType): PType

View file

@ -354,11 +354,11 @@ proc overloadedCallOpr(c: PContext, n: PNode): PNode =
for i in countup(0, sonsLen(n) - 1): addSon(result, n.sons[i]) for i in countup(0, sonsLen(n) - 1): addSon(result, n.sons[i])
result = semExpr(c, result) result = semExpr(c, result)
proc changeType(n: PNode, newType: PType) = proc changeType(n: PNode, newType: PType, check: bool) =
case n.kind case n.kind
of nkCurly, nkBracket: of nkCurly, nkBracket:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
changeType(n.sons[i], elemType(newType)) changeType(n.sons[i], elemType(newType), check)
of nkPar: of nkPar:
if newType.kind != tyTuple: if newType.kind != tyTuple:
InternalError(n.info, "changeType: no tuple type for constructor") InternalError(n.info, "changeType: no tuple type for constructor")
@ -373,15 +373,21 @@ proc changeType(n: PNode, newType: PType) =
if f == nil: if f == nil:
internalError(m.info, "changeType(): invalid identifier") internalError(m.info, "changeType(): invalid identifier")
return return
changeType(n.sons[i].sons[1], f.typ) changeType(n.sons[i].sons[1], f.typ, check)
else: else:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
var m = n.sons[i] var m = n.sons[i]
var a = newNodeIT(nkExprColonExpr, m.info, newType.sons[i]) var a = newNodeIT(nkExprColonExpr, m.info, newType.sons[i])
addSon(a, newSymNode(newType.n.sons[i].sym)) addSon(a, newSymNode(newType.n.sons[i].sym))
addSon(a, m) addSon(a, m)
changeType(m, newType.sons[i]) changeType(m, newType.sons[i], check)
n.sons[i] = a 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 else: nil
n.typ = newType n.typ = newType
@ -461,7 +467,7 @@ proc fixAbstractType(c: PContext, n: PNode) =
elif skipTypes(it.sons[1].typ, abstractVar).kind in elif skipTypes(it.sons[1].typ, abstractVar).kind in
{tyNil, tyArrayConstr, tyTuple, tySet}: {tyNil, tyArrayConstr, tyTuple, tySet}:
var s = skipTypes(it.typ, abstractVar) var s = skipTypes(it.typ, abstractVar)
changeType(it.sons[1], s) changeType(it.sons[1], s, check=true)
n.sons[i] = it.sons[1] n.sons[i] = it.sons[1]
of nkBracket: of nkBracket:
# an implicitely constructed array (passed to an open array): # 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]) call.add(n.sons[0])
var allConst = true var allConst = true
for i in 1 .. < n.len: for i in 1 .. < n.len:
let a = getConstExpr(c.module, n.sons[i]) var a = getConstExpr(c.module, n.sons[i])
if a != nil: call.add(a) if a == nil:
else:
allConst = false allConst = false
call.add(n.sons[i]) a = n.sons[i]
if a.kind == nkHiddenStdConv: a = a.sons[1]
call.add(a)
if allConst: if allConst:
result = semfold.getConstExpr(c.module, call) result = semfold.getConstExpr(c.module, call)
if result.isNil: result = n if result.isNil: result = n

View file

@ -458,16 +458,23 @@ proc getAppType(n: PNode): PNode =
else: else:
result = newStrNodeT("console", n) 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? # XXX range checks?
case skipTypes(n.typ, abstractRange).kind case skipTypes(n.typ, abstractRange).kind
of tyInt..tyInt64: of tyInt..tyInt64:
case skipTypes(a.typ, abstractRange).kind 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) of tyChar: result = newIntNodeT(getOrdValue(a), n)
else: else:
result = a result = a
result.typ = n.typ result.typ = n.typ
if check: rangeCheck(n, result.intVal)
of tyFloat..tyFloat64: of tyFloat..tyFloat64:
case skipTypes(a.typ, abstractRange).kind case skipTypes(a.typ, abstractRange).kind
of tyInt..tyInt64, tyEnum, tyBool, tyChar: of tyInt..tyInt64, tyEnum, tyBool, tyChar:
@ -695,7 +702,7 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkCast: of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkCast:
var a = getConstExpr(m, n.sons[1]) var a = getConstExpr(m, n.sons[1])
if a == nil: return if a == nil: return
result = foldConv(n, a) result = foldConv(n, a, check=n.kind == nkHiddenStdConv)
of nkBracketExpr: result = foldArrayAccess(m, n) of nkBracketExpr: result = foldArrayAccess(m, n)
of nkDotExpr: result = foldFieldAccess(m, n) of nkDotExpr: result = foldFieldAccess(m, n)
else: else:

View file

@ -166,10 +166,10 @@ proc semCase(c: PContext, n: PNode): PNode =
proc fitRemoveHiddenConv(c: PContext, typ: Ptype, n: PNode): PNode = proc fitRemoveHiddenConv(c: PContext, typ: Ptype, n: PNode): PNode =
result = fitNode(c, typ, n) result = fitNode(c, typ, n)
if result.kind in {nkHiddenStdConv, nkHiddenSubConv}: if result.kind in {nkHiddenStdConv, nkHiddenSubConv}:
changeType(result.sons[1], typ) changeType(result.sons[1], typ, check=true)
result = result.sons[1] result = result.sons[1]
elif not sameType(result.typ, typ): elif not sameType(result.typ, typ):
changeType(result, typ) changeType(result, typ, check=false)
proc findShadowedVar(c: PContext, v: PSym): PSym = proc findShadowedVar(c: PContext, v: PSym): PSym =
for i in countdown(c.tab.tos - 2, ModuleTablePos+1): for i in countdown(c.tab.tos - 2, ModuleTablePos+1):

View file

@ -362,6 +362,22 @@ proc matchTypeClass(c: var TCandidate, f, a: PType): TTypeRelation =
result = if matchTypeClass(c.bindings, f, a): isGeneric result = if matchTypeClass(c.bindings, f, a): isGeneric
else: isNone 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 = proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
# is a subtype of f? # is a subtype of f?
result = isNone result = isNone
@ -386,6 +402,8 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
result = typeRel(c, base(f), base(a)) result = typeRel(c, base(f), base(a))
# bugfix: accept integer conversions here # bugfix: accept integer conversions here
#if result < isGeneric: result = isNone #if result < isGeneric: result = isNone
if result notin {isNone, isGeneric}:
result = typeRangeRel(f, a)
elif skipTypes(f, {tyRange}).kind == a.kind: elif skipTypes(f, {tyRange}).kind == a.kind:
result = isIntConv result = isIntConv
elif isConvertibleToRange(skipTypes(f, {tyRange}), a): 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) result = implicitConv(nkHiddenSubConv, f, copyTree(arg), m, c)
of isSubrange: of isSubrange:
inc(m.subtypeMatches) inc(m.subtypeMatches)
result = copyTree(arg) #result = copyTree(arg)
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
of isGeneric: of isGeneric:
inc(m.genericMatches) inc(m.genericMatches)
if m.calleeSym != nil and m.calleeSym.kind in {skMacro, skTemplate}: if m.calleeSym != nil and m.calleeSym.kind in {skMacro, skTemplate}:

View file

@ -323,10 +323,10 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
of tyInt..tyInt64, tyEnum, tyChar, tyBool, tyUInt8..tyUInt32: of tyInt..tyInt64, tyEnum, tyChar, tyBool, tyUInt8..tyUInt32:
# we don't include uint and uint64 here as these are no ordinal types ;-) # we don't include uint and uint64 here as these are no ordinal types ;-)
if not isOrdinalType(source): if not isOrdinalType(source):
# XXX int64 -> float conversion? # float -> int conversions. ugh.
result = transformSons(c, n) result = transformSons(c, n)
elif firstOrd(dest) <= firstOrd(source) and elif firstOrd(n.typ) <= firstOrd(n.sons[1].typ) and
lastOrd(source) <= lastOrd(dest): lastOrd(n.sons[1].typ) <= lastOrd(n.typ):
# BUGFIX: simply leave n as it is; we need a nkConv node, # BUGFIX: simply leave n as it is; we need a nkConv node,
# but no range check: # but no range check:
result = transformSons(c, n) result = transformSons(c, n)
@ -341,6 +341,7 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
result[1] = newIntTypeNode(nkIntLit, firstOrd(dest), source).PTransNode result[1] = newIntTypeNode(nkIntLit, firstOrd(dest), source).PTransNode
result[2] = newIntTypeNode(nkIntLit, lastOrd(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: if skipTypes(n.typ, abstractVar).kind == tyRange:
result = newTransNode(nkChckRangeF, n, 3) result = newTransNode(nkChckRangeF, n, 3)
dest = skipTypes(n.typ, abstractVar) dest = skipTypes(n.typ, abstractVar)

View file

@ -486,7 +486,7 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
of tyPtr, tyRef, tyVar, tyMutable, tyConst: of tyPtr, tyRef, tyVar, tyMutable, tyConst:
result = typeToStr[t.kind] & typeToString(t.sons[0]) result = typeToStr[t.kind] & typeToString(t.sons[0])
of tyRange: of tyRange:
result = "range " & rangeToStr(t.n) result = "range " & rangeToStr(t.n) & "(" & typeToString(t.sons[0]) & ")"
of tyProc: of tyProc:
result = if tfIterator in t.flags: "iterator (" else: "proc (" result = if tfIterator in t.flags: "iterator (" else: "proc ("
for i in countup(1, sonsLen(t) - 1): for i in countup(1, sonsLen(t) - 1):

View file

@ -103,5 +103,5 @@ On UNIX
* ``bin/nimrod c koch`` * ``bin/nimrod c koch``
* ``./koch boot -d:release`` * ``./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]``.

View 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

View 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
View 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
View 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

View file

@ -13,7 +13,6 @@ Bugs
==== ====
- docgen: sometimes effects are listed twice - docgen: sometimes effects are listed twice
- even the easiest range checking is not performed anymore
- 'result' is not properly cleaned for NRVO - 'result' is not properly cleaned for NRVO
- instantiated generics are listed in error messages - instantiated generics are listed in error messages
- sneaking with qualifiedLookup() is really broken! - sneaking with qualifiedLookup() is really broken!
@ -23,6 +22,7 @@ Bugs
- osproc execProcesses can deadlock if all processes fail (as experienced - osproc execProcesses can deadlock if all processes fail (as experienced
in c++ mode) in c++ mode)
- bootstrapping does not work in C++ mode - bootstrapping does not work in C++ mode
- result = result shr 8 for the "system()" wrapper
version 0.9.4 version 0.9.4
@ -54,7 +54,6 @@ version 0.9.X
- improve the compiler as a service - improve the compiler as a service
- better support for macros that rewrite procs - better support for macros that rewrite procs
- macros need access to types and symbols (partially implemented) - macros need access to types and symbols (partially implemented)
- result = result shr 8 for the "system()" wrapper
- rethink the syntax/grammar: - rethink the syntax/grammar:
* parser is not strict enough with newlines * parser is not strict enough with newlines
* change comment handling in the AST * change comment handling in the AST