diff options
author | Araq <rumpf_a@web.de> | 2013-04-12 16:24:58 +0200 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2013-04-12 16:24:58 +0200 |
commit | 3cb3813eed378d753807a07f434234ce2d4c5159 (patch) | |
tree | 7c108fb992666e0833eb6050f53977628fa9534b /compiler | |
parent | f5db2de696af7e33fdcbcf96f2be577c1e9a52e2 (diff) | |
download | Nim-3cb3813eed378d753807a07f434234ce2d4c5159.tar.gz |
fixes #287; bugfix: subrange checking is performed again
Diffstat (limited to 'compiler')
-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 |
8 files changed, 69 insertions, 29 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): |