mirror of
https://github.com/nim-lang/Nim.git
synced 2026-08-29 01:51:43 +00:00
warn on set types bigger than max size, default to 0..255 for int literals (#21659)
* test implicitly huge set types refs https://github.com/nim-lang/RFCs/issues/298 * oh my god * boot at least * don't error, fix remaining issues, no 2 len arrays * fix runnable example * test assuming 0..255 for int literal * test refactor, add changelog, test
This commit is contained in:
@@ -219,6 +219,9 @@
|
||||
replacement of the `nnkFormalParams` node as well as having child nodes
|
||||
unlike other type class AST.
|
||||
|
||||
- Signed integer literals in `set` literals now default to a range type of
|
||||
`0..255` instead of `0..65535` (the maximum size of sets).
|
||||
|
||||
## Standard library additions and changes
|
||||
|
||||
[//]: # "Changes:"
|
||||
|
||||
@@ -653,7 +653,7 @@ proc genParForStmt(p: BProc, t: PNode) =
|
||||
#initLoc(forLoopVar.loc, locLocalVar, forLoopVar.typ, onStack)
|
||||
#discard mangleName(forLoopVar)
|
||||
let call = t[1]
|
||||
assert(call.len in {4, 5})
|
||||
assert(call.len == 4 or call.len == 5)
|
||||
initLocExpr(p, call[1], rangeA)
|
||||
initLocExpr(p, call[2], rangeB)
|
||||
|
||||
|
||||
@@ -876,7 +876,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
of "verbosity":
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
let verbosity = parseInt(arg)
|
||||
if verbosity notin {0..3}:
|
||||
if verbosity notin 0..3:
|
||||
localError(conf, info, "invalid verbosity level: '$1'" % arg)
|
||||
conf.verbosity = verbosity
|
||||
var verb = NotesVerbosity[conf.verbosity]
|
||||
|
||||
@@ -84,6 +84,7 @@ type
|
||||
warnPtrToCstringConv = "PtrToCstringConv",
|
||||
warnEffect = "Effect",
|
||||
warnCastSizes = "CastSizes"
|
||||
warnAboveMaxSizeSet = "AboveMaxSizeSet",
|
||||
warnImplicitTemplateRedefinition = "ImplicitTemplateRedefinition",
|
||||
warnUnnamedBreak = "UnnamedBreak",
|
||||
warnStmtListLambda = "StmtListLambda",
|
||||
@@ -186,6 +187,7 @@ const
|
||||
warnPtrToCstringConv: "unsafe conversion to 'cstring' from '$1'; this will become a compile time error in the future",
|
||||
warnEffect: "$1",
|
||||
warnCastSizes: "$1",
|
||||
warnAboveMaxSizeSet: "$1",
|
||||
warnImplicitTemplateRedefinition: "template '$1' is implicitly redefined; this is deprecated, add an explicit .redefine pragma",
|
||||
warnUnnamedBreak: "Using an unnamed break in a block is deprecated; Use a named block with a named break instead",
|
||||
warnStmtListLambda: "statement list expression assumed to be anonymous proc; this is deprecated, use `do (): ...` or `proc () = ...` instead",
|
||||
|
||||
@@ -347,7 +347,8 @@ proc genDeref*(n: PNode; k = nkHiddenDeref): PNode =
|
||||
|
||||
proc callCodegenProc*(g: ModuleGraph; name: string;
|
||||
info: TLineInfo = unknownLineInfo;
|
||||
arg1, arg2, arg3, optionalArgs: PNode = nil): PNode =
|
||||
arg1: PNode = nil, arg2: PNode = nil,
|
||||
arg3: PNode = nil, optionalArgs: PNode = nil): PNode =
|
||||
result = newNodeI(nkCall, info)
|
||||
let sym = magicsys.getCompilerProc(g, name)
|
||||
if sym == nil:
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
|
||||
const
|
||||
MaxSetElements* = 1 shl 16 # (2^16) to support unicode character sets?
|
||||
DefaultSetElements* = 1 shl 8
|
||||
## assumed set element count when using int literals
|
||||
VersionAsString* = system.NimVersion
|
||||
RodFileVersion* = "1223" # modify this if the rod-format changes!
|
||||
|
||||
|
||||
@@ -2563,34 +2563,39 @@ proc semSetConstr(c: PContext, n: PNode, expectedType: PType = nil): PNode =
|
||||
# only semantic checking for all elements, later type checking:
|
||||
var typ: PType = nil
|
||||
for i in 0..<n.len:
|
||||
let doSetType = typ == nil
|
||||
if isRange(n[i]):
|
||||
checkSonsLen(n[i], 3, c.config)
|
||||
n[i][1] = semExprWithType(c, n[i][1], {efTypeAllowed}, expectedElementType)
|
||||
n[i][2] = semExprWithType(c, n[i][2], {efTypeAllowed}, expectedElementType)
|
||||
if typ == nil:
|
||||
if doSetType:
|
||||
typ = skipTypes(n[i][1].typ,
|
||||
{tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink})
|
||||
if expectedElementType == nil:
|
||||
expectedElementType = typ
|
||||
n[i].typ = n[i][2].typ # range node needs type too
|
||||
elif n[i].kind == nkRange:
|
||||
# already semchecked
|
||||
if typ == nil:
|
||||
if doSetType:
|
||||
typ = skipTypes(n[i][0].typ,
|
||||
{tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink})
|
||||
if expectedElementType == nil:
|
||||
expectedElementType = typ
|
||||
else:
|
||||
n[i] = semExprWithType(c, n[i], {efTypeAllowed}, expectedElementType)
|
||||
if typ == nil:
|
||||
if doSetType:
|
||||
typ = skipTypes(n[i].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink})
|
||||
if expectedElementType == nil:
|
||||
expectedElementType = typ
|
||||
if not isOrdinalType(typ, allowEnumWithHoles=true):
|
||||
localError(c.config, n.info, errOrdinalTypeExpected % typeToString(typ, preferDesc))
|
||||
typ = makeRangeType(c, 0, MaxSetElements-1, n.info)
|
||||
elif lengthOrd(c.config, typ) > MaxSetElements:
|
||||
typ = makeRangeType(c, 0, MaxSetElements-1, n.info)
|
||||
if doSetType:
|
||||
if not isOrdinalType(typ, allowEnumWithHoles=true):
|
||||
localError(c.config, n.info, errOrdinalTypeExpected % typeToString(typ, preferDesc))
|
||||
typ = makeRangeType(c, 0, MaxSetElements-1, n.info)
|
||||
elif isIntLit(typ):
|
||||
# set of int literal, use a default range smaller than the max range
|
||||
typ = makeRangeType(c, 0, DefaultSetElements-1, n.info)
|
||||
elif lengthOrd(c.config, typ) > MaxSetElements:
|
||||
message(c.config, n.info, warnAboveMaxSizeSet, "type '" &
|
||||
typeToString(typ, preferDesc) & "' is too big to be a `set` element, " &
|
||||
"assuming a range of 0.." & $(MaxSetElements - 1) &
|
||||
", explicitly write this range to get rid of warning")
|
||||
typ = makeRangeType(c, 0, MaxSetElements-1, n.info)
|
||||
if expectedElementType == nil:
|
||||
expectedElementType = typ
|
||||
addSonSkipIntLit(result.typ, typ, c.idgen)
|
||||
for i in 0..<n.len:
|
||||
var m: PNode
|
||||
|
||||
@@ -1843,7 +1843,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
result = semTypeExpr(c, n, prev)
|
||||
else:
|
||||
let op = considerQuotedIdent(c, n[0])
|
||||
if op.id in {ord(wAnd), ord(wOr)} or op.s == "|":
|
||||
if op.id == ord(wAnd) or op.id == ord(wOr) or op.s == "|":
|
||||
checkSonsLen(n, 3, c.config)
|
||||
var
|
||||
t1 = semTypeNode(c, n[1], nil)
|
||||
|
||||
@@ -213,7 +213,7 @@ proc `$`*(suggest: Suggest): string =
|
||||
result.add(sep)
|
||||
when defined(nimsuggest) and not defined(noDocgen) and not defined(leanCompiler):
|
||||
result.add(suggest.doc.escape)
|
||||
if suggest.version in {0, 3}:
|
||||
if suggest.version == 0 or suggest.version == 3:
|
||||
result.add(sep)
|
||||
result.add($suggest.quality)
|
||||
if suggest.section == ideSug:
|
||||
|
||||
@@ -115,7 +115,8 @@ proc echoCode*(c: PCtx; start=0; last = -1) {.deprecated.} =
|
||||
codeListing(c, buf, start, last)
|
||||
echo buf
|
||||
|
||||
proc gABC(ctx: PCtx; n: PNode; opc: TOpcode; a, b, c: TRegister = 0) =
|
||||
proc gABC(ctx: PCtx; n: PNode; opc: TOpcode;
|
||||
a: TRegister = 0, b: TRegister = 0, c: TRegister = 0) =
|
||||
## Takes the registers `b` and `c`, applies the operation `opc` to them, and
|
||||
## stores the result into register `a`
|
||||
## The node is needed for debug information
|
||||
|
||||
@@ -5,10 +5,13 @@ only be an ordinal type of a certain size, namely:
|
||||
* `uint8`/`byte`-`uint16`
|
||||
* `char`
|
||||
* `enum`
|
||||
* Ordinal subrange types, i.e. `range[-10..10]`
|
||||
|
||||
or equivalent. For signed integers the set's base type is defined to be in the
|
||||
range `0 .. MaxSetElements-1` where `MaxSetElements` is currently always
|
||||
2^16.
|
||||
or equivalent. When constructing a set with signed integer literals, the set's
|
||||
base type is defined to be in the range `0 .. DefaultSetElements-1` where
|
||||
`DefaultSetElements` is currently always 2^8. The maximum range length for the
|
||||
base type of a set is `MaxSetElements` which is currently always 2^16. Types
|
||||
with a bigger range length are coerced into the range `0 .. MaxSetElements-1`.
|
||||
|
||||
The reason is that sets are implemented as high performance bit vectors.
|
||||
Attempting to declare a set with a larger type will result in an error:
|
||||
|
||||
@@ -348,20 +348,20 @@ func is1xx*(code: HttpCode): bool {.inline, since: (1, 5).} =
|
||||
runnableExamples:
|
||||
doAssert is1xx(HttpCode(103))
|
||||
|
||||
code.int in {100 .. 199}
|
||||
code.int in 100 .. 199
|
||||
|
||||
func is2xx*(code: HttpCode): bool {.inline.} =
|
||||
## Determines whether `code` is a 2xx HTTP status code.
|
||||
code.int in {200 .. 299}
|
||||
code.int in 200 .. 299
|
||||
|
||||
func is3xx*(code: HttpCode): bool {.inline.} =
|
||||
## Determines whether `code` is a 3xx HTTP status code.
|
||||
code.int in {300 .. 399}
|
||||
code.int in 300 .. 399
|
||||
|
||||
func is4xx*(code: HttpCode): bool {.inline.} =
|
||||
## Determines whether `code` is a 4xx HTTP status code.
|
||||
code.int in {400 .. 499}
|
||||
code.int in 400 .. 499
|
||||
|
||||
func is5xx*(code: HttpCode): bool {.inline.} =
|
||||
## Determines whether `code` is a 5xx HTTP status code.
|
||||
code.int in {500 .. 599}
|
||||
code.int in 500 .. 599
|
||||
|
||||
@@ -194,8 +194,8 @@ elif defined(linux) and not defined(nimNoGetRandom) and not defined(emscripten):
|
||||
elif readBytes > 0:
|
||||
inc(result, readBytes)
|
||||
else:
|
||||
if osLastError().int in {EINTR, EAGAIN}:
|
||||
discard
|
||||
case osLastError().int
|
||||
of EINTR, EAGAIN: discard
|
||||
else:
|
||||
result = -1
|
||||
break
|
||||
|
||||
@@ -26,9 +26,9 @@ func excl*[T](x: var set[T], y: T) {.magic: "Excl".} =
|
||||
##
|
||||
## This is the same as `x = x - {y}`, but it might be more efficient.
|
||||
runnableExamples:
|
||||
var b = {2, 3, 5, 6, 12, 545}
|
||||
var b = {2, 3, 5, 6, 12, 54}
|
||||
b.excl(5)
|
||||
assert b == {2, 3, 6, 12, 545}
|
||||
assert b == {2, 3, 6, 12, 54}
|
||||
|
||||
template excl*[T](x: var set[T], y: set[T]) {.callsite.} =
|
||||
## Excludes the set `y` from the set `x`.
|
||||
|
||||
10
tests/sets/thugeset.nim
Normal file
10
tests/sets/thugeset.nim
Normal file
@@ -0,0 +1,10 @@
|
||||
let x = 20_000
|
||||
let s = {x, 123} #[tt.Warning
|
||||
^ type 'int' is too big to be a `set` element, assuming a range of 0..65535, explicitly write this range to get rid of warning [AboveMaxSizeSet]]#
|
||||
doAssert x in s
|
||||
doAssert 20_000 in s
|
||||
{.push warningAsError[AboveMaxSizeSet]: on.}
|
||||
let s2 = {range[0..65535](x), 123}
|
||||
doAssert x in s
|
||||
doAssert 20_000 in s
|
||||
{.pop.}
|
||||
Reference in New Issue
Block a user