diff options
-rw-r--r-- | compiler/ccgexprs.nim | 10 | ||||
-rw-r--r-- | compiler/sem.nim | 2 | ||||
-rw-r--r-- | compiler/semexprs.nim | 25 | ||||
-rw-r--r-- | compiler/semfold.nim | 19 | ||||
-rw-r--r-- | compiler/semstmts.nim | 6 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 21 | ||||
-rw-r--r-- | compiler/transf.nim | 11 | ||||
-rw-r--r-- | compiler/types.nim | 4 | ||||
-rw-r--r-- | install.txt | 2 | ||||
-rw-r--r-- | tests/compile/tmatrix1.nim | 19 | ||||
-rw-r--r-- | tests/reject/tsubrange.nim | 21 | ||||
-rw-r--r-- | tests/run/tsubrange.nim | 19 | ||||
-rw-r--r-- | tests/run/tsubrange2.nim | 17 | ||||
-rw-r--r-- | todo.txt | 3 |
14 files changed, 147 insertions, 32 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): diff --git a/install.txt b/install.txt index a703edba0..eefdfb682 100644 --- a/install.txt +++ b/install.txt @@ -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]``. diff --git a/tests/compile/tmatrix1.nim b/tests/compile/tmatrix1.nim new file mode 100644 index 000000000..0adf30b57 --- /dev/null +++ b/tests/compile/tmatrix1.nim @@ -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 diff --git a/tests/reject/tsubrange.nim b/tests/reject/tsubrange.nim new file mode 100644 index 000000000..b4a333bf3 --- /dev/null +++ b/tests/reject/tsubrange.nim @@ -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 + diff --git a/tests/run/tsubrange.nim b/tests/run/tsubrange.nim new file mode 100644 index 000000000..d525eae1e --- /dev/null +++ b/tests/run/tsubrange.nim @@ -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 + diff --git a/tests/run/tsubrange2.nim b/tests/run/tsubrange2.nim new file mode 100644 index 000000000..42c16812f --- /dev/null +++ b/tests/run/tsubrange2.nim @@ -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 + diff --git a/todo.txt b/todo.txt index 31b15d1c1..65a9127d1 100644 --- a/todo.txt +++ b/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 |