From 96bade5b2b8c48c58509be60c20fc01356bbcdb1 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 31 May 2020 14:19:23 +0200 Subject: [PATCH 01/15] I don't care about observable stores --- compiler/nim.cfg | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/nim.cfg b/compiler/nim.cfg index a77fa84d36ed0..8e733bdf81d14 100644 --- a/compiler/nim.cfg +++ b/compiler/nim.cfg @@ -21,3 +21,7 @@ define:useStdoutAsStdmsg #define:useNodeIds #gc:markAndSweep + +@if nimHasWarningObservableStores: + warning[ObservableStores]: off +@end From 02646f03ef494976e0c13725bb39785460583c39 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 31 May 2020 14:53:27 +0200 Subject: [PATCH 02/15] enforce explicit initializations --- compiler/lineinfos.nim | 4 ++-- compiler/sempass2.nim | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index bc3c51d539d0b..36353de377b4b 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -113,7 +113,7 @@ const warnStaticIndexCheck: "$1", warnGcUnsafe: "not GC-safe: '$1'", warnGcUnsafe2: "$1", - warnUninit: "'$1' might not have been initialized", + warnUninit: "use explicit initialization of '$1' for clarity", warnGcMem: "'$1' uses GC'ed memory", warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future.", warnLockLevel: "$1", @@ -211,7 +211,7 @@ type proc computeNotesVerbosity(): array[0..3, TNoteKinds] = result[3] = {low(TNoteKind)..high(TNoteKind)} - {} - result[2] = result[3] - {hintStackTrace, warnUninit, hintExtendedContext} + result[2] = result[3] - {hintStackTrace, hintExtendedContext} result[1] = result[2] - {warnProveField, warnProveIndex, warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd, hintSource, hintGlobalVar, hintGCStats, hintMsgOrigin} diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 862123eaba4b5..66c3c29cef9bf 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -66,7 +66,7 @@ type TEffects = object exc: PNode # stack of exceptions tags: PNode # list of tags - bottom, inTryStmt: int + bottom, inTryStmt, leftPartOfAsgn: int owner: PSym ownerModule: PSym init: seq[int] # list of initialized variables @@ -255,7 +255,7 @@ proc useVar(a: PEffects, n: PNode) = elif s.id notin a.init: if s.typ.requiresInit: message(a.config, n.info, warnProveInit, s.name.s) - else: + elif a.leftPartOfAsgn <= 0: message(a.config, n.info, warnUninit, s.name.s) # prevent superfluous warnings about the same variable: a.init.add s.id @@ -852,7 +852,9 @@ proc track(tracked: PEffects, n: PNode) = track(tracked, n[1]) initVar(tracked, n[0], volatileCheck=true) invalidateFacts(tracked.guards, n[0]) + inc tracked.leftPartOfAsgn track(tracked, n[0]) + dec tracked.leftPartOfAsgn addAsgnFact(tracked.guards, n[0], n[1]) notNilCheck(tracked, n[1], n[0].typ) when false: cstringCheck(tracked, n) @@ -1038,7 +1040,10 @@ proc track(tracked: PEffects, n: PNode) = if optStaticBoundsCheck in tracked.currOptions and n.len == 2: if n[0].typ != nil and skipTypes(n[0].typ, abstractVar).kind != tyTuple: checkBounds(tracked, n[0], n[1]) - for i in 0 ..< n.len: track(tracked, n[i]) + track(tracked, n[0]) + dec tracked.leftPartOfAsgn + for i in 1 ..< n.len: track(tracked, n[i]) + inc tracked.leftPartOfAsgn else: for i in 0.. Date: Sun, 31 May 2020 14:54:08 +0200 Subject: [PATCH 03/15] cleaner code for the stdlib --- lib/core/macros.nim | 7 ++++--- lib/pure/bitops.nim | 2 ++ lib/pure/parseutils.nim | 16 +++++++++++----- lib/pure/strutils.nim | 8 ++++++++ lib/pure/unicode.nim | 1 + lib/system.nim | 1 + lib/system/sets.nim | 1 + 7 files changed, 28 insertions(+), 8 deletions(-) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 9e17b665a4b64..0157d109f2285 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -533,9 +533,7 @@ proc copyLineInfo*(arg: NimNode, info: NimNode) {.magic: "NLineInfo", noSideEffe proc lineInfoObj*(n: NimNode): LineInfo {.compileTime.} = ## Returns ``LineInfo`` of ``n``, using absolute path for ``filename``. - result.filename = n.getFile - result.line = n.getLine - result.column = n.getColumn + result = LineInfo(filename: n.getFile, line: n.getLine, column: n.getColumn) proc lineInfo*(arg: NimNode): string {.compileTime.} = ## Return line info in the form `filepath(line, column)`. @@ -863,12 +861,14 @@ proc treeRepr*(n: NimNode): string {.compileTime, benign.} = ## Convert the AST `n` to a human-readable tree-like string. ## ## See also `repr`, `lispRepr`, and `astGenRepr`. + result = "" n.treeTraverse(result, isLisp = false, indented = true) proc lispRepr*(n: NimNode; indented = false): string {.compileTime, benign.} = ## Convert the AST ``n`` to a human-readable lisp-like string. ## ## See also ``repr``, ``treeRepr``, and ``astGenRepr``. + result = "" n.treeTraverse(result, isLisp = true, indented = indented) proc astGenRepr*(n: NimNode): string {.compileTime, benign.} = @@ -1605,6 +1605,7 @@ macro getCustomPragmaVal*(n: typed, cp: typed{nkSym}): untyped = ## assert(o.myField.getCustomPragmaVal(serializationKey) == "mf") ## assert(o.getCustomPragmaVal(serializationKey) == "mo") ## assert(MyObj.getCustomPragmaVal(serializationKey) == "mo") + result = nil let pragmaNode = customPragmaNode(n) for p in pragmaNode: if p.kind in nnkPragmaCallKinds and p.len > 0 and p[0].kind == nnkSym and p[0] == cp: diff --git a/lib/pure/bitops.nim b/lib/pure/bitops.nim index 7dd171a38c268..4f22388f36484 100644 --- a/lib/pure/bitops.nim +++ b/lib/pure/bitops.nim @@ -395,6 +395,8 @@ proc firstSetBitNim(x: uint64): int {.inline, noSideEffect.} = if k == 0: k = uint32(v shr 32'u32) and 0xFFFFFFFF'u32 result = 32 + else: + result = 0 result += firstSetBitNim(k) proc fastlog2Nim(x: uint32): int {.inline, noSideEffect.} = diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim index c185eca3736fe..1d17b0827298a 100644 --- a/lib/pure/parseutils.nim +++ b/lib/pure/parseutils.nim @@ -249,6 +249,7 @@ proc skipWhitespace*(s: string, start = 0): int {.inline.} = doAssert skipWhitespace(" Hello World", 0) == 1 doAssert skipWhitespace("Hello World", 5) == 1 doAssert skipWhitespace("Hello World", 5) == 2 + result = 0 while start+result < s.len and s[start+result] in Whitespace: inc(result) proc skip*(s, token: string, start = 0): int {.inline.} = @@ -260,6 +261,7 @@ proc skip*(s, token: string, start = 0): int {.inline.} = doAssert skip("2019-01-22", "19", 2) == 2 doAssert skip("CAPlow", "CAP", 0) == 3 doAssert skip("CAPlow", "cap", 0) == 0 + result = 0 while start+result < s.len and result < token.len and s[result+start] == token[result]: inc(result) @@ -270,6 +272,7 @@ proc skipIgnoreCase*(s, token: string, start = 0): int = runnableExamples: doAssert skipIgnoreCase("CAPlow", "CAP", 0) == 3 doAssert skipIgnoreCase("CAPlow", "cap", 0) == 3 + result = 0 while start+result < s.len and result < token.len and toLower(s[result+start]) == toLower(token[result]): inc(result) if result != token.len: result = 0 @@ -282,6 +285,7 @@ proc skipUntil*(s: string, until: set[char], start = 0): int {.inline.} = doAssert skipUntil("Hello World", {'W', 'e'}, 0) == 1 doAssert skipUntil("Hello World", {'W'}, 0) == 6 doAssert skipUntil("Hello World", {'W', 'd'}, 0) == 6 + result = 0 while start+result < s.len and s[result+start] notin until: inc(result) proc skipUntil*(s: string, until: char, start = 0): int {.inline.} = @@ -293,6 +297,7 @@ proc skipUntil*(s: string, until: char, start = 0): int {.inline.} = doAssert skipUntil("Hello World", 'o', 4) == 0 doAssert skipUntil("Hello World", 'W', 0) == 6 doAssert skipUntil("Hello World", 'w', 0) == 11 + result = 0 while start+result < s.len and s[result+start] != until: inc(result) proc skipWhile*(s: string, toSkip: set[char], start = 0): int {.inline.} = @@ -302,6 +307,7 @@ proc skipWhile*(s: string, toSkip: set[char], start = 0): int {.inline.} = doAssert skipWhile("Hello World", {'H', 'e'}) == 2 doAssert skipWhile("Hello World", {'e'}) == 0 doAssert skipWhile("Hello World", {'W', 'o', 'r'}, 6) == 3 + result = 0 while start+result < s.len and s[result+start] in toSkip: inc(result) proc parseUntil*(s: string, token: var string, until: set[char], @@ -437,7 +443,7 @@ proc parseBiggestInt*(s: string, number: var BiggestInt, start = 0): int {. var res: BiggestInt doAssert parseBiggestInt("9223372036854775807", res, 0) == 19 doAssert res == 9223372036854775807 - var res: BiggestInt + var res = BiggestInt(0) # use 'res' for exception safety (don't write to 'number' in case of an # overflow exception): result = rawParseInt(s, res, start) @@ -455,7 +461,7 @@ proc parseInt*(s: string, number: var int, start = 0): int {. doAssert res == 2019 doAssert parseInt("2019", res, 2) == 2 doAssert res == 19 - var res: BiggestInt + var res = BiggestInt(0) result = parseBiggestInt(s, res, start) when sizeof(int) <= 4: if res < low(int) or res > high(int): @@ -518,7 +524,7 @@ proc parseBiggestUInt*(s: string, number: var BiggestUInt, start = 0): int {. doAssert res == 12 doAssert parseBiggestUInt("1111111111111111111", res, 0) == 19 doAssert res == 1111111111111111111'u64 - var res: BiggestUInt + var res = BiggestUInt(0) # use 'res' for exception safety (don't write to 'number' in case of an # overflow exception): result = rawParseUInt(s, res, start) @@ -536,7 +542,7 @@ proc parseUInt*(s: string, number: var uint, start = 0): int {. doAssert res == 3450 doAssert parseUInt("3450", res, 2) == 2 doAssert res == 50 - var res: BiggestUInt + var res = BiggestUInt(0) result = parseBiggestUInt(s, res, start) when sizeof(BiggestUInt) > sizeof(uint) and sizeof(uint) <= 4: if res > 0xFFFF_FFFF'u64: @@ -563,7 +569,7 @@ proc parseFloat*(s: string, number: var float, start = 0): int {. doAssert res == 32.57 doAssert parseFloat("32.57", res, 3) == 2 doAssert res == 57.00 - var bf: BiggestFloat + var bf = BiggestFloat(0.0) result = parseBiggestFloat(s, bf, start) if result != 0: number = bf diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 7c00de2d29e2d..12f8254b11692 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -1103,6 +1103,7 @@ proc parseInt*(s: string): int {.noSideEffect, ## If `s` is not a valid integer, `ValueError` is raised. runnableExamples: doAssert parseInt("-0042") == -42 + result = 0 let L = parseutils.parseInt(s, result, 0) if L != s.len or L == 0: raise newException(ValueError, "invalid integer: " & s) @@ -1112,6 +1113,7 @@ proc parseBiggestInt*(s: string): BiggestInt {.noSideEffect, ## Parses a decimal integer value contained in `s`. ## ## If `s` is not a valid integer, `ValueError` is raised. + result = BiggestInt(0) let L = parseutils.parseBiggestInt(s, result, 0) if L != s.len or L == 0: raise newException(ValueError, "invalid integer: " & s) @@ -1121,6 +1123,7 @@ proc parseUInt*(s: string): uint {.noSideEffect, ## Parses a decimal unsigned integer value contained in `s`. ## ## If `s` is not a valid integer, `ValueError` is raised. + result = uint(0) let L = parseutils.parseUInt(s, result, 0) if L != s.len or L == 0: raise newException(ValueError, "invalid unsigned integer: " & s) @@ -1130,6 +1133,7 @@ proc parseBiggestUInt*(s: string): BiggestUInt {.noSideEffect, ## Parses a decimal unsigned integer value contained in `s`. ## ## If `s` is not a valid integer, `ValueError` is raised. + result = BiggestUInt(0) let L = parseutils.parseBiggestUInt(s, result, 0) if L != s.len or L == 0: raise newException(ValueError, "invalid unsigned integer: " & s) @@ -1143,6 +1147,7 @@ proc parseFloat*(s: string): float {.noSideEffect, runnableExamples: doAssert parseFloat("3.14") == 3.14 doAssert parseFloat("inf") == 1.0/0 + result = 0.0 let L = parseutils.parseFloat(s, result, 0) if L != s.len or L == 0: raise newException(ValueError, "invalid float: " & s) @@ -1161,6 +1166,7 @@ proc parseBinInt*(s: string): int {.noSideEffect, doAssert a.parseBinInt() == 53 doAssert b.parseBinInt() == 7 + result = 0 let L = parseutils.parseBin(s, result, 0) if L != s.len or L == 0: raise newException(ValueError, "invalid binary integer: " & s) @@ -1172,6 +1178,7 @@ proc parseOctInt*(s: string): int {.noSideEffect, ## If `s` is not a valid oct integer, `ValueError` is raised. `s` can have one ## of the following optional prefixes: ``0o``, ``0O``. Underscores within ## `s` are ignored. + result = 0 let L = parseutils.parseOct(s, result, 0) if L != s.len or L == 0: raise newException(ValueError, "invalid oct integer: " & s) @@ -1183,6 +1190,7 @@ proc parseHexInt*(s: string): int {.noSideEffect, ## If `s` is not a valid hex integer, `ValueError` is raised. `s` can have one ## of the following optional prefixes: ``0x``, ``0X``, ``#``. Underscores ## within `s` are ignored. + result = 0 let L = parseutils.parseHex(s, result, 0) if L != s.len or L == 0: raise newException(ValueError, "invalid hex integer: " & s) diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim index 497d5e465a0c3..8225ed0349b25 100644 --- a/lib/pure/unicode.nim +++ b/lib/pure/unicode.nim @@ -39,6 +39,7 @@ proc runeLen*(s: string): int {.rtl, extern: "nuc$1".} = doAssert a.runeLen == 6 ## note: a.len == 8 + result = 0 var i = 0 while i < len(s): if uint(s[i]) <= 127: inc(i) diff --git a/lib/system.nim b/lib/system.nim index 85be43cbac43b..447a42784b2dd 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1768,6 +1768,7 @@ export iterators proc find*[T, S](a: T, item: S): int {.inline.}= ## Returns the first index of `item` in `a` or -1 if not found. This requires ## appropriate `items` and `==` operations to work. + result = 0 for i in items(a): if i == item: return inc(result) diff --git a/lib/system/sets.nim b/lib/system/sets.nim index 0df50957da71d..42c4488486490 100644 --- a/lib/system/sets.nim +++ b/lib/system/sets.nim @@ -31,6 +31,7 @@ proc countBits64(n: uint64): int {.compilerproc, inline.} = proc cardSet(s: NimSet, len: int): int {.compilerproc, inline.} = var i = 0 + result = 0 when defined(x86) or defined(amd64): while i < len - 8: inc(result, countBits64((cast[ptr uint64](s[i].unsafeAddr))[])) From 52de22e0edbdb79c9acd24760a773db77ff8eb02 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 31 May 2020 15:48:57 +0200 Subject: [PATCH 04/15] stdlib: use explicit initializations --- lib/pure/os.nim | 5 +++-- lib/pure/pathnorm.nim | 2 +- lib/pure/strutils.nim | 14 +++++++++----- lib/pure/times.nim | 18 ++++++++++-------- lib/pure/typetraits.nim | 2 +- 5 files changed, 24 insertions(+), 17 deletions(-) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index fbd722863eb05..6472d5497bbae 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -409,7 +409,8 @@ proc relativePath*(path, base: string, sep = DirSep): string {. if not sameRoot(path, base): return path - var f, b: PathIter + var f = default PathIter + var b = default PathIter var ff = (0, -1) var bb = (0, -1) # (int, int) result = newStringOfCap(path.len) @@ -2976,7 +2977,7 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect], noN setLen(result, L) break elif defined(macosx): - var size: cuint32 + var size = cuint32(0) getExecPath1(nil, size) result = newString(int(size)) if getExecPath2(result, size): diff --git a/lib/pure/pathnorm.nim b/lib/pure/pathnorm.nim index 8763ba8780eb0..03a65bd609485 100644 --- a/lib/pure/pathnorm.nim +++ b/lib/pure/pathnorm.nim @@ -44,7 +44,7 @@ proc next*(it: var PathIter; x: string): (int, int) = it.notFirst = true iterator dirs(x: string): (int, int) = - var it: PathIter + var it = default PathIter while hasNext(it, x): yield next(it, x) proc isDot(x: string; bounds: (int, int)): bool = diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 12f8254b11692..1ffc8bf227bf4 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -1278,9 +1278,9 @@ macro genEnumStmt(typ: typedesc, argSym: typed, default: typed): untyped = result = nnkCaseStmt.newTree(nnkDotExpr.newTree(argSym, bindSym"nimIdentNormalize")) # stores all processed field strings to give error msg for ambiguous enums - var foundFields: seq[string] - var fStr: string # string of current field - var fNum: BiggestInt # int value of current field + var foundFields: seq[string] = @[] + var fStr = "" # string of current field + var fNum = BiggestInt(0) # int value of current field for f in impl: case f.kind of nnkEmpty: continue # skip first node of `enumTy` @@ -2036,6 +2036,7 @@ proc rfind*(s, sub: string, start: Natural = 0, last = -1): int {.noSideEffect, if sub.len == 0: return -1 let last = if last == -1: s.high else: last + result = 0 for i in countdown(last - sub.len + 1, start): for j in 0..sub.len-1: result = i @@ -2052,6 +2053,7 @@ proc count*(s: string, sub: char): int {.noSideEffect, ## ## See also: ## * `countLines proc<#countLines,string>`_ + result = 0 for c in s: if c == sub: inc result @@ -2062,6 +2064,7 @@ proc count*(s: string, subs: set[char]): int {.noSideEffect, ## See also: ## * `countLines proc<#countLines,string>`_ doAssert card(subs) > 0 + result = 0 for c in s: if c in subs: inc result @@ -2074,6 +2077,7 @@ proc count*(s: string, sub: string, overlapping: bool = false): int {. ## See also: ## * `countLines proc<#countLines,string>`_ doAssert sub.len > 0 + result = 0 var i = 0 while true: i = s.find(sub, i) @@ -2321,7 +2325,7 @@ proc unescape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect, case s[i+1]: of 'x': inc i, 2 - var c: int + var c = 0 i += parseutils.parseHex(s, c, i, maxLen = 2) result.add(chr(c)) dec i, 2 @@ -2522,7 +2526,7 @@ proc formatSize*(bytes: int64, xb: int64 = bytes fbytes: float lastXb: int64 = bytes - matchedIndex: int + matchedIndex = 0 prefixes: array[9, string] if prefix == bpColloquial: prefixes = collPrefixes diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 1fff3d99bf53c..00cf2cd5ad54c 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -895,16 +895,16 @@ proc getTime*(): Time {.tags: [TimeEffect], benign.} = millis mod convert(Seconds, Milliseconds, 1).int) result = initTime(seconds, nanos) elif defined(macosx): - var a: Timeval + var a {.noinit.}: Timeval gettimeofday(a) result = initTime(a.tv_sec.int64, convert(Microseconds, Nanoseconds, a.tv_usec.int)) elif defined(posix): - var ts: Timespec + var ts {.noinit.}: Timespec discard clock_gettime(CLOCK_REALTIME, ts) result = initTime(ts.tv_sec.int64, ts.tv_nsec.int) elif defined(windows): - var f: FILETIME + var f {.noinit.}: FILETIME getSystemTimeAsFileTime(f) result = fromWinTime(rdFileTime(f)) @@ -1765,7 +1765,7 @@ proc formatPattern(dt: DateTime, pattern: FormatPattern, result: var string, proc parsePattern(input: string, pattern: FormatPattern, i: var int, parsed: var ParsedTime, loc: DateTimeLocale): bool = template takeInt(allowedWidth: Slice[int], allowSign = false): int = - var sv: int + var sv = 0 var pd = parseInt(input, sv, i, allowedWidth.b, allowSign) if pd < allowedWidth.a: return false @@ -1998,6 +1998,7 @@ proc format*(dt: DateTime, f: TimeFormat, let dt = initDateTime(01, mJan, 2000, 00, 00, 00, utc()) doAssert "2000-01-01" == dt.format(f) assertDateTimeInitialized dt + result = "" var idx = 0 while idx <= f.patterns.high: case f.patterns[idx].FormatPattern @@ -2295,7 +2296,7 @@ proc between*(startDt, endDt: DateTime): TimeInterval = endDate.monthday.dec # Years - result.years.inc endDate.year - startDate.year - 1 + result.years = endDate.year - startDate.year - 1 if (startDate.month, startDate.monthday) <= (endDate.month, endDate.monthday): result.years.inc startDate.year.inc result.years @@ -2452,6 +2453,7 @@ proc evaluateInterval(dt: DateTime, interval: TimeInterval): var months = interval.years * 12 + interval.months var curYear = dt.year var curMonth = dt.month + result = default(tuple[adjDur, absDur: Duration]) # Subtracting if months < 0: for mth in countdown(-1 * months, 1): @@ -2573,17 +2575,17 @@ proc epochTime*(): float {.tags: [TimeEffect].} = ## ## ``getTime`` should generally be preferred over this proc. when defined(macosx): - var a: Timeval + var a {.noinit.}: Timeval gettimeofday(a) result = toBiggestFloat(a.tv_sec.int64) + toBiggestFloat( a.tv_usec)*0.00_0001 elif defined(posix): - var ts: Timespec + var ts {.noinit.}: Timespec discard clock_gettime(CLOCK_REALTIME, ts) result = toBiggestFloat(ts.tv_sec.int64) + toBiggestFloat(ts.tv_nsec.int64) / 1_000_000_000 elif defined(windows): - var f: winlean.FILETIME + var f {.noinit.}: winlean.FILETIME getSystemTimeAsFileTime(f) var i64 = rdFileTime(f) - epochDiff var secs = i64 div rateDiff diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim index 9a215a35312ae..317376405cef1 100644 --- a/lib/pure/typetraits.nim +++ b/lib/pure/typetraits.nim @@ -112,7 +112,7 @@ macro genericParamsImpl(T: typedesc): untyped = of nnkBracketExpr: for i in 1.. Date: Sun, 31 May 2020 18:08:28 +0200 Subject: [PATCH 05/15] first implementation of 'out' parameters --- compiler/ast.nim | 23 +++++++------- compiler/ccgcalls.nim | 14 ++++----- compiler/ccgexprs.nim | 46 ++++++++++++++-------------- compiler/ccgreset.nim | 2 +- compiler/ccgtypes.nim | 18 +++++------ compiler/cgmeth.nim | 2 +- compiler/dfa.nim | 9 ++---- compiler/evalffi.nim | 10 +++--- compiler/guards.nim | 2 +- compiler/jsgen.nim | 22 ++++++------- compiler/jstypes.nim | 2 +- compiler/lambdalifting.nim | 2 +- compiler/liftdestructors.nim | 6 ++-- compiler/lowerings.nim | 6 ++-- compiler/parampatterns.nim | 14 ++++----- compiler/renderer.nim | 4 +-- compiler/semcall.nim | 4 +-- compiler/semdata.nim | 4 +-- compiler/semexprs.nim | 46 ++++++++++++++-------------- compiler/semmagic.nim | 6 ++-- compiler/semobjconstr.nim | 2 +- compiler/sempass2.nim | 5 +-- compiler/semstmts.nim | 38 +++++++++-------------- compiler/semtypes.nim | 8 ++--- compiler/semtypinst.nim | 4 +-- compiler/sighashes.nim | 2 +- compiler/sigmatch.nim | 32 +++++++++---------- compiler/sinkparameter_inference.nim | 2 +- compiler/sizealignoffsetimpl.nim | 2 +- compiler/spawn.nim | 8 ++--- compiler/suggest.nim | 6 ++-- compiler/transf.nim | 16 +++++----- compiler/types.nim | 37 ++++++++++------------ compiler/vmdeps.nim | 2 +- compiler/vmgen.nim | 8 ++--- compiler/writetracking.nim | 6 ++-- 36 files changed, 202 insertions(+), 218 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index d13487e9cfc1a..4d2b2faeff8b3 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -433,8 +433,9 @@ type # instantiation and prior to this it has the potential to # be any type. - tyOpt - # Builtin optional type + tyOut + # 'out' parameter. Comparable to a 'var' parameter but every + # path must assign a value to it before it can be read from. tyVoid # now different from tyEmpty, hurray! @@ -458,7 +459,7 @@ const tyMetaTypes* = {tyGenericParam, tyTypeDesc, tyUntyped} + tyTypeClasses tyUserTypeClasses* = {tyUserTypeClass, tyUserTypeClassInst} # consider renaming as `tyAbstractVarRange` - abstractVarRange* = {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal, + abstractVarRange* = {tyGenericInst, tyRange, tyVar, tyOut, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias, tyInferred, tySink, tyOwned} type @@ -657,7 +658,7 @@ type mNewString, mNewStringOfCap, mParseBiggestFloat, mMove, mWasMoved, mDestroy, mDefault, mUnown, mAccessEnv, mReset, - mArray, mOpenArray, mRange, mSet, mSeq, mOpt, mVarargs, + mArray, mOpenArray, mRange, mSet, mSeq, mOut, mVarargs, mRef, mPtr, mVar, mDistinct, mVoid, mTuple, mOrdinal, mInt, mInt8, mInt16, mInt32, mInt64, @@ -983,13 +984,13 @@ const tyGenericParam} StructuralEquivTypes*: TTypeKinds = {tyNil, tyTuple, tyArray, - tySet, tyRange, tyPtr, tyRef, tyVar, tyLent, tySequence, tyProc, tyOpenArray, + tySet, tyRange, tyPtr, tyRef, tyVar, tyOut, tyLent, tySequence, tyProc, tyOpenArray, tyVarargs} ConcreteTypes*: TTypeKinds = { # types of the expr that may occur in:: # var x = expr tyBool, tyChar, tyEnum, tyArray, tyObject, - tySet, tyTuple, tyRange, tyPtr, tyRef, tyVar, tyLent, tySequence, tyProc, + tySet, tyTuple, tyRange, tyPtr, tyRef, tyVar, tyOut, tyLent, tySequence, tyProc, tyPointer, tyOpenArray, tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128, tyUInt..tyUInt64} @@ -1491,7 +1492,7 @@ proc isGCedMem*(t: PType): bool {.inline.} = t.kind == tyProc and t.callConv == ccClosure proc propagateToOwner*(owner, elem: PType; propagateHasAsgn = true) = - const HaveTheirOwnEmpty = {tySequence, tyOpt, tySet, tyPtr, tyRef, tyProc} + const HaveTheirOwnEmpty = {tySequence, tySet, tyPtr, tyRef, tyProc} owner.flags = owner.flags + (elem.flags * {tfHasMeta, tfTriggersCompileTime}) if tfNotNil in elem.flags: if owner.kind in {tyGenericInst, tyGenericBody, tyGenericInvocation}: @@ -1504,7 +1505,7 @@ proc propagateToOwner*(owner, elem: PType; propagateHasAsgn = true) = if mask != {} and propagateHasAsgn: let o2 = owner.skipTypes({tyGenericInst, tyAlias, tySink}) if o2.kind in {tyTuple, tyObject, tyArray, - tySequence, tyOpt, tySet, tyDistinct, tyOpenArray, tyVarargs}: + tySequence, tySet, tyDistinct, tyOpenArray, tyVarargs}: o2.flags.incl mask owner.flags.incl mask @@ -1801,12 +1802,12 @@ proc skipStmtList*(n: PNode): PNode = else: result = n -proc toVar*(typ: PType): PType = +proc toVar*(typ: PType; kind: TTypeKind): PType = ## If ``typ`` is not a tyVar then it is converted into a `var ` and ## returned. Otherwise ``typ`` is simply returned as-is. result = typ - if typ.kind != tyVar: - result = newType(tyVar, typ.owner) + if typ.kind != kind: + result = newType(kind, typ.owner) rawAddSon(result, typ) proc toRef*(typ: PType): PType = diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index e19e96503f732..cca4d84e7d5b7 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -170,10 +170,10 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope = result = "($4*)($1)+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dest] of tyString, tySequence: let atyp = skipTypes(a.t, abstractInst) - if formalType.skipTypes(abstractInst).kind == tyVar and atyp.kind == tyString and + if formalType.skipTypes(abstractInst).kind in {tyVar, tyOut} and atyp.kind == tyString and optSeqDestructors in p.config.globalOptions: linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)]) - if atyp.kind == tyVar and not compileToCpp(p.module): + if atyp.kind in {tyVar, tyOut} and not compileToCpp(p.module): result = "($5*)(*$1)$4+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dataField(p), dest] else: result = "($5*)$1$4+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dataField(p), dest] @@ -186,10 +186,10 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope = result = "$1, $1Len_0" % [rdLoc(a)] of tyString, tySequence: let ntyp = skipTypes(n.typ, abstractInst) - if formalType.skipTypes(abstractInst).kind == tyVar and ntyp.kind == tyString and + if formalType.skipTypes(abstractInst).kind in {tyVar, tyOut} and ntyp.kind == tyString and optSeqDestructors in p.config.globalOptions: linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)]) - if ntyp.kind == tyVar and not compileToCpp(p.module): + if ntyp.kind in {tyVar, tyOut} and not compileToCpp(p.module): var t: TLoc t.r = "(*$1)" % [a.rdLoc] result = "(*$1)$3, $2" % [a.rdLoc, lenExpr(p, t), dataField(p)] @@ -224,7 +224,7 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): Rope = elif ccgIntroducedPtr(p.config, param, call[0].typ[0]): initLocExpr(p, n, a) result = addrLoc(p.config, a) - elif p.module.compileToCpp and param.typ.kind == tyVar and + elif p.module.compileToCpp and param.typ.kind in {tyVar, tyOut} and n.kind == nkHiddenAddr: initLocExprSingleUse(p, n[0], a) # if the proc is 'importc'ed but not 'importcpp'ed then 'var T' still @@ -364,7 +364,7 @@ proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope = assert(paramType.kind == nkSym) if paramType.typ.isCompileTimeOnly: result = nil - elif typ[i].kind == tyVar and ri[i].kind == nkHiddenAddr: + elif typ[i].kind in {tyVar, tyOut} and ri[i].kind == nkHiddenAddr: result = genArgNoParam(p, ri[i][0]) else: result = genArgNoParam(p, ri[i]) #, typ.n[i].sym) @@ -441,7 +441,7 @@ proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): Rope = var ri = ri[i] while ri.kind == nkObjDownConv: ri = ri[0] let t = typ[i].skipTypes({tyGenericInst, tyAlias, tySink}) - if t.kind == tyVar: + if t.kind in {tyVar, tyOut}: let x = if ri.kind == nkHiddenAddr: ri[0] else: ri if x.typ.kind == tyPtr: result = genArgNoParam(p, x) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index ec54081a23e30..76944f6a552d2 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -155,7 +155,7 @@ proc getStorageLoc(n: PNode): TStorageLoc = else: result = OnUnknown of nkDerefExpr, nkHiddenDeref: case n[0].typ.kind - of tyVar, tyLent: result = OnUnknown + of tyVar, tyLent, tyOut: result = OnUnknown of tyPtr: result = OnStack of tyRef: result = OnHeap else: doAssert(false, "getStorageLoc") @@ -367,7 +367,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = else: linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) of tyPtr, tyPointer, tyChar, tyBool, tyEnum, tyCString, - tyInt..tyUInt64, tyRange, tyVar, tyLent, tyNil: + tyInt..tyUInt64, tyRange, tyVar, tyOut, tyLent, tyNil: linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) else: internalError(p.config, "genAssignment: " & $ty.kind) @@ -412,7 +412,7 @@ proc genDeepCopy(p: BProc; dest, src: TLoc) = else: linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) of tyPointer, tyChar, tyBool, tyEnum, tyCString, - tyInt..tyUInt64, tyRange, tyVar, tyLent: + tyInt..tyUInt64, tyRange, tyVar, tyOut, tyLent: linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) else: internalError(p.config, "genDeepCopy: " & $ty.kind) @@ -675,7 +675,7 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) = proc isCppRef(p: BProc; typ: PType): bool {.inline.} = result = p.module.compileToCpp and - skipTypes(typ, abstractInstOwned).kind == tyVar and + skipTypes(typ, abstractInstOwned).kind in {tyVar, tyOut} and tfVarIsPtr notin skipTypes(typ, abstractInstOwned).flags proc genDeref(p: BProc, e: PNode, d: var TLoc) = @@ -692,7 +692,7 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) = if typ.kind in {tyUserTypeClass, tyUserTypeClassInst} and typ.isResolvedUserTypeClass: typ = typ.lastSon typ = typ.skipTypes(abstractInstOwned) - if typ.kind == tyVar and tfVarIsPtr notin typ.flags and p.module.compileToCpp and e[0].kind == nkHiddenAddr: + if typ.kind in {tyVar, tyOut} and tfVarIsPtr notin typ.flags and p.module.compileToCpp and e[0].kind == nkHiddenAddr: initLocExprSingleUse(p, e[0][0], d) return else: @@ -704,7 +704,7 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) = case typ.kind of tyRef: d.storage = OnHeap - of tyVar, tyLent: + of tyVar, tyOut, tyLent: d.storage = OnUnknown if tfVarIsPtr notin typ.flags and p.module.compileToCpp and e.kind == nkHiddenDeref: @@ -715,7 +715,7 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) = else: internalError(p.config, e.info, "genDeref " & $typ.kind) elif p.module.compileToCpp: - if typ.kind == tyVar and tfVarIsPtr notin typ.flags and + if typ.kind in {tyVar, tyOut} and tfVarIsPtr notin typ.flags and e.kind == nkHiddenDeref: putIntoDest(p, d, e, rdLoc(a), a.storage) return @@ -757,7 +757,7 @@ proc genTupleElem(p: BProc, e: PNode, d: var TLoc) = a: TLoc i: int initLocExpr(p, e[0], a) - let tupType = a.t.skipTypes(abstractInst+{tyVar}) + let tupType = a.t.skipTypes(abstractInst+{tyVar, tyOut}) assert tupType.kind == tyTuple d.inheritLocation(a) discard getTypeDesc(p.module, a.t) # fill the record's fields.loc @@ -1167,7 +1167,7 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = var a, b, dest, tmpL, call: TLoc initLocExpr(p, e[1], a) initLocExpr(p, e[2], b) - let seqType = skipTypes(e[1].typ, {tyVar}) + let seqType = skipTypes(e[1].typ, {tyVar, tyOut}) initLoc(call, locCall, e, OnHeap) if not p.module.compileToCpp: const seqAppendPattern = "($2) #incrSeqV3((TGenericSeq*)($1), $3)" @@ -1198,7 +1198,7 @@ proc genReset(p: BProc, n: PNode) = when false: linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n", [addrLoc(p.config, a), - genTypeInfo(p.module, skipTypes(a.t, {tyVar}), n.info)]) + genTypeInfo(p.module, skipTypes(a.t, {tyVar, tyOut}), n.info)]) proc genDefault(p: BProc; n: PNode; d: var TLoc) = if d.k == locNone: getTemp(p, n.typ, d, needsInit=true) @@ -1536,9 +1536,9 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) = var r = rdLoc(a) var nilCheck: Rope = nil var t = skipTypes(a.t, abstractInstOwned) - while t.kind in {tyVar, tyLent, tyPtr, tyRef}: - if t.kind notin {tyVar, tyLent}: nilCheck = r - if t.kind notin {tyVar, tyLent} or not p.module.compileToCpp: + while t.kind in {tyVar, tyOut, tyLent, tyPtr, tyRef}: + if t.kind notin {tyVar, tyOut, tyLent}: nilCheck = r + if t.kind notin {tyVar, tyOut, tyLent} or not p.module.compileToCpp: r = ropecg(p.module, "(*$1)", [r]) t = skipTypes(t.lastSon, typedescInst+{tyOwned}) discard getTypeDesc(p.module, t) @@ -1613,9 +1613,9 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) = proc rdMType(p: BProc; a: TLoc; nilCheck: var Rope): Rope = result = rdLoc(a) var t = skipTypes(a.t, abstractInst) - while t.kind in {tyVar, tyLent, tyPtr, tyRef}: - if t.kind notin {tyVar, tyLent}: nilCheck = result - if t.kind notin {tyVar, tyLent} or not p.module.compileToCpp: + while t.kind in {tyVar, tyOut, tyLent, tyPtr, tyRef}: + if t.kind notin {tyVar, tyOut, tyLent}: nilCheck = result + if t.kind notin {tyVar, tyOut, tyLent} or not p.module.compileToCpp: result = "(*$1)" % [result] t = skipTypes(t.lastSon, abstractInst) discard getTypeDesc(p.module, t) @@ -1712,7 +1712,7 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) = if x.kind in {nkAddr, nkHiddenAddr}: x = x[0] initLocExpr(p, x, a) initLocExpr(p, e[2], b) - let t = skipTypes(e[1].typ, {tyVar}) + let t = skipTypes(e[1].typ, {tyVar, tyOut}) initLoc(call, locCall, e, OnHeap) if not p.module.compileToCpp: @@ -2006,7 +2006,7 @@ proc genRangeChck(p: BProc, n: PNode, d: var TLoc) = [getTypeDesc(p.module, dest), rdCharLoc(a)], a.storage) proc genConv(p: BProc, e: PNode, d: var TLoc) = - let destType = e.typ.skipTypes({tyVar, tyLent, tyGenericInst, tyAlias, tySink}) + let destType = e.typ.skipTypes({tyVar, tyOut, tyLent, tyGenericInst, tyAlias, tySink}) if sameBackendType(destType, e[1].typ): expr(p, e[1], d) else: @@ -2160,7 +2160,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = const opr: array[mInc..mDec, string] = ["+=", "-="] const fun64: array[mInc..mDec, string] = ["nimAddInt64", "nimSubInt64"] const fun: array[mInc..mDec, string] = ["nimAddInt","nimSubInt"] - let underlying = skipTypes(e[1].typ, {tyGenericInst, tyAlias, tySink, tyVar, tyLent, tyRange, tyDistinct}) + let underlying = skipTypes(e[1].typ, {tyGenericInst, tyAlias, tySink, tyVar, tyOut, tyLent, tyRange, tyDistinct}) if optOverflowCheck notin p.options or underlying.kind in {tyUInt..tyUInt64}: binaryStmt(p, e, d, opr[op]) else: @@ -2170,7 +2170,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = initLocExpr(p, e[1], a) initLocExpr(p, e[2], b) - let ranged = skipTypes(e[1].typ, {tyGenericInst, tyAlias, tySink, tyVar, tyLent}) + let ranged = skipTypes(e[1].typ, {tyGenericInst, tyAlias, tySink, tyVar, tyOut, tyLent}) let res = binaryArithOverflowRaw(p, ranged, a, b, if underlying.kind == tyInt64: fun64[op] else: fun[op]) @@ -2497,7 +2497,7 @@ proc downConv(p: BProc, n: PNode, d: var TLoc) = var a: TLoc initLocExpr(p, arg, a) var r = rdLoc(a) - let isRef = skipTypes(arg.typ, abstractInstOwned).kind in {tyRef, tyPtr, tyVar, tyLent} + let isRef = skipTypes(arg.typ, abstractInstOwned).kind in {tyRef, tyPtr, tyVar, tyOut, tyLent} if isRef: r.add("->Sup") else: @@ -2509,7 +2509,7 @@ proc downConv(p: BProc, n: PNode, d: var TLoc) = # (see bug #837). However sometimes using a temporary is not correct: # init(TFigure(my)) # where it is passed to a 'var TFigure'. We test # this by ensuring the destination is also a pointer: - if d.k == locNone and skipTypes(n.typ, abstractInstOwned).kind in {tyRef, tyPtr, tyVar, tyLent}: + if d.k == locNone and skipTypes(n.typ, abstractInstOwned).kind in {tyRef, tyPtr, tyVar, tyOut, tyLent}: getTemp(p, n.typ, d) linefmt(p, cpsStmts, "$1 = &$2;$n", [rdLoc(d), r]) else: @@ -2758,7 +2758,7 @@ proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo): Rope = of tyBool: result = rope"NIM_FALSE" of tyEnum, tyChar, tyInt..tyInt64, tyUInt..tyUInt64: result = rope"0" of tyFloat..tyFloat128: result = rope"0.0" - of tyCString, tyVar, tyLent, tyPointer, tyPtr, tyUntyped, + of tyCString, tyVar, tyOut, tyLent, tyPointer, tyPtr, tyUntyped, tyTyped, tyTypeDesc, tyStatic, tyRef, tyNil: result = rope"NIM_NIL" of tyString, tySequence: diff --git a/compiler/ccgreset.nim b/compiler/ccgreset.nim index ef1505f5799d8..644c0985f10f0 100644 --- a/compiler/ccgreset.nim +++ b/compiler/ccgreset.nim @@ -85,7 +85,7 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) = lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [accessor]) of tyChar, tyBool, tyEnum, tyInt..tyUInt64: lineCg(p, cpsStmts, "$1 = 0;$n", [accessor]) - of tyCString, tyPointer, tyPtr, tyVar, tyLent: + of tyCString, tyPointer, tyPtr, tyVar, tyOut, tyLent: lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [accessor]) else: discard diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 96b59cd6020a9..4111c7c8add66 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -176,7 +176,7 @@ proc mapType(conf: ConfigRef; typ: PType): TCTypeKind = of 8: result = ctInt64 else: result = ctInt32 of tyRange: result = mapType(conf, typ[0]) - of tyPtr, tyVar, tyLent, tyRef: + of tyPtr, tyVar, tyOut, tyLent, tyRef: var base = skipTypes(typ.lastSon, typedescInst) case base.kind of tyOpenArray, tyArray, tyVarargs, tyUncheckedArray: result = ctPtrToArray @@ -225,7 +225,7 @@ proc isInvalidReturnType(conf: ConfigRef; rettype: PType): bool = case mapType(conf, rettype) of ctArray: result = not (skipTypes(rettype, typedescInst).kind in - {tyVar, tyLent, tyRef, tyPtr}) + {tyVar, tyOut, tyLent, tyRef, tyPtr}) of ctStruct: let t = skipTypes(rettype, typedescInst) if rettype.isImportedCppType or t.isImportedCppType: return false @@ -368,7 +368,7 @@ proc getTypeForward(m: BModule, typ: PType; sig: SigHash): Rope = if result != nil: return result = getTypePre(m, typ, sig) if result != nil: return - let concrete = typ.skipTypes(abstractInst + {tyOpt}) + let concrete = typ.skipTypes(abstractInst) case concrete.kind of tySequence, tyTuple, tyObject: result = getTypeName(m, typ, sig) @@ -441,7 +441,7 @@ $3endif$N """, [getTypeDescAux(m, t.skipTypes(abstractInst)[0], check), result, rope"#"]) proc paramStorageLoc(param: PSym): TStorageLoc = - if param.typ.skipTypes({tyVar, tyLent, tyTypeDesc}).kind notin { + if param.typ.skipTypes({tyVar, tyOut, tyLent, tyTypeDesc}).kind notin { tyArray, tyOpenArray, tyVarargs}: result = OnStack else: @@ -475,11 +475,11 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope, params.add(param.loc.r) # declare the len field for open arrays: var arr = param.typ - if arr.kind in {tyVar, tyLent, tySink}: arr = arr.lastSon + if arr.kind in {tyVar, tyOut, tyLent, tySink}: arr = arr.lastSon var j = 0 while arr.kind in {tyOpenArray, tyVarargs}: # this fixes the 'sort' bug: - if param.typ.kind in {tyVar, tyLent}: param.loc.storage = OnUnknown + if param.typ.kind in {tyVar, tyOut, tyLent}: param.loc.storage = OnUnknown # need to pass hidden parameter: params.addf(", NI $1Len_$2", [param.loc.r, j.rope]) inc(j) @@ -701,8 +701,8 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope = excl(check, t.id) return case t.kind - of tyRef, tyPtr, tyVar, tyLent: - var star = if t.kind == tyVar and tfVarIsPtr notin origTyp.flags and + of tyRef, tyPtr, tyVar, tyOut, tyLent: + var star = if t.kind in {tyVar, tyOut} and tfVarIsPtr notin origTyp.flags and compileToCpp(m): "&" else: "*" var et = origTyp.skipTypes(abstractInst).lastSon var etB = et.skipTypes(abstractInst) @@ -1373,7 +1373,7 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope = else: case t.kind of tyEmpty, tyVoid: result = rope"0" - of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar, tyLent: + of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar, tyOut, tyLent: genTypeInfoAuxBase(m, t, t, result, rope"0", info) of tyStatic: if t.n != nil: result = genTypeInfo(m, lastSon t, info) diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim index edf9db3833ddd..6ffd72815039f 100644 --- a/compiler/cgmeth.nim +++ b/compiler/cgmeth.nim @@ -67,7 +67,7 @@ proc sameMethodBucket(a, b: PSym; multiMethods: bool): MethodResult = while true: aa = skipTypes(aa, {tyGenericInst, tyAlias}) bb = skipTypes(bb, {tyGenericInst, tyAlias}) - if aa.kind == bb.kind and aa.kind in {tyVar, tyPtr, tyRef, tyLent}: + if aa.kind == bb.kind and aa.kind in {tyVar, tyOut, tyPtr, tyRef, tyLent}: aa = aa.lastSon bb = bb.lastSon else: diff --git a/compiler/dfa.nim b/compiler/dfa.nim index a0ec31ac6cd73..3ac980edaa7b5 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -714,12 +714,9 @@ proc genCall(c: var Con; n: PNode) = inc c.inCall for i in 1.. 0 and canRaiseConservative(n[0]): # we generate the instruction sequence: diff --git a/compiler/evalffi.nim b/compiler/evalffi.nim index f89451f514fe2..b79c571a3be06 100644 --- a/compiler/evalffi.nim +++ b/compiler/evalffi.nim @@ -92,7 +92,7 @@ proc mapType(conf: ConfigRef, t: ast.PType): ptr libffi.Type = else: result = nil of tyFloat, tyFloat64: result = addr libffi.type_double of tyFloat32: result = addr libffi.type_float - of tyVar, tyLent, tyPointer, tyPtr, tyRef, tyCString, tySequence, tyString, tyUntyped, + of tyVar, tyOut, tyLent, tyPointer, tyPtr, tyRef, tyCString, tySequence, tyString, tyUntyped, tyTyped, tyTypeDesc, tyProc, tyArray, tyStatic, tyNil: result = addr libffi.type_pointer of tyDistinct, tyAlias, tySink: @@ -118,7 +118,7 @@ template `+!`(x, y: untyped): untyped = proc packSize(conf: ConfigRef, v: PNode, typ: PType): int = ## computes the size of the blob case typ.kind - of tyPtr, tyRef, tyVar, tyLent: + of tyPtr, tyRef, tyVar, tyOut, tyLent: if v.kind in {nkNilLit, nkPtrLit}: result = sizeof(pointer) else: @@ -215,7 +215,7 @@ proc pack(conf: ConfigRef, v: PNode, typ: PType, res: pointer) = awr(cstring, cstring(v.strVal)) else: globalError(conf, v.info, "cannot map pointer/proc value to FFI") - of tyPtr, tyRef, tyVar, tyLent: + of tyPtr, tyRef, tyVar, tyOut, tyLent: if v.kind == nkNilLit: # nothing to do since the memory is 0 initialized anyway discard @@ -370,7 +370,7 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode = result = n else: awi(nkPtrLit, cast[ByteAddress](p)) - of tyPtr, tyRef, tyVar, tyLent: + of tyPtr, tyRef, tyVar, tyOut, tyLent: let p = rd(pointer, x) if p.isNil: setNil() @@ -401,7 +401,7 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode = globalError(conf, n.info, "cannot map value from FFI " & typeToString(typ)) proc fficast*(conf: ConfigRef, x: PNode, destTyp: PType): PNode = - if x.kind == nkPtrLit and x.typ.kind in {tyPtr, tyRef, tyVar, tyLent, tyPointer, + if x.kind == nkPtrLit and x.typ.kind in {tyPtr, tyRef, tyVar, tyOut, tyLent, tyPointer, tyProc, tyCString, tyString, tySequence}: result = newNodeIT(x.kind, x.info, destTyp) diff --git a/compiler/guards.nim b/compiler/guards.nim index e4f87bae4977a..1ef1bbfec61d6 100644 --- a/compiler/guards.nim +++ b/compiler/guards.nim @@ -46,7 +46,7 @@ proc isLet(n: PNode): bool = if n.sym.kind in {skLet, skTemp, skForVar}: result = true elif n.sym.kind == skParam and skipTypes(n.sym.typ, - abstractInst).kind != tyVar: + abstractInst).kind notin {tyVar, tyOut}: result = true proc isVar(n: PNode): bool = diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 6aacf818a6000..5c907b390deb7 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -179,7 +179,7 @@ const proc mapType(typ: PType): TJSTypeKind = let t = skipTypes(typ, abstractInst) case t.kind - of tyVar, tyRef, tyPtr, tyLent: + of tyVar, tyOut, tyRef, tyPtr, tyLent: if skipTypes(t.lastSon, abstractInst).kind in MappedToObject: result = etyObject else: @@ -193,7 +193,7 @@ proc mapType(typ: PType): TJSTypeKind = of tyBool: result = etyBool of tyFloat..tyFloat128: result = etyFloat of tySet: result = etyObject # map a set to a table - of tyString, tySequence, tyOpt: result = etySeq + of tyString, tySequence: result = etySeq of tyObject, tyArray, tyTuple, tyOpenArray, tyVarargs, tyUncheckedArray: result = etyObject of tyNil: result = etyNull @@ -1029,7 +1029,7 @@ proc needsNoCopy(p: PProc; y: PNode): bool = return y.kind in nodeKindsNeedNoCopy or ((mapType(y.typ) != etyBaseIndex or (y.kind == nkSym and y.sym.kind == skParam)) and (skipTypes(y.typ, abstractInst).kind in - {tyRef, tyPtr, tyLent, tyVar, tyCString, tyProc, tyOwned} + IntegralTypes)) + {tyRef, tyPtr, tyLent, tyVar, tyOut, tyCString, tyProc, tyOwned} + IntegralTypes)) proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) = var a, b: TCompRes @@ -1041,7 +1041,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) = # we don't care if it's an etyBaseIndex (global) of a string, it's # still a string that needs to be copied properly: - if x.typ.skipTypes(abstractInst).kind in {tySequence, tyOpt, tyString}: + if x.typ.skipTypes(abstractInst).kind in {tySequence, tyString}: xtyp = etySeq case xtyp of etySeq: @@ -1052,7 +1052,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) = lineF(p, "$1 = nimCopy(null, $2, $3);$n", [a.rdLoc, b.res, genTypeInfo(p, y.typ)]) of etyObject: - if x.typ.kind == tyVar or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded: + if x.typ.kind in {tyVar, tyOut} or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded: lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc]) else: useMagic(p, "nimCopy") @@ -1083,7 +1083,7 @@ proc genFastAsgn(p: PProc, n: PNode) = # See bug #5933. So we try to be more compatible with the C backend semantics # here for 'shallowCopy'. This is an educated guess and might require further # changes later: - let noCopy = n[0].typ.skipTypes(abstractInst).kind in {tySequence, tyOpt, tyString} + let noCopy = n[0].typ.skipTypes(abstractInst).kind in {tySequence, tyString} genAsgnAux(p, n[0], n[1], noCopyNeeded=noCopy) proc genSwap(p: PProc, n: PNode) = @@ -1443,7 +1443,7 @@ proc genArg(p: PProc, n: PNode, param: PSym, r: var TCompRes; emitted: ptr int = r.res.add(", ") r.res.add(a.res) if emitted != nil: inc emitted[] - elif n.typ.kind in {tyVar, tyPtr, tyRef, tyLent, tyOwned} and + elif n.typ.kind in {tyVar, tyOut, tyPtr, tyRef, tyLent, tyOwned} and n.kind in nkCallKinds and mapType(param.typ) == etyBaseIndex: # this fixes bug #5608: let tmp = getTemp(p) @@ -1683,14 +1683,14 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope = createObjInitList(p, t, initIntSet(), initList) result = ("{$1}") % [initList] if indirect: result = "[$1]" % [result] - of tyVar, tyPtr, tyLent, tyRef, tyPointer: + of tyVar, tyOut, tyPtr, tyLent, tyRef, tyPointer: if mapType(p, t) == etyBaseIndex: result = putToSeq("[null, 0]", indirect) else: result = putToSeq("null", indirect) of tySequence, tyString: result = putToSeq("[]", indirect) - of tyCString, tyOpt, tyProc: + of tyCString, tyProc: result = putToSeq("null", indirect) of tyStatic: if t.n != nil: @@ -1728,7 +1728,7 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) = if n.kind == nkEmpty: if not isIndirect(v) and - v.typ.kind in {tyVar, tyPtr, tyLent, tyRef, tyOwned} and mapType(p, v.typ) == etyBaseIndex: + v.typ.kind in {tyVar, tyOut, tyPtr, tyLent, tyRef, tyOwned} and mapType(p, v.typ) == etyBaseIndex: lineF(p, "var $1 = null;$n", [varName]) lineF(p, "var $1_Idx = 0;$n", [varName]) else: @@ -2278,7 +2278,7 @@ proc genProc(oldProc: PProc, prc: PSym): Rope = resultSym = prc.ast[resultPos].sym let mname = mangleName(p.module, resultSym) if not isIndirect(resultSym) and - resultSym.typ.kind in {tyVar, tyPtr, tyLent, tyRef, tyOwned} and + resultSym.typ.kind in {tyVar, tyOut, tyPtr, tyLent, tyRef, tyOwned} and mapType(p, resultSym.typ) == etyBaseIndex: resultAsgn = p.indentLine(("var $# = null;$n") % [mname]) resultAsgn.add p.indentLine("var $#_Idx = 0;$n" % [mname]) diff --git a/compiler/jstypes.nim b/compiler/jstypes.nim index 2073c252ec1a9..9f0b8c6c7de18 100644 --- a/compiler/jstypes.nim +++ b/compiler/jstypes.nim @@ -133,7 +133,7 @@ proc genTypeInfo(p: PProc, typ: PType): Rope = "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n" % [result, rope(ord(t.kind))] prepend(p.g.typeInfo, s) - of tyVar, tyLent, tyRef, tyPtr, tySequence, tyRange, tySet: + of tyVar, tyOut, tyLent, tyRef, tyPtr, tySequence, tyRange, tySet: var s = "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n" % [result, rope(ord(t.kind))] diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index c1cd075837989..4282caf52b8c0 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -192,7 +192,7 @@ proc interestingVar(s: PSym): bool {.inline.} = proc illegalCapture(s: PSym): bool {.inline.} = result = skipTypes(s.typ, abstractInst).kind in - {tyVar, tyOpenArray, tyVarargs, tyLent} or + {tyVar, tyOut, tyOpenArray, tyVarargs, tyLent} or s.kind == skResult proc isInnerProc(s: PSym): bool = diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 2d8655caef705..ea7212ba69430 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -50,7 +50,7 @@ proc fillBodyTup(c: var TLiftCtx; t: PType; body, x, y: PNode) = proc dotField(x: PNode, f: PSym): PNode = result = newNodeI(nkDotExpr, x.info, 2) - if x.typ.skipTypes(abstractInst).kind == tyVar: + if x.typ.skipTypes(abstractInst).kind in {tyVar, tyOut}: result[0] = x.newDeref else: result[0] = x @@ -248,7 +248,7 @@ proc newHookCall(g: ModuleGraph; op: PSym; x, y: PNode): PNode = # localError(c.config, x.info, "usage of '$1' is a user-defined error" % op.name.s) result = newNodeI(nkCall, x.info) result.add newSymNode(op) - if op.typ.sons[1].kind == tyVar: + if op.typ.sons[1].kind in {tyVar, tyOut}: result.add genAddr(g, x) else: result.add x @@ -703,7 +703,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) = case t.kind of tyNone, tyEmpty, tyVoid: discard of tyPointer, tySet, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString, - tyPtr, tyOpt, tyUncheckedArray, tyVar, tyLent: + tyPtr, tyUncheckedArray, tyVar, tyOut, tyLent: defaultOp(c, t, body, x, y) of tyRef: if c.g.config.selectedGC in {gcArc, gcOrc}: diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index 575bfe8aa72d2..2d628d257925b 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -21,8 +21,8 @@ proc newDeref*(n: PNode): PNode {.inline.} = proc newTupleAccess*(g: ModuleGraph; tup: PNode, i: int): PNode = if tup.kind == nkHiddenAddr: - result = newNodeIT(nkHiddenAddr, tup.info, tup.typ.skipTypes(abstractInst+{tyPtr, tyVar, tyLent})) - result.add newNodeIT(nkBracketExpr, tup.info, tup.typ.skipTypes(abstractInst+{tyPtr, tyVar, tyLent})[i]) + result = newNodeIT(nkHiddenAddr, tup.info, tup.typ.skipTypes(abstractInst+{tyPtr, tyVar, tyOut, tyLent})) + result.add newNodeIT(nkBracketExpr, tup.info, tup.typ.skipTypes(abstractInst+{tyPtr, tyVar, tyOut, tyLent})[i]) result[0].add tup[0] var lit = newNodeIT(nkIntLit, tup.info, getSysType(g, tup.info, tyInt)) lit.intVal = i @@ -59,7 +59,7 @@ proc newFastAsgnStmt*(le, ri: PNode): PNode = result[0] = le result[1] = ri -proc newFastMoveStmt*(g: ModuleGraph, le, ri: PNode): PNode = +proc newFastMoveStmt*(g: ModuleGraph, le, ri: PNode): PNode = result = newNodeI(nkFastAsgn, le.info, 2) result[0] = le result[1] = newNodeIT(nkCall, ri.info, ri.typ) diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim index 33881a7b30b97..5e76b758cc503 100644 --- a/compiler/parampatterns.nim +++ b/compiler/parampatterns.nim @@ -200,7 +200,7 @@ proc exprRoot*(n: PNode): PSym = if it.len > 0 and it.typ != nil: it = it.lastSon else: break of nkCallKinds: - if it.typ != nil and it.typ.kind == tyVar and it.len > 1: + if it.typ != nil and it.typ.kind in {tyVar, tyOut} and it.len > 1: # See RFC #7373, calls returning 'var T' are assumed to # return a view into the first argument (if there is one): it = it[1] @@ -214,12 +214,12 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult result = arNone case n.kind of nkEmpty: - if n.typ != nil and n.typ.kind == tyVar: + if n.typ != nil and n.typ.kind in {tyVar, tyOut}: result = arLValue of nkSym: let kinds = if isUnsafeAddr: {skVar, skResult, skTemp, skParam, skLet, skForVar} else: {skVar, skResult, skTemp} - if n.sym.kind == skParam and n.sym.typ.kind in {tyVar, tySink}: + if n.sym.kind == skParam and n.sym.typ.kind in {tyVar, tyOut, tySink}: result = arLValue elif isUnsafeAddr and n.sym.kind == skParam: result = arLValue @@ -231,10 +231,10 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult result = arLValue elif n.sym.kind == skType: let t = n.sym.typ.skipTypes({tyTypeDesc}) - if t.kind == tyVar: result = arStrange + if t.kind in {tyVar, tyOut}: result = arStrange of nkDotExpr: let t = skipTypes(n[0].typ, abstractInst-{tyTypeDesc}) - if t.kind in {tyVar, tySink, tyPtr, tyRef}: + if t.kind in {tyVar, tyOut, tySink, tyPtr, tyRef}: result = arLValue elif isUnsafeAddr and t.kind == tyLent: result = arLValue @@ -245,7 +245,7 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult result = arDiscriminant of nkBracketExpr: let t = skipTypes(n[0].typ, abstractInst-{tyTypeDesc}) - if t.kind in {tyVar, tySink, tyPtr, tyRef}: + if t.kind in {tyVar, tyOut, tySink, tyPtr, tyRef}: result = arLValue elif isUnsafeAddr and t.kind == tyLent: result = arLValue @@ -277,7 +277,7 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult # builtin slice keeps lvalue-ness: if getMagic(n) in {mArrGet, mSlice}: result = isAssignable(owner, n[1], isUnsafeAddr) - elif n.typ != nil and n.typ.kind == tyVar: + elif n.typ != nil and n.typ.kind in {tyVar, tyOut}: result = arLValue elif isUnsafeAddr and n.typ != nil and n.typ.kind == tyLent: result = arLValue diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 29ff80ca93caf..b892a3e2f2459 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -309,8 +309,8 @@ proc lsub(g: TSrcGen; n: PNode): int proc litAux(g: TSrcGen; n: PNode, x: BiggestInt, size: int): string = proc skip(t: PType): PType = result = t - while result != nil and result.kind in {tyGenericInst, tyRange, tyVar, tyLent, tyDistinct, - tyOrdinal, tyAlias, tySink}: + while result != nil and result.kind in {tyGenericInst, tyRange, tyVar, tyOut, + tyLent, tyDistinct, tyOrdinal, tyAlias, tySink}: result = lastSon(result) let typ = n.typ.skip diff --git a/compiler/semcall.nim b/compiler/semcall.nim index c6e12facf4a8b..8eae1bb5b5953 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -672,8 +672,8 @@ proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym = let t = skipTypes(param.typ, abstractVar-{tyTypeDesc, tyDistinct}) if t.kind == tyDistinct or param.typ.kind == tyDistinct: hasDistinct = true var x: PType - if param.typ.kind == tyVar: - x = newTypeS(tyVar, c) + if param.typ.kind in {tyVar, tyOut}: + x = newTypeS(param.typ.kind, c) x.addSonSkipIntLit t.baseOfDistinct else: x = t.baseOfDistinct diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 5a2c08de266b8..7b3ac48d4b72f 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -288,9 +288,9 @@ proc makePtrType*(c: PContext, baseType: PType): PType = proc makeTypeWithModifier*(c: PContext, modifier: TTypeKind, baseType: PType): PType = - assert modifier in {tyVar, tyLent, tyPtr, tyRef, tyStatic, tyTypeDesc} + assert modifier in {tyVar, tyOut, tyLent, tyPtr, tyRef, tyStatic, tyTypeDesc} - if modifier in {tyVar, tyLent, tyTypeDesc} and baseType.kind == modifier: + if modifier in {tyVar, tyOut, tyLent, tyTypeDesc} and baseType.kind == modifier: result = baseType else: result = newTypeS(modifier, c) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index c5b864d1fbc7a..80a818f5d2298 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -54,7 +54,7 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = # XXX tyGenericInst here? if result.typ.kind == tyProc and tfUnresolved in result.typ.flags: localError(c.config, n.info, errProcHasNoConcreteType % n.renderTree) - if result.typ.kind in {tyVar, tyLent}: result = newDeref(result) + if result.typ.kind in {tyVar, tyOut, tyLent}: result = newDeref(result) elif {efWantStmt, efAllowStmt} * flags != {}: result.typ = newTypeS(tyVoid, c) else: @@ -79,7 +79,7 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = renderTree(result, {renderNoComments})) result.typ = errorType(c) else: - if result.typ.kind in {tyVar, tyLent}: result = newDeref(result) + if result.typ.kind in {tyVar, tyOut, tyLent}: result = newDeref(result) proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = result = semExprCheck(c, n, flags) @@ -551,7 +551,7 @@ proc arrayConstrType(c: PContext, n: PNode): PType = if n.len == 0: rawAddSon(typ, newTypeS(tyEmpty, c)) # needs an empty basetype! else: - var t = skipTypes(n[0].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink}) + var t = skipTypes(n[0].typ, {tyGenericInst, tyVar, tyOut, tyLent, tyOrdinal, tyAlias, tySink}) addSonSkipIntLit(typ, t) typ[0] = makeRangeType(c, 0, n.len - 1, n.info) result = typ @@ -584,7 +584,7 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = let yy = semExprWithType(c, x) var typ = yy.typ result.add yy - #var typ = skipTypes(result[0].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal}) + #var typ = skipTypes(result[0].typ, {tyGenericInst, tyVar, tyOut, tyLent, tyOrdinal}) for i in 1.. 'result' n[1] = takeImplicitAddr(c, ri, x.typ.kind == tyLent) x.typ.flags.incl tfVarIsPtr @@ -1711,7 +1711,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode = var le = a.typ if le == nil: localError(c.config, a.info, "expression has no type") - elif (skipTypes(le, {tyGenericInst, tyAlias, tySink}).kind != tyVar and + elif (skipTypes(le, {tyGenericInst, tyAlias, tySink}).kind notin {tyVar, tyOut} and isAssignable(c, a) in {arNone, arLentValue}) or skipTypes(le, abstractVar).kind in {tyOpenArray, tyVarargs}: # Direct assignment to a discriminant is allowed! @@ -1808,7 +1808,7 @@ proc semProcBody(c: PContext, n: PNode): PNode = proc semYieldVarResult(c: PContext, n: PNode, restype: PType) = var t = skipTypes(restype, {tyGenericInst, tyAlias, tySink}) case t.kind - of tyVar, tyLent: + of tyVar, tyOut, tyLent: t.flags.incl tfVarIsPtr # bugfix for #4048, #4910, #6892 if n[0].kind in {nkHiddenStdConv, nkHiddenSubConv}: n[0] = n[0][1] @@ -1816,7 +1816,7 @@ proc semYieldVarResult(c: PContext, n: PNode, restype: PType) = of tyTuple: for i in 0..= 2 and t[0] == nil if cond: - var obj = t[1].skipTypes({tyVar}) + var obj = t[1].skipTypes({tyVar, tyOut}) while true: incl(obj.flags, tfHasAsgn) if obj.kind in {tyGenericBody, tyGenericInst}: obj = obj.lastSon @@ -1825,7 +1815,7 @@ proc semMethodPrototype(c: PContext; s: PSym; n: PNode) = for col in 1.. 0 and t[0] != nil: hashType c, t[0], flags - of tyRef, tyPtr, tyGenericBody, tyVar: + of tyRef, tyPtr, tyGenericBody, tyVar, tyOut: c &= char(t.kind) c.hashType t.lastSon, flags if tfVarIsPtr in t.flags: c &= ".varisptr" diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index e99269c41b45d..cdde9974eb072 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -219,7 +219,7 @@ proc sumGeneric(t: PType): int = if branchSum > maxBranch: maxBranch = branchSum inc result, maxBranch break - of tyVar: + of tyVar, tyOut: t = t[0] inc result inc isvar @@ -549,7 +549,7 @@ proc allowsNilDeprecated(c: TCandidate, f: PType): TTypeRelation = proc inconsistentVarTypes(f, a: PType): bool {.inline.} = result = f.kind != a.kind and - (f.kind in {tyVar, tyLent, tySink} or a.kind in {tyVar, tyLent, tySink}) + (f.kind in {tyVar, tyOut, tyLent, tySink} or a.kind in {tyVar, tyOut, tyLent, tySink}) proc procParamTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = ## For example we have: @@ -926,7 +926,7 @@ proc inferStaticsInRange(c: var TCandidate, template subtypeCheck() = if result <= isSubrange and f.lastSon.skipTypes(abstractInst).kind in { - tyRef, tyPtr, tyVar, tyLent, tyOwned}: + tyRef, tyPtr, tyVar, tyOut, tyLent, tyOwned}: result = isNone proc isCovariantPtr(c: var TCandidate, f, a: PType): bool = @@ -934,7 +934,7 @@ proc isCovariantPtr(c: var TCandidate, f, a: PType): bool = assert f.kind == a.kind template baseTypesCheck(lhs, rhs: PType): bool = - lhs.kind notin {tyPtr, tyRef, tyVar, tyLent, tyOwned} and + lhs.kind notin {tyPtr, tyRef, tyVar, tyOut, tyLent, tyOwned} and typeRel(c, lhs, rhs, {trNoCovariance}) == isSubtype case f.kind @@ -1050,7 +1050,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, template doBind: bool = trDontBind notin flags # var, sink and static arguments match regular modifier-free types - var a = maybeSkipDistinct(c, aOrig.skipTypes({tyStatic, tyVar, tyLent, tySink}), c.calleeSym) + var a = maybeSkipDistinct(c, aOrig.skipTypes({tyStatic, tyVar, tyOut, tyLent, tySink}), c.calleeSym) # XXX: Theoretically, maybeSkipDistinct could be called before we even # start the param matching process. This could be done in `prepareOperand` # for example, but unfortunately `prepareOperand` is not called in certain @@ -1060,7 +1060,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, return typeRel(c, f, lastSon(aOrig)) if a.kind == tyGenericInst and - skipTypes(f, {tyVar, tyLent, tySink}).kind notin { + skipTypes(f, {tyVar, tyOut, tyLent, tySink}).kind notin { tyGenericBody, tyGenericInvocation, tyGenericInst, tyGenericParam} + tyTypeClasses: return typeRel(c, f, lastSon(a)) @@ -1173,7 +1173,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, of tyFloat32: result = handleFloatRange(f, a) of tyFloat64: result = handleFloatRange(f, a) of tyFloat128: result = handleFloatRange(f, a) - of tyVar, tyLent: + of tyVar, tyOut, tyLent: if aOrig.kind == f.kind: result = typeRel(c, f.base, aOrig.base) else: result = typeRel(c, f.base, aOrig, flags + {trNoCovariance}) subtypeCheck() @@ -1895,14 +1895,14 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType, let constraint = c.converters[i].typ.n[1].sym.constraint if not constraint.isNil and not matchNodeKinds(constraint, arg): continue - if src.kind in {tyVar, tyLent} and not arg.isLValue: + if src.kind in {tyVar, tyOut, tyLent} and not arg.isLValue: continue let destIsGeneric = containsGenericType(dest) if destIsGeneric: dest = generateTypeInstance(c, m.bindings, arg, dest) let fdest = typeRel(m, f, dest) - if fdest in {isEqual, isGeneric} and not (dest.kind == tyLent and f.kind == tyVar): + if fdest in {isEqual, isGeneric} and not (dest.kind == tyLent and f.kind in {tyVar, tyOut}): markUsed(c, arg.info, c.converters[i]) var s = newSymNode(c.converters[i]) s.typ = c.converters[i].typ @@ -1915,7 +1915,7 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType, var param: PNode = nil if srca == isSubtype: param = implicitConv(nkHiddenSubConv, src, copyTree(arg), m, c) - elif src.kind == tyVar: + elif src.kind in {tyVar, tyOut}: # Analyse the converter return type param = newNodeIT(nkHiddenAddr, arg.info, s.typ[1]) param.add copyTree(arg) @@ -1923,7 +1923,7 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType, param = copyTree(arg) result.add param - if dest.kind in {tyVar, tyLent}: + if dest.kind in {tyVar, tyOut, tyLent}: dest.flags.incl tfVarIsPtr result = newDeref(result) @@ -2082,7 +2082,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType, result = implicitConv(nkHiddenSubConv, f, arg, m, c) of isSubrange: inc(m.subtypeMatches) - if f.kind == tyVar: + if f.kind in {tyVar, tyOut}: result = arg else: result = implicitConv(nkHiddenStdConv, f, arg, m, c) @@ -2290,7 +2290,7 @@ proc arrayConstr(c: PContext, n: PNode): PType = result = newTypeS(tyArray, c) rawAddSon(result, makeRangeType(c, 0, 0, n.info)) addSonSkipIntLit(result, skipTypes(n.typ, - {tyGenericInst, tyVar, tyLent, tyOrdinal})) + {tyGenericInst, tyVar, tyOut, tyLent, tyOrdinal})) proc arrayConstr(c: PContext, info: TLineInfo): PType = result = newTypeS(tyArray, c) @@ -2327,10 +2327,10 @@ proc matchesAux(c: PContext, n, nOrig: PNode, noMatch() return - if formal.typ.kind == tyVar: + if formal.typ.kind in {tyVar, tyOut}: let argConverter = if arg.kind == nkHiddenDeref: arg[0] else: arg if argConverter.kind == nkHiddenCallConv: - if argConverter.typ.kind != tyVar: + if argConverter.typ.kind notin {tyVar, tyOut}: m.firstMismatch.kind = kVarNeeded noMatch() return @@ -2604,7 +2604,7 @@ proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo; if op == attachedDeepCopy: if f.kind in {tyRef, tyPtr}: f = f.lastSon else: - if f.kind == tyVar: f = f.lastSon + if f.kind in {tyVar, tyOut}: f = f.lastSon if typeRel(m, f, t) == isNone: localError(c.config, info, "cannot instantiate: '" & dc.name.s & "'") else: diff --git a/compiler/sinkparameter_inference.nim b/compiler/sinkparameter_inference.nim index 182e443247688..d5510e7fb0c17 100644 --- a/compiler/sinkparameter_inference.nim +++ b/compiler/sinkparameter_inference.nim @@ -26,7 +26,7 @@ proc checkForSink*(config: ConfigRef; owner: PSym; arg: PNode) = arg.sym.owner == owner and owner.typ != nil and owner.typ.kind == tyProc and arg.sym.typ.hasDestructor and - arg.sym.typ.kind notin {tyVar, tySink, tyOwned}: + arg.sym.typ.kind notin {tyVar, tyOut, tySink, tyOwned}: # Watch out: cannot do this inference for procs with forward # declarations. if sfWasForwarded notin owner.flags: diff --git a/compiler/sizealignoffsetimpl.nim b/compiler/sizealignoffsetimpl.nim index 9d12297eac49e..504375aa6b027 100644 --- a/compiler/sizealignoffsetimpl.nim +++ b/compiler/sizealignoffsetimpl.nim @@ -240,7 +240,7 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) = else: typ.size = conf.target.ptrSize typ.align = int16(conf.target.ptrSize) - of tyCString, tySequence, tyPtr, tyRef, tyVar, tyLent, tyOpenArray: + of tyCString, tySequence, tyPtr, tyRef, tyVar, tyOut, tyLent, tyOpenArray: let base = typ.lastSon if base == typ: # this is not the correct location to detect ``type A = ptr A`` diff --git a/compiler/spawn.nim b/compiler/spawn.nim index 8b1f89e15af7f..547cf9abca1dd 100644 --- a/compiler/spawn.nim +++ b/compiler/spawn.nim @@ -37,7 +37,7 @@ proc spawnResult*(t: PType; inParallel: bool): TSpawnResult = else: srFlowVar proc flowVarKind(c: ConfigRef, t: PType): TFlowVarKind = - if c.selectedGC in {gcArc, gcOrc}: fvBlob + if c.selectedGC in {gcArc, gcOrc}: fvBlob elif t.skipTypes(abstractInst).kind in {tyRef, tyString, tySequence}: fvGC elif containsGarbageCollectedRef(t): fvInvalid else: fvBlob @@ -50,7 +50,7 @@ proc typeNeedsNoDeepCopy(t: PType): bool = # note that seq[T] is fine, but 'var seq[T]' is not, so we need to skip 'var' # for the stricter check and likewise we can skip 'seq' for a less # strict check: - if t.kind in {tyVar, tyLent, tySequence}: t = t.lastSon + if t.kind in {tyVar, tyOut, tyLent, tySequence}: t = t.lastSon result = not containsGarbageCollectedRef(t) proc addLocalVar(g: ModuleGraph; varSection, varInit: PNode; owner: PSym; typ: PType; @@ -201,8 +201,8 @@ proc setupArgsForConcurrency(g: ModuleGraph; n: PNode; objType: PType; # we pick n's type here, which hopefully is 'tyArray' and not # 'tyOpenArray': var argType = n[i].typ.skipTypes(abstractInst) - if i < formals.len: - if formals[i].typ.kind in {tyVar, tyLent}: + if i < formals.len: + if formals[i].typ.kind in {tyVar, tyOut, tyLent}: localError(g.config, n[i].info, "'spawn'ed function cannot have a 'var' parameter") if formals[i].typ.kind in {tyTypeDesc, tyStatic}: continue diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 58b54cc038169..fb60b50a391a2 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -260,7 +260,7 @@ proc suggestField(c: PContext, s: PSym; f: PNode; info: TLineInfo; outputs: var proc getQuality(s: PSym): range[0..100] = if s.typ != nil and s.typ.len > 1: - var exp = s.typ[1].skipTypes({tyGenericInst, tyVar, tyLent, tyAlias, tySink}) + var exp = s.typ[1].skipTypes({tyGenericInst, tyVar, tyOut, tyLent, tyAlias, tySink}) if exp.kind == tyVarargs: exp = elemType(exp) if exp.kind in {tyUntyped, tyTyped, tyGenericParam, tyAnything}: return 50 return 100 @@ -331,7 +331,7 @@ proc typeFits(c: PContext, s: PSym, firstArg: PType): bool {.inline.} = let m = s.getModule() if m != nil and sfSystemModule in m.flags: if s.kind == skType: return - var exp = s.typ[1].skipTypes({tyGenericInst, tyVar, tyLent, tyAlias, tySink}) + var exp = s.typ[1].skipTypes({tyGenericInst, tyVar, tyOut, tyLent, tyAlias, tySink}) if exp.kind == tyVarargs: exp = elemType(exp) if exp.kind in {tyUntyped, tyTyped, tyGenericParam, tyAnything}: return result = sigmatch.argtypeMatches(c, s.typ[1], firstArg) @@ -401,7 +401,7 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions) suggestOperations(c, n, field, typ, outputs) else: let orig = typ # skipTypes(typ, {tyGenericInst, tyAlias, tySink}) - typ = skipTypes(typ, {tyGenericInst, tyVar, tyLent, tyPtr, tyRef, tyAlias, tySink, tyOwned}) + typ = skipTypes(typ, {tyGenericInst, tyVar, tyOut, tyLent, tyPtr, tyRef, tyAlias, tySink, tyOwned}) if typ.kind == tyObject: var t = typ while true: diff --git a/compiler/transf.nim b/compiler/transf.nim index bd9f567ed3f88..c09d4d61816f2 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -422,8 +422,8 @@ proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PNode = result = n[0] if n.typ.skipTypes(abstractVar).kind != tyOpenArray: result.typ = n.typ - elif n.typ.skipTypes(abstractInst).kind in {tyVar}: - result.typ = toVar(result.typ) + elif n.typ.skipTypes(abstractInst).kind in {tyVar, tyOut}: + result.typ = toVar(result.typ, n.typ.skipTypes(abstractInst).kind) of nkHiddenStdConv, nkHiddenSubConv, nkConv: var m = n[0][1] if m.kind == a or m.kind == b: @@ -432,8 +432,8 @@ proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PNode = result = n[0] if n.typ.skipTypes(abstractVar).kind != tyOpenArray: result.typ = n.typ - elif n.typ.skipTypes(abstractInst).kind in {tyVar}: - result.typ = toVar(result.typ) + elif n.typ.skipTypes(abstractInst).kind in {tyVar, tyOut}: + result.typ = toVar(result.typ, n.typ.skipTypes(abstractInst).kind) else: if n[0].kind == a or n[0].kind == b: # addr ( deref ( x )) --> x @@ -569,18 +569,18 @@ proc putArgInto(arg: PNode, formal: PType): TPutArgInto = result = putArgInto(arg[0], formal) of nkCurly, nkBracket: for i in 0.. 0: result &= "[" & typeToString(t[0]) & ']' - of tyOpt: - result = "opt" - if t.len > 0: - result &= "opt[" & typeToString(t[0]) & ']' of tyOrdinal: result = "ordinal" if t.len > 0: @@ -646,7 +643,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = result.add(typeToString(t[i])) if i < t.len - 1: result.add(", ") result.add(')') - of tyPtr, tyRef, tyVar, tyLent: + of tyPtr, tyRef, tyOut, tyVar, tyLent: result = typeToStr[t.kind] if t.len >= 2: setLen(result, result.len-1) @@ -709,7 +706,7 @@ proc firstOrd*(conf: ConfigRef; t: PType): Int128 = case t.kind of tyBool, tyChar, tySequence, tyOpenArray, tyString, tyVarargs, tyProxy: result = Zero - of tySet, tyVar: result = firstOrd(conf, t[0]) + of tySet, tyVar, tyOut: result = firstOrd(conf, t[0]) of tyArray: result = firstOrd(conf, t[0]) of tyRange: assert(t.n != nil) # range directly given: @@ -751,7 +748,7 @@ proc firstFloat*(t: PType): BiggestFloat = assert(t.n != nil) # range directly given: assert(t.n.kind == nkRange) getFloatValue(t.n[0]) - of tyVar: firstFloat(t[0]) + of tyVar, tyOut: firstFloat(t[0]) of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tySink, tyStatic, tyInferred, tyUserTypeClasses: firstFloat(lastSon(t)) @@ -763,7 +760,7 @@ proc lastOrd*(conf: ConfigRef; t: PType): Int128 = case t.kind of tyBool: result = toInt128(1'u) of tyChar: result = toInt128(255'u) - of tySet, tyVar: result = lastOrd(conf, t[0]) + of tySet, tyVar, tyOut: result = lastOrd(conf, t[0]) of tyArray: result = lastOrd(conf, t[0]) of tyRange: assert(t.n != nil) # range directly given: @@ -805,7 +802,7 @@ proc lastOrd*(conf: ConfigRef; t: PType): Int128 = proc lastFloat*(t: PType): BiggestFloat = case t.kind of tyFloat..tyFloat128: Inf - of tyVar: lastFloat(t[0]) + of tyVar, tyOut: lastFloat(t[0]) of tyRange: assert(t.n != nil) # range directly given: assert(t.n.kind == nkRange) @@ -825,7 +822,7 @@ proc floatRangeCheck*(x: BiggestFloat, t: PType): bool = true of tyRange: x in firstFloat(t)..lastFloat(t) - of tyVar: + of tyVar, tyOut: floatRangeCheck(x, t[0]) of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tySink, tyStatic, tyInferred, tyUserTypeClasses: @@ -1148,9 +1145,9 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = assert b[0].len == 0 result = a[0].kind == b[0].kind of tyGenericInvocation, tyGenericBody, tySequence, tyOpenArray, tySet, tyRef, - tyPtr, tyVar, tyLent, tySink, tyUncheckedArray, tyArray, tyProc, tyVarargs, + tyPtr, tyVar, tyOut, tyLent, tySink, tyUncheckedArray, tyArray, tyProc, tyVarargs, tyOrdinal, tyCompositeTypeClass, tyUserTypeClass, tyUserTypeClassInst, - tyAnd, tyOr, tyNot, tyAnything, tyOpt, tyOwned: + tyAnd, tyOr, tyNot, tyAnything, tyOwned: cycleCheck() if a.kind == tyUserTypeClass and a.n != nil: return a.n == b.n result = sameChildrenAux(a, b, c) @@ -1289,7 +1286,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, if containsOrIncl(marker, typ.id): return nil var t = skipTypes(typ, abstractInst-{tyTypeDesc}) case t.kind - of tyVar, tyLent: + of tyVar, tyOut, tyLent: if kind in {skProc, skFunc, skConst}: result = t elif t.kind == tyLent and kind != skResult: @@ -1297,7 +1294,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, else: var t2 = skipTypes(t[0], abstractInst-{tyTypeDesc}) case t2.kind - of tyVar, tyLent: + of tyVar, tyOut, tyLent: if taHeap notin flags: result = t2 # ``var var`` is illegal on the heap of tyOpenArray: if kind != skParam or taIsOpenArray in flags: result = t @@ -1365,7 +1362,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, result = t else: result = typeAllowedAux(marker, lastSon(t), kind, flags-{taHeap}) - of tySequence, tyOpt: + of tySequence: if t[0].kind != tyEmpty: result = typeAllowedAux(marker, t[0], kind, flags+{taHeap}) elif kind in {skVar, skLet}: @@ -1661,7 +1658,7 @@ proc isTupleRecursive(t: PType, cycleDetector: var IntSet): bool = assign(cycleDetectorCopy, cycleDetector) if isTupleRecursive(t[i], cycleDetectorCopy): return true - of tyAlias, tyRef, tyPtr, tyGenericInst, tyVar, tyLent, tySink, + of tyAlias, tyRef, tyPtr, tyGenericInst, tyVar, tyOut, tyLent, tySink, tyArray, tyUncheckedArray, tySequence, tyDistinct: return isTupleRecursive(t.lastSon, cycleDetector) else: diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index 7cfba046ab023..573bbf93212df 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -224,7 +224,7 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo; of tyLent: result = mapTypeToBracket("lent", mBuiltinType, t, info) of tySink: result = mapTypeToBracket("sink", mBuiltinType, t, info) of tySequence: result = mapTypeToBracket("seq", mSeq, t, info) - of tyOpt: result = mapTypeToBracket("opt", mOpt, t, info) + of tyOut: result = mapTypeToBracket("out", mOut, t, info) of tyProc: if inst: result = newNodeX(nkProcTy) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index b408db08b0f99..37923982b3813 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -967,7 +967,7 @@ proc whichAsgnOpc(n: PNode; requiresCopy = true): TOpcode = opcAsgnInt of tyFloat..tyFloat128: opcAsgnFloat - of tyRef, tyNil, tyVar, tyLent, tyPtr: + of tyRef, tyNil, tyVar, tyOut, tyLent, tyPtr: opcAsgnRef else: (if requiresCopy: opcAsgnComplex else: opcFastAsgnComplex) @@ -1654,7 +1654,7 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) = template needsRegLoad(): untyped = {gfNode, gfNodeAddr} * flags == {} and - fitsRegister(n.typ.skipTypes({tyVar, tyLent, tyStatic})) + fitsRegister(n.typ.skipTypes({tyVar, tyOut, tyLent, tyStatic})) proc genArrAccessOpcode(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode; flags: TGenFlags) = @@ -1794,7 +1794,7 @@ proc getNullValue(typ: PType, info: TLineInfo; conf: ConfigRef): PNode = of tyCString, tyString: result = newNodeIT(nkStrLit, info, t) result.strVal = "" - of tyVar, tyLent, tyPointer, tyPtr, tyUntyped, + of tyVar, tyOut, tyLent, tyPointer, tyPtr, tyUntyped, tyTyped, tyTypeDesc, tyRef, tyNil: result = newNodeIT(nkNilLit, info, t) of tyProc: @@ -1820,8 +1820,6 @@ proc getNullValue(typ: PType, info: TLineInfo; conf: ConfigRef): PNode = result.add getNullValue(t[i], info, conf) of tySet: result = newNodeIT(nkCurly, info, t) - of tyOpt: - result = newNodeIT(nkNilLit, info, t) of tySequence: result = newNodeIT(nkBracket, info, t) else: diff --git a/compiler/writetracking.nim b/compiler/writetracking.nim index 3db60a19a5e88..4c95d9c26409b 100644 --- a/compiler/writetracking.nim +++ b/compiler/writetracking.nim @@ -85,7 +85,7 @@ proc allRoots(n: PNode; result: var seq[ptr TSym]; info: var set[RootInfo]) = assert(typ.n[i].kind == nkSym) let paramType = typ.n[i] if paramType.typ.isCompileTimeOnly: continue - if sfEscapes in paramType.sym.flags or paramType.typ.kind == tyVar: + if sfEscapes in paramType.sym.flags or paramType.typ.kind in {tyVar, tyOut}: allRoots(it, result, info) else: allRoots(it, result, info) @@ -164,7 +164,7 @@ proc depsArgs(w: var W; n: PNode) = let paramType = typ.n[i] if paramType.typ.isCompileTimeOnly: continue var destInfo: set[RootInfo] = {} - if sfWrittenTo in paramType.sym.flags or paramType.typ.kind == tyVar: + if sfWrittenTo in paramType.sym.flags or paramType.typ.kind in {tyVar, tyOut}: # p(f(x, y), X, g(h, z)) destInfo.incl markAsWrittenTo if sfEscapes in paramType.sym.flags: @@ -247,7 +247,7 @@ proc markWriteOrEscape(w: var W; conf: ConfigRef) = for p in a.dest: if p.kind == skParam and p.owner == w.owner: incl(p.flags, sfWrittenTo) - if w.owner.kind == skFunc and p.typ.kind != tyVar: + if w.owner.kind == skFunc and p.typ.kind notin {tyVar, tyOut}: localError(conf, a.info, "write access to non-var parameter: " & p.name.s) if {rootIsResultOrParam, rootIsHeapAccess, markAsEscaping}*a.destInfo != {}: From dba69658c7c635eba447710accfedd74a0639b69 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 31 May 2020 19:17:49 +0200 Subject: [PATCH 06/15] documented 'out' parameters --- changelog.md | 15 ++++++++--- doc/manual.rst | 72 ++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 73 insertions(+), 14 deletions(-) diff --git a/changelog.md b/changelog.md index 25fc3535c7eea..301c3f7f33b00 100644 --- a/changelog.md +++ b/changelog.md @@ -60,7 +60,7 @@ accept an existing string to modify, which avoids memory allocations, similar to `streams.readLine` (#13857). -- Added high-level `asyncnet.sendTo` and `asyncnet.recvFrom`. UDP functionality. +- Added high-level `asyncnet.sendTo` and `asyncnet.recvFrom` UDP functionality. - `paramCount` & `paramStr` are now defined in os.nim instead of nimscript.nim for nimscript/nimble. - `dollars.$` now works for unsigned ints with `nim js` @@ -100,7 +100,11 @@ parameters. ## Language changes -- In the newruntime it is now allowed to assign discriminator field without restrictions as long as case object doesn't have custom destructor. Discriminator value doesn't have to be a constant either. If you have custom destructor for case object and you do want to freely assign discriminator fields, it is recommended to refactor object into 2 objects like this: +- In the newruntime it is now allowed to assign to the discriminator field + without restrictions as long as case object doesn't have custom destructor. + The discriminator value doesn't have to be a constant either. If you have a + custom destructor for a case object and you do want to freely assign discriminator + fields, it is recommended to refactor object into 2 objects like this: ```nim type @@ -159,7 +163,12 @@ proc mydiv(a, b): int {.raises: [].} = The reason for this is that `DivByZeroDefect` inherits from `Defect` and with `--panics:on` `Defects` become unrecoverable errors. -- Added `thiscall` calling convention as specified by Microsoft, mostly for hooking purpose +- Added the `thiscall` calling convention as specified by Microsoft. + +- Added a new parameter mode, `out T` in order to strengthen the language's + "definite assignment checking". Definite assignment checking is now turned + on by default. + ## Compiler changes diff --git a/doc/manual.rst b/doc/manual.rst index f70c484a241e8..14b3238e252ec 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -2458,12 +2458,13 @@ matches) is preferred: gen(ri) # "ref T" -Overloading based on 'var T' ----------------------------- +Overloading based on 'var T' / 'out T' +-------------------------------------- -If the formal parameter ``f`` is of type ``var T`` in addition to the ordinary -type checking, the argument is checked to be an `l-value`:idx:. ``var T`` -matches better than just ``T`` then. +If the formal parameter ``f`` is of type ``var T`` (or ``out T``) +in addition to the ordinary +type checking, the argument is checked to be an `l-value`:idx:. +``var T`` (or ``out T``) matches better than just ``T`` then. .. code-block:: nim proc sayHi(x: int): string = @@ -2482,6 +2483,17 @@ matches better than just ``T`` then. # 13 +An l-value matches ``var T`` and ``out T`` equally well, hence +the following is ambiguous: + +.. code-block:: nim + + proc p(x: out string) = x = "" + proc p(x: var string) = x = "" + var v: string + p(v) # ambiguous + + Lazy type resolution for untyped -------------------------------- @@ -3711,6 +3723,46 @@ location is derived from the second parameter (called ``varTy[T, 2]`` which is incompatible with ``varTy[T, 1]``. +Out parameters +-------------- + +The type of a parameter may be ``out T``: + +.. code-block:: nim + proc divmod(a, b: int; res, remainder: out int) = + res = a div b + remainder = a mod b + + var + x, y: int + + divmod(8, 5, x, y) # modifies x and y + assert x == 1 + assert y == 3 + +In the example, ``res`` and ``remainder`` are `out parameters`. +Out parameters can be modified by the procedure and the changes are +visible to the caller. The argument passed to an out parameter has to be +an l-value. It is enforced that every code path assigns a value to +every `out` parameter before the routine returns and before a read from +the `out` parameter can be performed. This is the distinguishing difference +between an `out` parameter and a `var` parameter. An `out` parameter is an +output parameter, a `var` parameter is an input-output parameter. + +There is no semantic difference +between ``proc p(x: out T) {.raises: [].}`` and ``proc p(): T {.raises: [].}`` +but how these constructs are mapped to machine code might differ. +An `out` parameter is mapped to a pointer for a routine imported from C/C++, +for example: + +.. code-block:: nim + + type Stat {.importc: "stat_t", header: "stat.h".} = object + proc stat(path: cstring; result: out Stat) {.importc, header: "stat.h".} + ## mapped to 'ptr Stat' + + + NRVO ---- @@ -4230,9 +4282,7 @@ error message from ``e``, and for such situations it is enough to use Custom exceptions ----------------- -Is it possible to create custom exceptions. These make it easy to distinguish between exceptions raised by nim and those from your own code. - -A custom exception is a custom type: +Is it possible to create custom exceptions. A custom exception is a custom type: .. code-block:: nim type @@ -4782,7 +4832,7 @@ of "typedesc"-ness is stripped off: Generic inference restrictions ------------------------------ -The types ``var T`` and ``typedesc[T]`` cannot be inferred in a generic +The types ``var T``, ``out T`` and ``typedesc[T]`` cannot be inferred in a generic instantiation. The following is not allowed: .. code-block:: nim @@ -5931,7 +5981,7 @@ noSideEffect pragma The ``noSideEffect`` pragma is used to mark a proc/iterator to have no side effects. This means that the proc/iterator only changes locations that are reachable from its parameters and the return value only depends on the -arguments. If none of its parameters have the type ``var T`` +arguments. If none of its parameters have the type ``var T`` or ``out T`` or ``ref T`` or ``ptr T`` this means no locations are modified. It is a static error to mark a proc/iterator to have no side effect if the compiler cannot verify this. @@ -6613,7 +6663,7 @@ during semantic analysis: Emit pragma ----------- The ``emit`` pragma can be used to directly affect the output of the -compiler's code generator. So it makes your code unportable to other code +compiler's code generator. The code is then unportable to other code generators/backends. Its usage is highly discouraged! However, it can be extremely useful for interfacing with `C++`:idx: or `Objective C`:idx: code. From 8fa0d39524fc83f02f67f8d4352f1a93b7f1e5f3 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 31 May 2020 20:20:39 +0200 Subject: [PATCH 07/15] more refinements for 'out' parameters --- compiler/ast.nim | 2 +- compiler/parampatterns.nim | 2 +- compiler/parser.nim | 10 ++++------ compiler/renderer.nim | 7 +++++++ compiler/sempass2.nim | 6 ++++-- compiler/semtypes.nim | 12 ++++++++---- compiler/typesrenderer.nim | 5 +++++ compiler/vm.nim | 2 +- compiler/vmdeps.nim | 7 ++++++- lib/core/macros.nim | 2 +- 10 files changed, 38 insertions(+), 17 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 4d2b2faeff8b3..52de3aee458d9 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -209,7 +209,7 @@ type nkPtrTy, # ``ptr T`` nkVarTy, # ``var T`` nkConstTy, # ``const T`` - nkMutableTy, # ``mutable T`` + nkOutTy, # ``out T`` nkDistinctTy, # distinct type nkProcTy, # proc type nkIteratorTy, # iterator type diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim index 5e76b758cc503..fe56a236c45b3 100644 --- a/compiler/parampatterns.nim +++ b/compiler/parampatterns.nim @@ -284,7 +284,7 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult of nkStmtList, nkStmtListExpr: if n.typ != nil: result = isAssignable(owner, n.lastSon, isUnsafeAddr) - of nkVarTy: + of nkVarTy, nkOutTy: # XXX: The fact that this is here is a bit of a hack. # The goal is to allow the use of checks such as "foo(var T)" # within concepts. Semantically, it's not correct to say that diff --git a/compiler/parser.nim b/compiler/parser.nim index 9d1f6f97a5ca3..110310933774b 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -740,10 +740,6 @@ proc commandParam(p: var TParser, isFirstParam: var bool; mode: TPrimaryMode): P result.add(parseExpr(p)) isFirstParam = false -const - tkTypeClasses = {tkRef, tkPtr, tkVar, tkStatic, tkType, - tkEnum, tkTuple, tkObject, tkProc} - proc commandExpr(p: var TParser; r: PNode; mode: TPrimaryMode): PNode = result = newNodeP(nkCommand, p) result.add(r) @@ -797,7 +793,8 @@ proc primarySuffix(p: var TParser, r: PNode, break result = namedParams(p, result, nkCurlyExpr, tkCurlyRi) of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast, - tkOpr, tkDotDot, tkTypeClasses - {tkRef, tkPtr}: + tkOpr, tkDotDot, tkVar, tkOut, tkStatic, tkType, + tkEnum, tkTuple, tkObject, tkProc: # XXX: In type sections we allow the free application of the # command syntax, with the exception of expressions such as # `foo ref` or `foo ptr`. Unfortunately, these two are also @@ -1270,7 +1267,7 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode = result.add(primary(p, pmNormal)) return - case p.tok.tokType: + case p.tok.tokType of tkTuple: result = parseTuple(p, mode == pmTypeDef) of tkProc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}, nkLambda) of tkFunc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}, nkFuncDef) @@ -1303,6 +1300,7 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode = optInd(p, result) result.add(primary(p, pmNormal)) of tkVar: result = parseTypeDescKAux(p, nkVarTy, mode) + of tkOut: result = parseTypeDescKAux(p, nkOutTy, mode) of tkRef: result = parseTypeDescKAux(p, nkRefTy, mode) of tkPtr: result = parseTypeDescKAux(p, nkPtrTy, mode) of tkDistinct: result = parseTypeDescKAux(p, nkDistinctTy, mode) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index b892a3e2f2459..adf8dd193c650 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -482,6 +482,7 @@ proc lsub(g: TSrcGen; n: PNode): int = of nkRefTy: result = (if n.len > 0: lsub(g, n[0])+1 else: 0) + len("ref") of nkPtrTy: result = (if n.len > 0: lsub(g, n[0])+1 else: 0) + len("ptr") of nkVarTy: result = (if n.len > 0: lsub(g, n[0])+1 else: 0) + len("var") + of nkOutTy: result = (if n.len > 0: lsub(g, n[0])+1 else: 0) + len("out") of nkDistinctTy: result = len("distinct") + (if n.len > 0: lsub(g, n[0])+1 else: 0) if n.len > 1: @@ -1225,6 +1226,12 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = gsub(g, n[0]) else: put(g, tkVar, "var") + of nkOutTy: + if n.len > 0: + putWithSpace(g, tkOut, "out") + gsub(g, n[0]) + else: + put(g, tkOut, "out") of nkDistinctTy: if n.len > 0: putWithSpace(g, tkDistinct, "distinct") diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 0e2918cf7a258..671d8246a20fd 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -87,8 +87,8 @@ proc `==`(a, b: TLockLevel): bool {.borrow.} proc max(a, b: TLockLevel): TLockLevel {.borrow.} proc isLocalVar(a: PEffects, s: PSym): bool = - s.kind in {skVar, skResult} and sfGlobal notin s.flags and - s.owner == a.owner and s.typ != nil + s.kind in {skVar, skResult, skParam} and sfGlobal notin s.flags and + s.owner == a.owner and s.typ != nil and (s.kind != skParam or s.typ.kind == tyOut) proc getLockLevel(t: PType): TLockLevel = var t = t @@ -1182,6 +1182,8 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) = if isSinkTypeForParam(typ) or (t.config.selectedGC in {gcArc, gcOrc} and isClosure(typ.skipTypes(abstractInst))): createTypeBoundOps(t, typ, param.info) + if typ.kind == tyOut and param.id notin t.init: + message(g.config, param.info, warnProveInit, param.name.s) if not isEmptyType(s.typ[0]) and (s.typ[0].requiresInit or s.typ[0].skipTypes(abstractInst).kind == tyVar) and diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index abbd30284e974..3899fa791b36c 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -193,16 +193,16 @@ proc semVarargs(c: PContext, n: PNode, prev: PType): PType = localError(c.config, n.info, errXExpectsOneTypeParam % "varargs") addSonSkipIntLit(result, errorType(c)) -proc semVarType(c: PContext, n: PNode, prev: PType): PType = +proc semVarOutType(c: PContext, n: PNode, prev: PType; kind: TTypeKind): PType = if n.len == 1: - result = newOrPrevType(tyVar, prev, c) + result = newOrPrevType(kind, prev, c) var base = semTypeNode(c, n[0], nil).skipTypes({tyTypeDesc}) if base.kind in {tyVar, tyOut}: localError(c.config, n.info, "type 'var var' is not allowed") base = base[0] addSonSkipIntLit(result, base) else: - result = newConstraint(c, tyVar) + result = newConstraint(c, kind) proc semDistinct(c: PContext, n: PNode, prev: PType): PType = if n.len == 0: return newConstraint(c, tyDistinct) @@ -1522,6 +1522,7 @@ proc freshType(res, prev: PType): PType {.inline.} = template modifierTypeKindOfNode(n: PNode): TTypeKind = case n.kind of nkVarTy: tyVar + of nkOutTy: tyOut of nkRefTy: tyRef of nkPtrTy: tyPtr of nkStaticTy: tyStatic @@ -1917,7 +1918,8 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = of nkTypeClassTy: result = semTypeClass(c, n, prev) of nkRefTy: result = semAnyRef(c, n, tyRef, prev) of nkPtrTy: result = semAnyRef(c, n, tyPtr, prev) - of nkVarTy: result = semVarType(c, n, prev) + of nkVarTy: result = semVarOutType(c, n, prev, tyVar) + of nkOutTy: result = semVarOutType(c, n, prev, tyOut) of nkDistinctTy: result = semDistinct(c, n, prev) of nkStaticTy: result = semStaticType(c, n[0], prev) of nkIteratorTy: @@ -2047,6 +2049,8 @@ proc processMagicType(c: PContext, m: PSym) = of "owned": setMagicType(c.config, m, tyOwned, c.config.target.ptrSize) incl m.typ.flags, tfHasOwned + of "out": + setMagicType(c.config, m, tyOut, c.config.target.ptrSize) else: localError(c.config, m.info, errTypeExpected) else: localError(c.config, m.info, errTypeExpected) diff --git a/compiler/typesrenderer.nim b/compiler/typesrenderer.nim index 60f9f6603c175..d58d1dc2dcf56 100644 --- a/compiler/typesrenderer.nim +++ b/compiler/typesrenderer.nim @@ -40,6 +40,11 @@ proc renderType(n: PNode): string = result = renderType(n[0]) else: result = "var" + of nkOutTy: + if n.len == 1: + result = renderType(n[0]) + else: + result = "out" of nkRefTy: if n.len == 1: result = "ref." & renderType(n[0]) diff --git a/compiler/vm.nim b/compiler/vm.nim index c15f9e2681de7..82f1193b961ea 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1100,7 +1100,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = of opcGetImpl: decodeB(rkNode) var a = regs[rb].node - if a.kind == nkVarTy: a = a[0] + if a.kind in {nkVarTy, nkOutTy}: a = a[0] if a.kind == nkSym: regs[ra].node = if a.sym.ast.isNil: newNode(nkNilLit) else: copyTree(a.sym.ast) diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index 573bbf93212df..de2c266818491 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -221,10 +221,15 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo; result.add mapTypeToAst(t[0], info) else: result = mapTypeToBracket("var", mVar, t, info) + of tyOut: + if inst: + result = newNodeX(nkOutTy) + result.add mapTypeToAst(t[0], info) + else: + result = mapTypeToBracket("out", mOut, t, info) of tyLent: result = mapTypeToBracket("lent", mBuiltinType, t, info) of tySink: result = mapTypeToBracket("sink", mBuiltinType, t, info) of tySequence: result = mapTypeToBracket("seq", mSeq, t, info) - of tyOut: result = mapTypeToBracket("out", mOut, t, info) of tyProc: if inst: result = newNodeX(nkProcTy) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 0157d109f2285..420a52bac8e65 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -71,7 +71,7 @@ type nnkTupleTy, nnkTupleClassTy, nnkTypeClassTy, nnkStaticTy, nnkRecList, nnkRecCase, nnkRecWhen, nnkRefTy, nnkPtrTy, nnkVarTy, - nnkConstTy, nnkMutableTy, + nnkConstTy, nnkOutTy, nnkDistinctTy, nnkProcTy, nnkIteratorTy, # iterator type From 84c2d239d56d8a210225eddc3b58761df9406ed7 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 31 May 2020 21:09:03 +0200 Subject: [PATCH 08/15] more fixes for 'out' parameters --- compiler/ast.nim | 3 + compiler/semmagic.nim | 3 - compiler/sempass2.nim | 203 +++++++++++++++++++----------------- doc/manual_experimental.rst | 6 +- 4 files changed, 116 insertions(+), 99 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 52de3aee458d9..1b0098f6ce79c 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1934,3 +1934,6 @@ proc toHumanStr*(kind: TSymKind): string = proc toHumanStr*(kind: TTypeKind): string = ## strips leading `tk` result = toHumanStrImpl(kind, 2) + +proc skipAddr*(n: PNode): PNode {.inline.} = + (if n.kind == nkHiddenAddr: n[0] else: n) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 70ef54117541c..c3aa89435d33b 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -42,9 +42,6 @@ type proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode -proc skipAddr(n: PNode): PNode {.inline.} = - (if n.kind == nkHiddenAddr: n[0] else: n) - proc semArrGet(c: PContext; n: PNode; flags: TExprFlags): PNode = result = newNodeI(nkBracketExpr, n.info) for i in 1.. 0: + createTypeBoundOps(tracked, n[1].typ.lastSon, n.info) + createTypeBoundOps(tracked, n[1].typ, n.info) + # new(x, finalizer): Problem: how to move finalizer into 'createTypeBoundOps'? + + elif a.kind == nkSym and a.sym.magic in {mArrGet, mArrPut} and + optStaticBoundsCheck in tracked.currOptions: + checkBounds(tracked, n[1], n[2]) + + if a.kind == nkSym and a.sym.name.s.len > 0 and a.sym.name.s[0] == '=' and + tracked.owner.kind != skMacro: + let opKind = find(AttachedOpToStr, a.sym.name.s.normalize) + if opKind != -1: + # rebind type bounds operations after createTypeBoundOps call + let t = n[1].typ.skipTypes({tyAlias, tyVar, tyOut}) + if a.sym != t.attachedOps[TTypeAttachedOp(opKind)]: + createTypeBoundOps(tracked, t, n.info) + let op = t.attachedOps[TTypeAttachedOp(opKind)] + if op != nil: + n[0].sym = op + + if a.kind != nkSym or a.sym.magic != mRunnableExamples: + for i in 0.. 0: - createTypeBoundOps(tracked, n[1].typ.lastSon, n.info) - createTypeBoundOps(tracked, n[1].typ, n.info) - # new(x, finalizer): Problem: how to move finalizer into 'createTypeBoundOps'? - - elif a.kind == nkSym and a.sym.magic in {mArrGet, mArrPut} and - optStaticBoundsCheck in tracked.currOptions: - checkBounds(tracked, n[1], n[2]) - - if a.kind == nkSym and a.sym.name.s.len > 0 and a.sym.name.s[0] == '=' and - tracked.owner.kind != skMacro: - let opKind = find(AttachedOpToStr, a.sym.name.s.normalize) - if opKind != -1: - # rebind type bounds operations after createTypeBoundOps call - let t = n[1].typ.skipTypes({tyAlias, tyVar, tyOut}) - if a.sym != t.attachedOps[TTypeAttachedOp(opKind)]: - createTypeBoundOps(tracked, t, n.info) - let op = t.attachedOps[TTypeAttachedOp(opKind)] - if op != nil: - n[0].sym = op - - if a.kind != nkSym or a.sym.magic != mRunnableExamples: - for i in 0.. Date: Sun, 31 May 2020 22:39:41 +0200 Subject: [PATCH 09/15] code improvements; added toutparam test --- compiler/msgs.nim | 6 +++++- lib/pure/os.nim | 1 + lib/system.nim | 6 ++++-- lib/system/alloc.nim | 3 ++- lib/system/assertions.nim | 1 + lib/system/gc_common.nim | 5 +++-- lib/system/io.nim | 16 ++++++++-------- lib/system/repr.nim | 1 + lib/system/strmantle.nim | 6 +++--- lib/system/widestrs.nim | 1 + tests/effects/toutparam.nim | 27 +++++++++++++++++++++++++++ 11 files changed, 56 insertions(+), 17 deletions(-) create mode 100644 tests/effects/toutparam.nim diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 0e64d93274184..c4658abcfe406 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -494,8 +494,12 @@ proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string, of warnMin..warnMax: sev = Severity.Warning ignoreMsg = not conf.hasWarn(msg) + if msg in conf.warningAsErrors: + ignoreMsg = false + title = ErrorTitle + else: + title = WarningTitle if not ignoreMsg: writeContext(conf, info) - title = if msg in conf.warningAsErrors: ErrorTitle else: WarningTitle color = WarningColor inc(conf.warnCounter) of hintMin..hintMax: diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 6472d5497bbae..52a2f949ed838 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -1046,6 +1046,7 @@ when defined(windows) or defined(posix) or defined(nintendoswitch): assert quoteShellCommand(["aaa", "", "c d"]) == "aaa \"\" \"c d\"" # can't use `map` pending https://github.com/nim-lang/Nim/issues/8303 + result = "" for i in 0.. 0: result.add " " result.add quoteShell(args[i]) diff --git a/lib/system.nim b/lib/system.nim index 447a42784b2dd..6fc55c726b110 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2107,7 +2107,7 @@ when not defined(js): # Linux 64bit system. -- That's because the stack direction is the other # way around. when declared(nimGC_setStackBottom): - var locals {.volatile.}: pointer + var locals {.volatile, noinit.}: pointer locals = addr(locals) nimGC_setStackBottom(locals) @@ -2276,7 +2276,9 @@ when notJSnotNims: of 2: d = uint(cast[ptr uint16](a + uint(n.offset))[]) of 4: d = uint(cast[ptr uint32](a + uint(n.offset))[]) of 8: d = uint(cast[ptr uint64](a + uint(n.offset))[]) - else: sysAssert(false, "getDiscriminant: invalid n.typ.size") + else: + d = 0'u + sysAssert(false, "getDiscriminant: invalid n.typ.size") return d proc selectBranch(aa: pointer, n: ptr TNimNode): ptr TNimNode = diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim index 7ace0d536028c..95658c49a02ce 100644 --- a/lib/system/alloc.nim +++ b/lib/system/alloc.nim @@ -586,7 +586,8 @@ proc freeBigChunk(a: var MemRegion, c: PBigChunk) = proc getBigChunk(a: var MemRegion, size: int): PBigChunk = sysAssert(size > 0, "getBigChunk 2") var size = size # roundup(size, PageSize) - var fl, sl: int + var fl = 0 + var sl = 0 mappingSearch(size, fl, sl) sysAssert((size and PageMask) == 0, "getBigChunk: unaligned chunk") result = findSuitableBlock(a, fl, sl) diff --git a/lib/system/assertions.nim b/lib/system/assertions.nim index ca3bd7bc1e404..c6283c89ce034 100644 --- a/lib/system/assertions.nim +++ b/lib/system/assertions.nim @@ -11,6 +11,7 @@ proc `$`(x: int): string {.magic: "IntToStr", noSideEffect.} proc `$`(info: InstantiationInfo): string = # The +1 is needed here # instead of overriding `$` (and changing its meaning), consider explicit name. + result = "" result.toLocation(info.filename, info.line, info.column+1) # --------------------------------------------------------------------------- diff --git a/lib/system/gc_common.nim b/lib/system/gc_common.nim index d75ada7911b3e..7f6c41e1b247b 100644 --- a/lib/system/gc_common.nim +++ b/lib/system/gc_common.nim @@ -217,7 +217,7 @@ proc stackSize(stack: ptr GcStack): int {.noinline.} = when nimCoroutines: var pos = stack.pos else: - var pos {.volatile.}: pointer + var pos {.volatile, noinit.}: pointer pos = addr(pos) if pos != nil: @@ -229,6 +229,7 @@ proc stackSize(stack: ptr GcStack): int {.noinline.} = result = 0 proc stackSize(): int {.noinline.} = + result = 0 for stack in gch.stack.items(): result = result + stack.stackSize() @@ -303,7 +304,7 @@ when not defined(useNimRtl): {.pop.} proc isOnStack(p: pointer): bool = - var stackTop {.volatile.}: pointer + var stackTop {.volatile, noinit.}: pointer stackTop = addr(stackTop) var a = cast[ByteAddress](gch.getActiveStack().bottom) var b = cast[ByteAddress](stackTop) diff --git a/lib/system/io.nim b/lib/system/io.nim index b1f6bb61bd40d..dbe4fb5210232 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -424,12 +424,12 @@ proc write*(f: File, b: bool) {.tags: [WriteIOEffect], benign.} = else: write(f, "false") proc write*(f: File, r: float32) {.tags: [WriteIOEffect], benign.} = - var buffer: array[65, char] + var buffer {.noinit.}: array[65, char] discard writeFloatToBuffer(buffer, r) if c_fprintf(f, "%s", buffer[0].addr) < 0: checkErr(f) proc write*(f: File, r: BiggestFloat) {.tags: [WriteIOEffect], benign.} = - var buffer: array[65, char] + var buffer {.noinit.}: array[65, char] discard writeFloatToBuffer(buffer, r) if c_fprintf(f, "%s", buffer[0].addr) < 0: checkErr(f) @@ -591,7 +591,7 @@ when defined(posix) and not defined(nimscript): proc open*(f: var File, filename: string, mode: FileMode = fmRead, - bufSize: int = -1): bool {.tags: [], raises: [], benign.} = + bufSize: int = -1): bool {.tags: [], raises: [], benign.} = ## Opens a file named `filename` with given `mode`. ## ## Default mode is readonly. Returns true if the file could be opened. @@ -605,7 +605,7 @@ proc open*(f: var File, filename: string, # How `fopen` handles opening a directory is not specified in ISO C and # POSIX. We do not want to handle directories as regular files that can # be opened. - var res: Stat + var res {.noinit.}: Stat if c_fstat(getFileHandle(f2), res) >= 0'i32 and modeIsDir(res.st_mode): close(f2) return false @@ -759,7 +759,7 @@ proc readFile*(filename: string): TaintedString {.tags: [ReadIOEffect], benign.} ## Raises an IO exception in case of an error. If you need to call ## this inside a compile time macro you can use `staticRead ## `_. - var f: File + var f: File = nil if open(f, filename): try: result = readAll(f) @@ -772,7 +772,7 @@ proc writeFile*(filename, content: string) {.tags: [WriteIOEffect], benign.} = ## Opens a file named `filename` for writing. Then writes the ## `content` completely to the file and closes the file afterwards. ## Raises an IO exception in case of an error. - var f: File + var f: File = nil if open(f, filename, fmWrite): try: f.write(content) @@ -785,7 +785,7 @@ proc writeFile*(filename: string, content: openArray[byte]) {.since: (1, 1).} = ## Opens a file named `filename` for writing. Then writes the ## `content` completely to the file and closes the file afterwards. ## Raises an IO exception in case of an error. - var f: File + var f: File = nil if open(f, filename, fmWrite): try: f.writeBuffer(unsafeAddr content[0], content.len) @@ -799,7 +799,7 @@ proc readLines*(filename: string, n: Natural): seq[TaintedString] = ## in case of an error. Raises EOF if file does not contain at least `n` lines. ## Available at compile time. A line of text may be delimited by ``LF`` or ``CRLF``. ## The newline character(s) are not part of the returned strings. - var f: File + var f: File = nil if open(f, filename): try: result = newSeq[TaintedString](n) diff --git a/lib/system/repr.nim b/lib/system/repr.nim index 526839aa2d6cb..318e95ebb6e69 100644 --- a/lib/system/repr.nim +++ b/lib/system/repr.nim @@ -102,6 +102,7 @@ proc reprSetAux(result: var string, p: pointer, typ: PNimType) = of 4: u = cast[ptr uint32](p)[] of 8: u = cast[ptr uint64](p)[] else: + u = uint64(0) var a = cast[PByteArray](p) for i in 0 .. typ.size*8-1: if (uint(a[i shr 3]) and (1'u shl (i and 7))) != 0: diff --git a/lib/system/strmantle.nim b/lib/system/strmantle.nim index c3ac5fc1bafb9..cb26833ac40ea 100644 --- a/lib/system/strmantle.nim +++ b/lib/system/strmantle.nim @@ -94,7 +94,7 @@ proc addFloat*(result: var string; x: float) = when nimvm: result.add $x else: - var buffer: array[65, char] + var buffer {.noinit.}: array[65, char] let n = writeFloatToBuffer(buffer, x) result.addCstringN(cstring(buffer[0].addr), n) @@ -131,8 +131,8 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat, i = start sign = 1.0 kdigits, fdigits = 0 - exponent: int - integer: uint64 + exponent = 0 + integer = uint64(0) fracExponent = 0 expSign = 1 firstDigit = -1 diff --git a/lib/system/widestrs.nim b/lib/system/widestrs.nim index 3048de82aef5e..a7a514446b5c9 100644 --- a/lib/system/widestrs.nim +++ b/lib/system/widestrs.nim @@ -63,6 +63,7 @@ proc ord(arg: Utf16Char): int = int(cast[uint16](arg)) proc len*(w: WideCString): int = ## returns the length of a widestring. This traverses the whole string to ## find the binary zero end marker! + result = 0 while int16(w[result]) != 0'i16: inc result const diff --git a/tests/effects/toutparam.nim b/tests/effects/toutparam.nim new file mode 100644 index 0000000000000..61337fb0dc515 --- /dev/null +++ b/tests/effects/toutparam.nim @@ -0,0 +1,27 @@ +discard """ + cmd: '''nim c --warningAsError[Uninit]:on --skipCfg --skipParentCfg $file''' + errormsg: "use explicit initialization of 'x' for clarity [Uninit]" + line: 24 +""" + +proc gah[T](x: out T) = + x = 3 + +proc main = + var a: array[2, int] + var x: int + gah(x) + a[0] = 3 + a[x] = 3 + echo x + +main() + +proc mainB = + var a: array[2, int] + var x: int + a[0] = 3 + a[x] = 3 + echo x + +mainB() From 42b3ec4f9e0a92b328961452500c6b8ee26f045e Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 31 May 2020 23:36:39 +0200 Subject: [PATCH 10/15] coding style improvements, back to nnkMutableTy in order to prevent code breakage --- compiler/ccgexprs.nim | 6 ++---- compiler/nimsets.nim | 32 +++++++++++++------------------- compiler/renderverbatim.nim | 1 + lib/core/macros.nim | 2 +- 4 files changed, 17 insertions(+), 24 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 76944f6a552d2..38f372b635ef2 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -126,9 +126,8 @@ proc genRawSetData(cs: TBitSet, size: int): Rope = result = intLiteral(cast[BiggestInt](bitSetToWord(cs, size))) proc genSetNode(p: BProc, n: PNode): Rope = - var cs: TBitSet var size = int(getSize(p.config, n.typ)) - toBitSet(p.config, n, cs) + let cs = toBitSet(p.config, n) if size > 8: let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels) result = p.module.tmpBase & rope(id) @@ -2959,8 +2958,7 @@ proc genBracedInit(p: BProc, n: PNode; isConst: bool): Rope = ty = skipTypes(n.typ, abstractInstOwned + {tyStatic}).kind case ty of tySet: - var cs: TBitSet - toBitSet(p.config, n, cs) + let cs = toBitSet(p.config, n) result = genRawSetData(cs, int(getSize(p.config, n.typ))) of tySequence: if optSeqDestructors in p.config.globalOptions: diff --git a/compiler/nimsets.nim b/compiler/nimsets.nim index 3876a114ef06f..8683604af2a9c 100644 --- a/compiler/nimsets.nim +++ b/compiler/nimsets.nim @@ -58,18 +58,18 @@ proc someInSet*(s: PNode, a, b: PNode): bool = return true result = false -proc toBitSet*(conf: ConfigRef; s: PNode, b: var TBitSet) = +proc toBitSet*(conf: ConfigRef; s: PNode): TBitSet = var first, j: Int128 first = firstOrd(conf, s.typ[0]) - bitSetInit(b, int(getSize(conf, s.typ))) + bitSetInit(result, int(getSize(conf, s.typ))) for i in 0.. Date: Mon, 1 Jun 2020 01:19:17 +0200 Subject: [PATCH 11/15] make tests green --- lib/std/stackframes.nim | 6 +++--- tests/assert/tassert_c.nim | 7 ++++--- tests/init/tuninit1.nim | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/std/stackframes.nim b/lib/std/stackframes.nim index dbd866536c930..28be7ce11f25b 100644 --- a/lib/std/stackframes.nim +++ b/lib/std/stackframes.nim @@ -4,7 +4,7 @@ const NimStackTraceMsgs = compileOption("stacktraceMsgs") template procName*(): string = ## returns current C/C++ function name when defined(c) or defined(cpp): - var name {.inject.}: cstring + var name {.inject, noinit.}: cstring {.emit: "`name` = __func__;".} $name @@ -12,7 +12,7 @@ template getPFrame*(): PFrame = ## avoids a function call (unlike `getFrame()`) block: when NimStackTrace: - var framePtr {.inject.}: PFrame + var framePtr {.inject, noinit.}: PFrame {.emit: "`framePtr` = &FR_;".} framePtr @@ -21,7 +21,7 @@ template setFrameMsg*(msg: string, prefix = " ") = ## in a given PFrame. Noop unless passing --stacktraceMsgs and --stacktrace when NimStackTrace and NimStackTraceMsgs: block: - var fr {.inject.}: PFrame + var fr {.inject, noinit.}: PFrame {.emit: "`fr` = &FR_;".} # consider setting a custom upper limit on size (analog to stack overflow) frameMsgBuf.setLen fr.frameMsgLen diff --git a/tests/assert/tassert_c.nim b/tests/assert/tassert_c.nim index cbb565f842694..c6a2eadb191f6 100644 --- a/tests/assert/tassert_c.nim +++ b/tests/assert/tassert_c.nim @@ -6,8 +6,8 @@ discard """ const expected = """ tassert_c.nim(35) tassert_c tassert_c.nim(34) foo -assertions.nim(29) failedAssertImpl -assertions.nim(22) raiseAssert +assertions.nim(30) failedAssertImpl +assertions.nim(23) raiseAssert fatal.nim(49) sysFatal""" proc tmatch(x, p: string): bool = @@ -36,4 +36,5 @@ try: except AssertionDefect: let e = getCurrentException() let trace = e.getStackTrace - if tmatch(trace, expected): echo true else: echo "wrong trace:\n" & trace + if tmatch(trace, expected): echo true + else: echo "wrong trace:\n" & trace diff --git a/tests/init/tuninit1.nim b/tests/init/tuninit1.nim index 67c0c4d8b1071..fe91733ffc3a6 100644 --- a/tests/init/tuninit1.nim +++ b/tests/init/tuninit1.nim @@ -1,5 +1,5 @@ discard """ - nimout: "Warning: 'y' might not have been initialized [Uninit]" + nimout: "Warning: use explicit initialization of 'y' for clarity [Uninit]" line:34 action: compile """ From 01163ded6b938ed9d7a3cd53b845dca43d4a13dd Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 1 Jun 2020 08:35:43 +0200 Subject: [PATCH 12/15] algorithm.nim: set result explicitly --- lib/pure/algorithm.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index 91f2f41b8ed33..55a43d85738f6 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -187,6 +187,7 @@ proc binarySearch*[T, K](a: openArray[T], key: K, else: return -1 + result = 0 if (len and (len - 1)) == 0: # when `len` is a power of 2, a faster shr can be used. var step = len shr 1 From 85133a52ce4bc569a6e09528b3873ba6138b9443 Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 22 Jun 2020 21:27:07 +0200 Subject: [PATCH 13/15] remove out parameters and bring the PR into a mergable state --- compiler/ast.nim | 10 +++--- compiler/ccgcalls.nim | 14 ++++----- compiler/ccgexprs.nim | 46 ++++++++++++++-------------- compiler/ccgreset.nim | 2 +- compiler/ccgtypes.nim | 16 +++++----- compiler/cgmeth.nim | 2 +- compiler/dfa.nim | 7 +++-- compiler/evalffi.nim | 10 +++--- compiler/guards.nim | 2 +- compiler/jsgen.nim | 14 ++++----- compiler/jstypes.nim | 2 +- compiler/lambdalifting.nim | 2 +- compiler/liftdestructors.nim | 4 +-- compiler/lineinfos.nim | 2 +- compiler/lowerings.nim | 4 +-- compiler/parampatterns.nim | 14 ++++----- compiler/parser.nim | 7 +++-- compiler/renderer.nim | 13 ++------ compiler/semcall.nim | 2 +- compiler/semdata.nim | 4 +-- compiler/semexprs.nim | 46 ++++++++++++++-------------- compiler/semmagic.nim | 6 ++-- compiler/semobjconstr.nim | 2 +- compiler/sempass2.nim | 24 ++++++++------- compiler/semstmts.nim | 24 +++++++-------- compiler/semtypes.nim | 10 ++---- compiler/semtypinst.nim | 4 +-- compiler/sighashes.nim | 2 +- compiler/sigmatch.nim | 32 +++++++++---------- compiler/sinkparameter_inference.nim | 2 +- compiler/sizealignoffsetimpl.nim | 2 +- compiler/spawn.nim | 4 +-- compiler/suggest.nim | 6 ++-- compiler/transf.nim | 8 ++--- compiler/types.nim | 27 ++++++++-------- compiler/typesrenderer.nim | 5 --- compiler/vm.nim | 2 +- compiler/vmdeps.nim | 6 ---- compiler/vmgen.nim | 6 ++-- compiler/writetracking.nim | 6 ++-- tests/effects/toutparam.nim | 1 + 41 files changed, 193 insertions(+), 209 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 9cb07cc6a461e..66a1a253b9e20 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -209,7 +209,7 @@ type nkPtrTy, # ``ptr T`` nkVarTy, # ``var T`` nkConstTy, # ``const T`` - nkOutTy, # ``out T`` + nkMutableTy, # ``mutable T`` nkDistinctTy, # distinct type nkProcTy, # proc type nkIteratorTy, # iterator type @@ -434,7 +434,7 @@ type # instantiation and prior to this it has the potential to # be any type. - tyOut + tyOptDeprecated # 'out' parameter. Comparable to a 'var' parameter but every # path must assign a value to it before it can be read from. @@ -460,7 +460,7 @@ const tyMetaTypes* = {tyGenericParam, tyTypeDesc, tyUntyped} + tyTypeClasses tyUserTypeClasses* = {tyUserTypeClass, tyUserTypeClassInst} # consider renaming as `tyAbstractVarRange` - abstractVarRange* = {tyGenericInst, tyRange, tyVar, tyOut, tyDistinct, tyOrdinal, + abstractVarRange* = {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias, tyInferred, tySink, tyOwned} type @@ -985,13 +985,13 @@ const tyGenericParam} StructuralEquivTypes*: TTypeKinds = {tyNil, tyTuple, tyArray, - tySet, tyRange, tyPtr, tyRef, tyVar, tyOut, tyLent, tySequence, tyProc, tyOpenArray, + tySet, tyRange, tyPtr, tyRef, tyVar, tyLent, tySequence, tyProc, tyOpenArray, tyVarargs} ConcreteTypes*: TTypeKinds = { # types of the expr that may occur in:: # var x = expr tyBool, tyChar, tyEnum, tyArray, tyObject, - tySet, tyTuple, tyRange, tyPtr, tyRef, tyVar, tyOut, tyLent, tySequence, tyProc, + tySet, tyTuple, tyRange, tyPtr, tyRef, tyVar, tyLent, tySequence, tyProc, tyPointer, tyOpenArray, tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128, tyUInt..tyUInt64} diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 6442cd2ccc745..80f02b6c36866 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -178,10 +178,10 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope = result = "($4*)($1)+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dest] of tyString, tySequence: let atyp = skipTypes(a.t, abstractInst) - if formalType.skipTypes(abstractInst).kind in {tyVar, tyOut} and atyp.kind == tyString and + if formalType.skipTypes(abstractInst).kind in {tyVar} and atyp.kind == tyString and optSeqDestructors in p.config.globalOptions: linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)]) - if atyp.kind in {tyVar, tyOut} and not compileToCpp(p.module): + if atyp.kind in {tyVar} and not compileToCpp(p.module): result = "($5*)(*$1)$4+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dataField(p), dest] else: result = "($5*)$1$4+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dataField(p), dest] @@ -194,10 +194,10 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope = result = "$1, $1Len_0" % [rdLoc(a)] of tyString, tySequence: let ntyp = skipTypes(n.typ, abstractInst) - if formalType.skipTypes(abstractInst).kind in {tyVar, tyOut} and ntyp.kind == tyString and + if formalType.skipTypes(abstractInst).kind in {tyVar} and ntyp.kind == tyString and optSeqDestructors in p.config.globalOptions: linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)]) - if ntyp.kind in {tyVar, tyOut} and not compileToCpp(p.module): + if ntyp.kind in {tyVar} and not compileToCpp(p.module): var t: TLoc t.r = "(*$1)" % [a.rdLoc] result = "(*$1)$3, $2" % [a.rdLoc, lenExpr(p, t), dataField(p)] @@ -232,7 +232,7 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): Rope = elif ccgIntroducedPtr(p.config, param, call[0].typ[0]): initLocExpr(p, n, a) result = addrLoc(p.config, a) - elif p.module.compileToCpp and param.typ.kind in {tyVar, tyOut} and + elif p.module.compileToCpp and param.typ.kind in {tyVar} and n.kind == nkHiddenAddr: initLocExprSingleUse(p, n[0], a) # if the proc is 'importc'ed but not 'importcpp'ed then 'var T' still @@ -372,7 +372,7 @@ proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope = assert(paramType.kind == nkSym) if paramType.typ.isCompileTimeOnly: result = nil - elif typ[i].kind in {tyVar, tyOut} and ri[i].kind == nkHiddenAddr: + elif typ[i].kind in {tyVar} and ri[i].kind == nkHiddenAddr: result = genArgNoParam(p, ri[i][0]) else: result = genArgNoParam(p, ri[i]) #, typ.n[i].sym) @@ -449,7 +449,7 @@ proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): Rope = var ri = ri[i] while ri.kind == nkObjDownConv: ri = ri[0] let t = typ[i].skipTypes({tyGenericInst, tyAlias, tySink}) - if t.kind in {tyVar, tyOut}: + if t.kind in {tyVar}: let x = if ri.kind == nkHiddenAddr: ri[0] else: ri if x.typ.kind == tyPtr: result = genArgNoParam(p, x) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 030a4ef3dc140..a595290210bb6 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -155,7 +155,7 @@ proc getStorageLoc(n: PNode): TStorageLoc = else: result = OnUnknown of nkDerefExpr, nkHiddenDeref: case n[0].typ.kind - of tyVar, tyLent, tyOut: result = OnUnknown + of tyVar, tyLent: result = OnUnknown of tyPtr: result = OnStack of tyRef: result = OnHeap else: doAssert(false, "getStorageLoc") @@ -367,7 +367,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = else: linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) of tyPtr, tyPointer, tyChar, tyBool, tyEnum, tyCString, - tyInt..tyUInt64, tyRange, tyVar, tyOut, tyLent, tyNil: + tyInt..tyUInt64, tyRange, tyVar, tyLent, tyNil: linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) else: internalError(p.config, "genAssignment: " & $ty.kind) @@ -412,7 +412,7 @@ proc genDeepCopy(p: BProc; dest, src: TLoc) = else: linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) of tyPointer, tyChar, tyBool, tyEnum, tyCString, - tyInt..tyUInt64, tyRange, tyVar, tyOut, tyLent: + tyInt..tyUInt64, tyRange, tyVar, tyLent: linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) else: internalError(p.config, "genDeepCopy: " & $ty.kind) @@ -675,7 +675,7 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) = proc isCppRef(p: BProc; typ: PType): bool {.inline.} = result = p.module.compileToCpp and - skipTypes(typ, abstractInstOwned).kind in {tyVar, tyOut} and + skipTypes(typ, abstractInstOwned).kind in {tyVar} and tfVarIsPtr notin skipTypes(typ, abstractInstOwned).flags proc genDeref(p: BProc, e: PNode, d: var TLoc) = @@ -692,7 +692,7 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) = if typ.kind in {tyUserTypeClass, tyUserTypeClassInst} and typ.isResolvedUserTypeClass: typ = typ.lastSon typ = typ.skipTypes(abstractInstOwned) - if typ.kind in {tyVar, tyOut} and tfVarIsPtr notin typ.flags and p.module.compileToCpp and e[0].kind == nkHiddenAddr: + if typ.kind in {tyVar} and tfVarIsPtr notin typ.flags and p.module.compileToCpp and e[0].kind == nkHiddenAddr: initLocExprSingleUse(p, e[0][0], d) return else: @@ -704,7 +704,7 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) = case typ.kind of tyRef: d.storage = OnHeap - of tyVar, tyOut, tyLent: + of tyVar, tyLent: d.storage = OnUnknown if tfVarIsPtr notin typ.flags and p.module.compileToCpp and e.kind == nkHiddenDeref: @@ -715,7 +715,7 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) = else: internalError(p.config, e.info, "genDeref " & $typ.kind) elif p.module.compileToCpp: - if typ.kind in {tyVar, tyOut} and tfVarIsPtr notin typ.flags and + if typ.kind in {tyVar} and tfVarIsPtr notin typ.flags and e.kind == nkHiddenDeref: putIntoDest(p, d, e, rdLoc(a), a.storage) return @@ -757,7 +757,7 @@ proc genTupleElem(p: BProc, e: PNode, d: var TLoc) = a: TLoc i: int initLocExpr(p, e[0], a) - let tupType = a.t.skipTypes(abstractInst+{tyVar, tyOut}) + let tupType = a.t.skipTypes(abstractInst+{tyVar}) assert tupType.kind == tyTuple d.inheritLocation(a) discard getTypeDesc(p.module, a.t) # fill the record's fields.loc @@ -1167,7 +1167,7 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = var a, b, dest, tmpL, call: TLoc initLocExpr(p, e[1], a) initLocExpr(p, e[2], b) - let seqType = skipTypes(e[1].typ, {tyVar, tyOut}) + let seqType = skipTypes(e[1].typ, {tyVar}) initLoc(call, locCall, e, OnHeap) if not p.module.compileToCpp: const seqAppendPattern = "($2) #incrSeqV3((TGenericSeq*)($1), $3)" @@ -1198,7 +1198,7 @@ proc genReset(p: BProc, n: PNode) = when false: linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n", [addrLoc(p.config, a), - genTypeInfo(p.module, skipTypes(a.t, {tyVar, tyOut}), n.info)]) + genTypeInfo(p.module, skipTypes(a.t, {tyVar}), n.info)]) proc genDefault(p: BProc; n: PNode; d: var TLoc) = if d.k == locNone: getTemp(p, n.typ, d, needsInit=true) @@ -1536,9 +1536,9 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) = var r = rdLoc(a) var nilCheck: Rope = nil var t = skipTypes(a.t, abstractInstOwned) - while t.kind in {tyVar, tyOut, tyLent, tyPtr, tyRef}: - if t.kind notin {tyVar, tyOut, tyLent}: nilCheck = r - if t.kind notin {tyVar, tyOut, tyLent} or not p.module.compileToCpp: + while t.kind in {tyVar, tyLent, tyPtr, tyRef}: + if t.kind notin {tyVar, tyLent}: nilCheck = r + if t.kind notin {tyVar, tyLent} or not p.module.compileToCpp: r = ropecg(p.module, "(*$1)", [r]) t = skipTypes(t.lastSon, typedescInst+{tyOwned}) discard getTypeDesc(p.module, t) @@ -1613,9 +1613,9 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) = proc rdMType(p: BProc; a: TLoc; nilCheck: var Rope): Rope = result = rdLoc(a) var t = skipTypes(a.t, abstractInst) - while t.kind in {tyVar, tyOut, tyLent, tyPtr, tyRef}: - if t.kind notin {tyVar, tyOut, tyLent}: nilCheck = result - if t.kind notin {tyVar, tyOut, tyLent} or not p.module.compileToCpp: + while t.kind in {tyVar, tyLent, tyPtr, tyRef}: + if t.kind notin {tyVar, tyLent}: nilCheck = result + if t.kind notin {tyVar, tyLent} or not p.module.compileToCpp: result = "(*$1)" % [result] t = skipTypes(t.lastSon, abstractInst) discard getTypeDesc(p.module, t) @@ -1712,7 +1712,7 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) = if x.kind in {nkAddr, nkHiddenAddr}: x = x[0] initLocExpr(p, x, a) initLocExpr(p, e[2], b) - let t = skipTypes(e[1].typ, {tyVar, tyOut}) + let t = skipTypes(e[1].typ, {tyVar}) initLoc(call, locCall, e, OnHeap) if not p.module.compileToCpp: @@ -2006,7 +2006,7 @@ proc genRangeChck(p: BProc, n: PNode, d: var TLoc) = [getTypeDesc(p.module, dest), rdCharLoc(a)], a.storage) proc genConv(p: BProc, e: PNode, d: var TLoc) = - let destType = e.typ.skipTypes({tyVar, tyOut, tyLent, tyGenericInst, tyAlias, tySink}) + let destType = e.typ.skipTypes({tyVar, tyLent, tyGenericInst, tyAlias, tySink}) if sameBackendType(destType, e[1].typ): expr(p, e[1], d) else: @@ -2160,7 +2160,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = const opr: array[mInc..mDec, string] = ["+=", "-="] const fun64: array[mInc..mDec, string] = ["nimAddInt64", "nimSubInt64"] const fun: array[mInc..mDec, string] = ["nimAddInt","nimSubInt"] - let underlying = skipTypes(e[1].typ, {tyGenericInst, tyAlias, tySink, tyVar, tyOut, tyLent, tyRange, tyDistinct}) + let underlying = skipTypes(e[1].typ, {tyGenericInst, tyAlias, tySink, tyVar, tyLent, tyRange, tyDistinct}) if optOverflowCheck notin p.options or underlying.kind in {tyUInt..tyUInt64}: binaryStmt(p, e, d, opr[op]) else: @@ -2170,7 +2170,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = initLocExpr(p, e[1], a) initLocExpr(p, e[2], b) - let ranged = skipTypes(e[1].typ, {tyGenericInst, tyAlias, tySink, tyVar, tyOut, tyLent}) + let ranged = skipTypes(e[1].typ, {tyGenericInst, tyAlias, tySink, tyVar, tyLent}) let res = binaryArithOverflowRaw(p, ranged, a, b, if underlying.kind == tyInt64: fun64[op] else: fun[op]) @@ -2497,7 +2497,7 @@ proc downConv(p: BProc, n: PNode, d: var TLoc) = var a: TLoc initLocExpr(p, arg, a) var r = rdLoc(a) - let isRef = skipTypes(arg.typ, abstractInstOwned).kind in {tyRef, tyPtr, tyVar, tyOut, tyLent} + let isRef = skipTypes(arg.typ, abstractInstOwned).kind in {tyRef, tyPtr, tyVar, tyLent} if isRef: r.add("->Sup") else: @@ -2509,7 +2509,7 @@ proc downConv(p: BProc, n: PNode, d: var TLoc) = # (see bug #837). However sometimes using a temporary is not correct: # init(TFigure(my)) # where it is passed to a 'var TFigure'. We test # this by ensuring the destination is also a pointer: - if d.k == locNone and skipTypes(n.typ, abstractInstOwned).kind in {tyRef, tyPtr, tyVar, tyOut, tyLent}: + if d.k == locNone and skipTypes(n.typ, abstractInstOwned).kind in {tyRef, tyPtr, tyVar, tyLent}: getTemp(p, n.typ, d) linefmt(p, cpsStmts, "$1 = &$2;$n", [rdLoc(d), r]) else: @@ -2758,7 +2758,7 @@ proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo): Rope = of tyBool: result = rope"NIM_FALSE" of tyEnum, tyChar, tyInt..tyInt64, tyUInt..tyUInt64: result = rope"0" of tyFloat..tyFloat128: result = rope"0.0" - of tyCString, tyVar, tyOut, tyLent, tyPointer, tyPtr, tyUntyped, + of tyCString, tyVar, tyLent, tyPointer, tyPtr, tyUntyped, tyTyped, tyTypeDesc, tyStatic, tyRef, tyNil: result = rope"NIM_NIL" of tyString, tySequence: diff --git a/compiler/ccgreset.nim b/compiler/ccgreset.nim index 644c0985f10f0..ef1505f5799d8 100644 --- a/compiler/ccgreset.nim +++ b/compiler/ccgreset.nim @@ -85,7 +85,7 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) = lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [accessor]) of tyChar, tyBool, tyEnum, tyInt..tyUInt64: lineCg(p, cpsStmts, "$1 = 0;$n", [accessor]) - of tyCString, tyPointer, tyPtr, tyVar, tyOut, tyLent: + of tyCString, tyPointer, tyPtr, tyVar, tyLent: lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [accessor]) else: discard diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index ab7cf6ece47c7..11743499d7d20 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -176,7 +176,7 @@ proc mapType(conf: ConfigRef; typ: PType): TCTypeKind = of 8: result = ctInt64 else: result = ctInt32 of tyRange: result = mapType(conf, typ[0]) - of tyPtr, tyVar, tyOut, tyLent, tyRef: + of tyPtr, tyVar, tyLent, tyRef: var base = skipTypes(typ.lastSon, typedescInst) case base.kind of tyOpenArray, tyArray, tyVarargs, tyUncheckedArray: result = ctPtrToArray @@ -225,7 +225,7 @@ proc isInvalidReturnType(conf: ConfigRef; rettype: PType): bool = case mapType(conf, rettype) of ctArray: result = not (skipTypes(rettype, typedescInst).kind in - {tyVar, tyOut, tyLent, tyRef, tyPtr}) + {tyVar, tyLent, tyRef, tyPtr}) of ctStruct: let t = skipTypes(rettype, typedescInst) if rettype.isImportedCppType or t.isImportedCppType: return false @@ -440,7 +440,7 @@ $3endif$N """, [getTypeDescAux(m, t.skipTypes(abstractInst)[0], check), result, rope"#"]) proc paramStorageLoc(param: PSym): TStorageLoc = - if param.typ.skipTypes({tyVar, tyOut, tyLent, tyTypeDesc}).kind notin { + if param.typ.skipTypes({tyVar, tyLent, tyTypeDesc}).kind notin { tyArray, tyOpenArray, tyVarargs}: result = OnStack else: @@ -474,11 +474,11 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope, params.add(param.loc.r) # declare the len field for open arrays: var arr = param.typ - if arr.kind in {tyVar, tyOut, tyLent, tySink}: arr = arr.lastSon + if arr.kind in {tyVar, tyLent, tySink}: arr = arr.lastSon var j = 0 while arr.kind in {tyOpenArray, tyVarargs}: # this fixes the 'sort' bug: - if param.typ.kind in {tyVar, tyOut, tyLent}: param.loc.storage = OnUnknown + if param.typ.kind in {tyVar, tyLent}: param.loc.storage = OnUnknown # need to pass hidden parameter: params.addf(", NI $1Len_$2", [param.loc.r, j.rope]) inc(j) @@ -700,8 +700,8 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope = excl(check, t.id) return case t.kind - of tyRef, tyPtr, tyVar, tyOut, tyLent: - var star = if t.kind in {tyVar, tyOut} and tfVarIsPtr notin origTyp.flags and + of tyRef, tyPtr, tyVar, tyLent: + var star = if t.kind in {tyVar} and tfVarIsPtr notin origTyp.flags and compileToCpp(m): "&" else: "*" var et = origTyp.skipTypes(abstractInst).lastSon var etB = et.skipTypes(abstractInst) @@ -1372,7 +1372,7 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope = else: case t.kind of tyEmpty, tyVoid: result = rope"0" - of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar, tyOut, tyLent: + of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar, tyLent: genTypeInfoAuxBase(m, t, t, result, rope"0", info) of tyStatic: if t.n != nil: result = genTypeInfo(m, lastSon t, info) diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim index 6ffd72815039f..edf9db3833ddd 100644 --- a/compiler/cgmeth.nim +++ b/compiler/cgmeth.nim @@ -67,7 +67,7 @@ proc sameMethodBucket(a, b: PSym; multiMethods: bool): MethodResult = while true: aa = skipTypes(aa, {tyGenericInst, tyAlias}) bb = skipTypes(bb, {tyGenericInst, tyAlias}) - if aa.kind == bb.kind and aa.kind in {tyVar, tyOut, tyPtr, tyRef, tyLent}: + if aa.kind == bb.kind and aa.kind in {tyVar, tyPtr, tyRef, tyLent}: aa = aa.lastSon bb = bb.lastSon else: diff --git a/compiler/dfa.nim b/compiler/dfa.nim index 3ac980edaa7b5..c393b2c8198b5 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -714,9 +714,10 @@ proc genCall(c: var Con; n: PNode) = inc c.inCall for i in 1.. 0 and canRaiseConservative(n[0]): # we generate the instruction sequence: diff --git a/compiler/evalffi.nim b/compiler/evalffi.nim index b79c571a3be06..f89451f514fe2 100644 --- a/compiler/evalffi.nim +++ b/compiler/evalffi.nim @@ -92,7 +92,7 @@ proc mapType(conf: ConfigRef, t: ast.PType): ptr libffi.Type = else: result = nil of tyFloat, tyFloat64: result = addr libffi.type_double of tyFloat32: result = addr libffi.type_float - of tyVar, tyOut, tyLent, tyPointer, tyPtr, tyRef, tyCString, tySequence, tyString, tyUntyped, + of tyVar, tyLent, tyPointer, tyPtr, tyRef, tyCString, tySequence, tyString, tyUntyped, tyTyped, tyTypeDesc, tyProc, tyArray, tyStatic, tyNil: result = addr libffi.type_pointer of tyDistinct, tyAlias, tySink: @@ -118,7 +118,7 @@ template `+!`(x, y: untyped): untyped = proc packSize(conf: ConfigRef, v: PNode, typ: PType): int = ## computes the size of the blob case typ.kind - of tyPtr, tyRef, tyVar, tyOut, tyLent: + of tyPtr, tyRef, tyVar, tyLent: if v.kind in {nkNilLit, nkPtrLit}: result = sizeof(pointer) else: @@ -215,7 +215,7 @@ proc pack(conf: ConfigRef, v: PNode, typ: PType, res: pointer) = awr(cstring, cstring(v.strVal)) else: globalError(conf, v.info, "cannot map pointer/proc value to FFI") - of tyPtr, tyRef, tyVar, tyOut, tyLent: + of tyPtr, tyRef, tyVar, tyLent: if v.kind == nkNilLit: # nothing to do since the memory is 0 initialized anyway discard @@ -370,7 +370,7 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode = result = n else: awi(nkPtrLit, cast[ByteAddress](p)) - of tyPtr, tyRef, tyVar, tyOut, tyLent: + of tyPtr, tyRef, tyVar, tyLent: let p = rd(pointer, x) if p.isNil: setNil() @@ -401,7 +401,7 @@ proc unpack(conf: ConfigRef, x: pointer, typ: PType, n: PNode): PNode = globalError(conf, n.info, "cannot map value from FFI " & typeToString(typ)) proc fficast*(conf: ConfigRef, x: PNode, destTyp: PType): PNode = - if x.kind == nkPtrLit and x.typ.kind in {tyPtr, tyRef, tyVar, tyOut, tyLent, tyPointer, + if x.kind == nkPtrLit and x.typ.kind in {tyPtr, tyRef, tyVar, tyLent, tyPointer, tyProc, tyCString, tyString, tySequence}: result = newNodeIT(x.kind, x.info, destTyp) diff --git a/compiler/guards.nim b/compiler/guards.nim index 1ef1bbfec61d6..a6ca44978a476 100644 --- a/compiler/guards.nim +++ b/compiler/guards.nim @@ -46,7 +46,7 @@ proc isLet(n: PNode): bool = if n.sym.kind in {skLet, skTemp, skForVar}: result = true elif n.sym.kind == skParam and skipTypes(n.sym.typ, - abstractInst).kind notin {tyVar, tyOut}: + abstractInst).kind notin {tyVar}: result = true proc isVar(n: PNode): bool = diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 9893df04ae30c..57a6b80942c9c 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -179,7 +179,7 @@ const proc mapType(typ: PType): TJSTypeKind = let t = skipTypes(typ, abstractInst) case t.kind - of tyVar, tyOut, tyRef, tyPtr, tyLent: + of tyVar, tyRef, tyPtr, tyLent: if skipTypes(t.lastSon, abstractInst).kind in MappedToObject: result = etyObject else: @@ -1030,7 +1030,7 @@ proc needsNoCopy(p: PProc; y: PNode): bool = return y.kind in nodeKindsNeedNoCopy or ((mapType(y.typ) != etyBaseIndex or (y.kind == nkSym and y.sym.kind == skParam)) and (skipTypes(y.typ, abstractInst).kind in - {tyRef, tyPtr, tyLent, tyVar, tyOut, tyCString, tyProc, tyOwned} + IntegralTypes)) + {tyRef, tyPtr, tyLent, tyVar, tyCString, tyProc, tyOwned} + IntegralTypes)) proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) = var a, b: TCompRes @@ -1053,7 +1053,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) = lineF(p, "$1 = nimCopy(null, $2, $3);$n", [a.rdLoc, b.res, genTypeInfo(p, y.typ)]) of etyObject: - if x.typ.kind in {tyVar, tyOut} or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded: + if x.typ.kind in {tyVar} or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded: lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc]) else: useMagic(p, "nimCopy") @@ -1451,7 +1451,7 @@ proc genArg(p: PProc, n: PNode, param: PSym, r: var TCompRes; emitted: ptr int = r.res.add(", ") r.res.add(a.res) if emitted != nil: inc emitted[] - elif n.typ.kind in {tyVar, tyOut, tyPtr, tyRef, tyLent, tyOwned} and + elif n.typ.kind in {tyVar, tyPtr, tyRef, tyLent, tyOwned} and n.kind in nkCallKinds and mapType(param.typ) == etyBaseIndex: # this fixes bug #5608: let tmp = getTemp(p) @@ -1691,7 +1691,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope = createObjInitList(p, t, initIntSet(), initList) result = ("{$1}") % [initList] if indirect: result = "[$1]" % [result] - of tyVar, tyOut, tyPtr, tyLent, tyRef, tyPointer: + of tyVar, tyPtr, tyLent, tyRef, tyPointer: if mapType(p, t) == etyBaseIndex: result = putToSeq("[null, 0]", indirect) else: @@ -1736,7 +1736,7 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) = if n.kind == nkEmpty: if not isIndirect(v) and - v.typ.kind in {tyVar, tyOut, tyPtr, tyLent, tyRef, tyOwned} and mapType(p, v.typ) == etyBaseIndex: + v.typ.kind in {tyVar, tyPtr, tyLent, tyRef, tyOwned} and mapType(p, v.typ) == etyBaseIndex: lineF(p, "var $1 = null;$n", [varName]) lineF(p, "var $1_Idx = 0;$n", [varName]) else: @@ -2286,7 +2286,7 @@ proc genProc(oldProc: PProc, prc: PSym): Rope = resultSym = prc.ast[resultPos].sym let mname = mangleName(p.module, resultSym) if not isIndirect(resultSym) and - resultSym.typ.kind in {tyVar, tyOut, tyPtr, tyLent, tyRef, tyOwned} and + resultSym.typ.kind in {tyVar, tyPtr, tyLent, tyRef, tyOwned} and mapType(p, resultSym.typ) == etyBaseIndex: resultAsgn = p.indentLine(("var $# = null;$n") % [mname]) resultAsgn.add p.indentLine("var $#_Idx = 0;$n" % [mname]) diff --git a/compiler/jstypes.nim b/compiler/jstypes.nim index 9f0b8c6c7de18..2073c252ec1a9 100644 --- a/compiler/jstypes.nim +++ b/compiler/jstypes.nim @@ -133,7 +133,7 @@ proc genTypeInfo(p: PProc, typ: PType): Rope = "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n" % [result, rope(ord(t.kind))] prepend(p.g.typeInfo, s) - of tyVar, tyOut, tyLent, tyRef, tyPtr, tySequence, tyRange, tySet: + of tyVar, tyLent, tyRef, tyPtr, tySequence, tyRange, tySet: var s = "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n" % [result, rope(ord(t.kind))] diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 4282caf52b8c0..c1cd075837989 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -192,7 +192,7 @@ proc interestingVar(s: PSym): bool {.inline.} = proc illegalCapture(s: PSym): bool {.inline.} = result = skipTypes(s.typ, abstractInst).kind in - {tyVar, tyOut, tyOpenArray, tyVarargs, tyLent} or + {tyVar, tyOpenArray, tyVarargs, tyLent} or s.kind == skResult proc isInnerProc(s: PSym): bool = diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 19e1b096cfdea..0346f6c671a32 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -50,7 +50,7 @@ proc fillBodyTup(c: var TLiftCtx; t: PType; body, x, y: PNode) = proc dotField(x: PNode, f: PSym): PNode = result = newNodeI(nkDotExpr, x.info, 2) - if x.typ.skipTypes(abstractInst).kind in {tyVar, tyOut}: + if x.typ.skipTypes(abstractInst).kind == tyVar: result[0] = x.newDeref else: result[0] = x @@ -248,7 +248,7 @@ proc newHookCall(g: ModuleGraph; op: PSym; x, y: PNode): PNode = # localError(c.config, x.info, "usage of '$1' is a user-defined error" % op.name.s) result = newNodeI(nkCall, x.info) result.add newSymNode(op) - if op.typ.sons[1].kind in {tyVar, tyOut}: + if op.typ.sons[1].kind == tyVar: result.add genAddr(g, x) else: result.add x diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 36353de377b4b..6287e21aa7741 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -211,7 +211,7 @@ type proc computeNotesVerbosity(): array[0..3, TNoteKinds] = result[3] = {low(TNoteKind)..high(TNoteKind)} - {} - result[2] = result[3] - {hintStackTrace, hintExtendedContext} + result[2] = result[3] - {hintStackTrace, warnUninit, hintExtendedContext} result[1] = result[2] - {warnProveField, warnProveIndex, warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd, hintSource, hintGlobalVar, hintGCStats, hintMsgOrigin} diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index 2d628d257925b..5e75c36de86cd 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -21,8 +21,8 @@ proc newDeref*(n: PNode): PNode {.inline.} = proc newTupleAccess*(g: ModuleGraph; tup: PNode, i: int): PNode = if tup.kind == nkHiddenAddr: - result = newNodeIT(nkHiddenAddr, tup.info, tup.typ.skipTypes(abstractInst+{tyPtr, tyVar, tyOut, tyLent})) - result.add newNodeIT(nkBracketExpr, tup.info, tup.typ.skipTypes(abstractInst+{tyPtr, tyVar, tyOut, tyLent})[i]) + result = newNodeIT(nkHiddenAddr, tup.info, tup.typ.skipTypes(abstractInst+{tyPtr, tyVar, tyLent})) + result.add newNodeIT(nkBracketExpr, tup.info, tup.typ.skipTypes(abstractInst+{tyPtr, tyVar, tyLent})[i]) result[0].add tup[0] var lit = newNodeIT(nkIntLit, tup.info, getSysType(g, tup.info, tyInt)) lit.intVal = i diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim index 890be52150bd4..ce9a855d8af90 100644 --- a/compiler/parampatterns.nim +++ b/compiler/parampatterns.nim @@ -214,12 +214,12 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult result = arNone case n.kind of nkEmpty: - if n.typ != nil and n.typ.kind in {tyVar, tyOut}: + if n.typ != nil and n.typ.kind in {tyVar}: result = arLValue of nkSym: let kinds = if isUnsafeAddr: {skVar, skResult, skTemp, skParam, skLet, skForVar} else: {skVar, skResult, skTemp} - if n.sym.kind == skParam and n.sym.typ.kind in {tyVar, tyOut, tySink}: + if n.sym.kind == skParam and n.sym.typ.kind in {tyVar, tySink}: result = arLValue elif isUnsafeAddr and n.sym.kind == skParam: result = arLValue @@ -231,10 +231,10 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult result = arLValue elif n.sym.kind == skType: let t = n.sym.typ.skipTypes({tyTypeDesc}) - if t.kind in {tyVar, tyOut}: result = arStrange + if t.kind in {tyVar}: result = arStrange of nkDotExpr: let t = skipTypes(n[0].typ, abstractInst-{tyTypeDesc}) - if t.kind in {tyVar, tyOut, tySink, tyPtr, tyRef}: + if t.kind in {tyVar, tySink, tyPtr, tyRef}: result = arLValue elif isUnsafeAddr and t.kind == tyLent: result = arLValue @@ -245,7 +245,7 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult result = arDiscriminant of nkBracketExpr: let t = skipTypes(n[0].typ, abstractInst-{tyTypeDesc}) - if t.kind in {tyVar, tyOut, tySink, tyPtr, tyRef}: + if t.kind in {tyVar, tySink, tyPtr, tyRef}: result = arLValue elif isUnsafeAddr and t.kind == tyLent: result = arLValue @@ -277,14 +277,14 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult # builtin slice keeps lvalue-ness: if getMagic(n) in {mArrGet, mSlice}: result = isAssignable(owner, n[1], isUnsafeAddr) - elif n.typ != nil and n.typ.kind in {tyVar, tyOut}: + elif n.typ != nil and n.typ.kind in {tyVar}: result = arLValue elif isUnsafeAddr and n.typ != nil and n.typ.kind == tyLent: result = arLValue of nkStmtList, nkStmtListExpr: if n.typ != nil: result = isAssignable(owner, n.lastSon, isUnsafeAddr) - of nkVarTy, nkOutTy: + of nkVarTy: # XXX: The fact that this is here is a bit of a hack. # The goal is to allow the use of checks such as "foo(var T)" # within concepts. Semantically, it's not correct to say that diff --git a/compiler/parser.nim b/compiler/parser.nim index 245e5325901a1..ccb7ca3b15b96 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -793,7 +793,7 @@ proc primarySuffix(p: var TParser, r: PNode, break result = namedParams(p, result, nkCurlyExpr, tkCurlyRi) of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast, - tkOpr, tkDotDot, tkVar, tkStatic, tkType, tkEnum, tkTuple, + tkOpr, tkDotDot, tkVar, tkOut, tkStatic, tkType, tkEnum, tkTuple, tkObject, tkProc: # XXX: In type sections we allow the free application of the # command syntax, with the exception of expressions such as @@ -1300,7 +1300,10 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode = optInd(p, result) result.add(primary(p, pmNormal)) of tkVar: result = parseTypeDescKAux(p, nkVarTy, mode) - of tkOut: result = parseTypeDescKAux(p, nkOutTy, mode) + of tkOut: + # I like this parser extension to be in 1.4 as it still might turn out + # useful in the long run. + result = parseTypeDescKAux(p, nkMutableTy, mode) of tkRef: result = parseTypeDescKAux(p, nkRefTy, mode) of tkPtr: result = parseTypeDescKAux(p, nkPtrTy, mode) of tkDistinct: result = parseTypeDescKAux(p, nkDistinctTy, mode) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index c69268f872234..4b8c78cc715f3 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -309,7 +309,7 @@ proc lsub(g: TSrcGen; n: PNode): int proc litAux(g: TSrcGen; n: PNode, x: BiggestInt, size: int): string = proc skip(t: PType): PType = result = t - while result != nil and result.kind in {tyGenericInst, tyRange, tyVar, tyOut, + while result != nil and result.kind in {tyGenericInst, tyRange, tyVar, tyLent, tyDistinct, tyOrdinal, tyAlias, tySink}: result = lastSon(result) @@ -482,7 +482,6 @@ proc lsub(g: TSrcGen; n: PNode): int = of nkRefTy: result = (if n.len > 0: lsub(g, n[0])+1 else: 0) + len("ref") of nkPtrTy: result = (if n.len > 0: lsub(g, n[0])+1 else: 0) + len("ptr") of nkVarTy: result = (if n.len > 0: lsub(g, n[0])+1 else: 0) + len("var") - of nkOutTy: result = (if n.len > 0: lsub(g, n[0])+1 else: 0) + len("out") of nkDistinctTy: result = len("distinct") + (if n.len > 0: lsub(g, n[0])+1 else: 0) if n.len > 1: @@ -884,7 +883,7 @@ proc bracketKind*(g: TSrcGen, n: PNode): BracketKind = case n.kind of nkClosedSymChoice, nkOpenSymChoice: if n.len > 0: result = bracketKind(g, n[0]) - of nkSym: + of nkSym: result = case n.sym.name.s of "[]": bkBracket of "[]=": bkBracketAsgn @@ -975,7 +974,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = put(g, tkParRi, ")") put(g, tkColon, ":") gsub(g, n, n.len-1) - elif n.len >= 1: + elif n.len >= 1: case bracketKind(g, n[0]) of bkBracket: gsub(g, n, 1) @@ -1264,12 +1263,6 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = gsub(g, n[0]) else: put(g, tkVar, "var") - of nkOutTy: - if n.len > 0: - putWithSpace(g, tkOut, "out") - gsub(g, n[0]) - else: - put(g, tkOut, "out") of nkDistinctTy: if n.len > 0: putWithSpace(g, tkDistinct, "distinct") diff --git a/compiler/semcall.nim b/compiler/semcall.nim index e64db3b3e776b..405de52eec7bd 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -675,7 +675,7 @@ proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym = let t = skipTypes(param.typ, abstractVar-{tyTypeDesc, tyDistinct}) if t.kind == tyDistinct or param.typ.kind == tyDistinct: hasDistinct = true var x: PType - if param.typ.kind in {tyVar, tyOut}: + if param.typ.kind == tyVar: x = newTypeS(param.typ.kind, c) x.addSonSkipIntLit t.baseOfDistinct else: diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 7b3ac48d4b72f..5a2c08de266b8 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -288,9 +288,9 @@ proc makePtrType*(c: PContext, baseType: PType): PType = proc makeTypeWithModifier*(c: PContext, modifier: TTypeKind, baseType: PType): PType = - assert modifier in {tyVar, tyOut, tyLent, tyPtr, tyRef, tyStatic, tyTypeDesc} + assert modifier in {tyVar, tyLent, tyPtr, tyRef, tyStatic, tyTypeDesc} - if modifier in {tyVar, tyOut, tyLent, tyTypeDesc} and baseType.kind == modifier: + if modifier in {tyVar, tyLent, tyTypeDesc} and baseType.kind == modifier: result = baseType else: result = newTypeS(modifier, c) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 7e28c5cd1940a..6f267b4eb326d 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -54,7 +54,7 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = # XXX tyGenericInst here? if result.typ.kind == tyProc and tfUnresolved in result.typ.flags: localError(c.config, n.info, errProcHasNoConcreteType % n.renderTree) - if result.typ.kind in {tyVar, tyOut, tyLent}: result = newDeref(result) + if result.typ.kind in {tyVar, tyLent}: result = newDeref(result) elif {efWantStmt, efAllowStmt} * flags != {}: result.typ = newTypeS(tyVoid, c) else: @@ -79,7 +79,7 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = renderTree(result, {renderNoComments})) result.typ = errorType(c) else: - if result.typ.kind in {tyVar, tyOut, tyLent}: result = newDeref(result) + if result.typ.kind in {tyVar, tyLent}: result = newDeref(result) proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = result = semExprCheck(c, n, flags) @@ -551,7 +551,7 @@ proc arrayConstrType(c: PContext, n: PNode): PType = if n.len == 0: rawAddSon(typ, newTypeS(tyEmpty, c)) # needs an empty basetype! else: - var t = skipTypes(n[0].typ, {tyGenericInst, tyVar, tyOut, tyLent, tyOrdinal, tyAlias, tySink}) + var t = skipTypes(n[0].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink}) addSonSkipIntLit(typ, t) typ[0] = makeRangeType(c, 0, n.len - 1, n.info) result = typ @@ -584,7 +584,7 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = let yy = semExprWithType(c, x) var typ = yy.typ result.add yy - #var typ = skipTypes(result[0].typ, {tyGenericInst, tyVar, tyOut, tyLent, tyOrdinal}) + #var typ = skipTypes(result[0].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal}) for i in 1.. 'result' n[1] = takeImplicitAddr(c, ri, x.typ.kind == tyLent) x.typ.flags.incl tfVarIsPtr @@ -1711,7 +1711,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode = var le = a.typ if le == nil: localError(c.config, a.info, "expression has no type") - elif (skipTypes(le, {tyGenericInst, tyAlias, tySink}).kind notin {tyVar, tyOut} and + elif (skipTypes(le, {tyGenericInst, tyAlias, tySink}).kind notin {tyVar} and isAssignable(c, a) in {arNone, arLentValue}) or skipTypes(le, abstractVar).kind in {tyOpenArray, tyVarargs}: # Direct assignment to a discriminant is allowed! @@ -1808,7 +1808,7 @@ proc semProcBody(c: PContext, n: PNode): PNode = proc semYieldVarResult(c: PContext, n: PNode, restype: PType) = var t = skipTypes(restype, {tyGenericInst, tyAlias, tySink}) case t.kind - of tyVar, tyOut, tyLent: + of tyVar, tyLent: t.flags.incl tfVarIsPtr # bugfix for #4048, #4910, #6892 if n[0].kind in {nkHiddenStdConv, nkHiddenSubConv}: n[0] = n[0][1] @@ -1816,7 +1816,7 @@ proc semYieldVarResult(c: PContext, n: PNode, restype: PType) = of tyTuple: for i in 0..= 2 and t[0] == nil if cond: - var obj = t[1].skipTypes({tyVar, tyOut}) + var obj = t[1].skipTypes({tyVar}) while true: incl(obj.flags, tfHasAsgn) if obj.kind in {tyGenericBody, tyGenericInst}: obj = obj.lastSon @@ -1814,7 +1814,7 @@ proc semMethodPrototype(c: PContext; s: PSym; n: PNode) = for col in 1.. 0 and t[0] != nil: hashType c, t[0], flags - of tyRef, tyPtr, tyGenericBody, tyVar, tyOut: + of tyRef, tyPtr, tyGenericBody, tyVar: c &= char(t.kind) c.hashType t.lastSon, flags if tfVarIsPtr in t.flags: c &= ".varisptr" diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index cdde9974eb072..e663f96b65e0d 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -219,7 +219,7 @@ proc sumGeneric(t: PType): int = if branchSum > maxBranch: maxBranch = branchSum inc result, maxBranch break - of tyVar, tyOut: + of tyVar: t = t[0] inc result inc isvar @@ -549,7 +549,7 @@ proc allowsNilDeprecated(c: TCandidate, f: PType): TTypeRelation = proc inconsistentVarTypes(f, a: PType): bool {.inline.} = result = f.kind != a.kind and - (f.kind in {tyVar, tyOut, tyLent, tySink} or a.kind in {tyVar, tyOut, tyLent, tySink}) + (f.kind in {tyVar, tyLent, tySink} or a.kind in {tyVar, tyLent, tySink}) proc procParamTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = ## For example we have: @@ -926,7 +926,7 @@ proc inferStaticsInRange(c: var TCandidate, template subtypeCheck() = if result <= isSubrange and f.lastSon.skipTypes(abstractInst).kind in { - tyRef, tyPtr, tyVar, tyOut, tyLent, tyOwned}: + tyRef, tyPtr, tyVar, tyLent, tyOwned}: result = isNone proc isCovariantPtr(c: var TCandidate, f, a: PType): bool = @@ -934,7 +934,7 @@ proc isCovariantPtr(c: var TCandidate, f, a: PType): bool = assert f.kind == a.kind template baseTypesCheck(lhs, rhs: PType): bool = - lhs.kind notin {tyPtr, tyRef, tyVar, tyOut, tyLent, tyOwned} and + lhs.kind notin {tyPtr, tyRef, tyVar, tyLent, tyOwned} and typeRel(c, lhs, rhs, {trNoCovariance}) == isSubtype case f.kind @@ -1050,7 +1050,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, template doBind: bool = trDontBind notin flags # var, sink and static arguments match regular modifier-free types - var a = maybeSkipDistinct(c, aOrig.skipTypes({tyStatic, tyVar, tyOut, tyLent, tySink}), c.calleeSym) + var a = maybeSkipDistinct(c, aOrig.skipTypes({tyStatic, tyVar, tyLent, tySink}), c.calleeSym) # XXX: Theoretically, maybeSkipDistinct could be called before we even # start the param matching process. This could be done in `prepareOperand` # for example, but unfortunately `prepareOperand` is not called in certain @@ -1060,7 +1060,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, return typeRel(c, f, lastSon(aOrig)) if a.kind == tyGenericInst and - skipTypes(f, {tyVar, tyOut, tyLent, tySink}).kind notin { + skipTypes(f, {tyVar, tyLent, tySink}).kind notin { tyGenericBody, tyGenericInvocation, tyGenericInst, tyGenericParam} + tyTypeClasses: return typeRel(c, f, lastSon(a)) @@ -1173,7 +1173,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, of tyFloat32: result = handleFloatRange(f, a) of tyFloat64: result = handleFloatRange(f, a) of tyFloat128: result = handleFloatRange(f, a) - of tyVar, tyOut, tyLent: + of tyVar, tyLent: if aOrig.kind == f.kind: result = typeRel(c, f.base, aOrig.base) else: result = typeRel(c, f.base, aOrig, flags + {trNoCovariance}) subtypeCheck() @@ -1895,14 +1895,14 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType, let constraint = c.converters[i].typ.n[1].sym.constraint if not constraint.isNil and not matchNodeKinds(constraint, arg): continue - if src.kind in {tyVar, tyOut, tyLent} and not arg.isLValue: + if src.kind in {tyVar, tyLent} and not arg.isLValue: continue let destIsGeneric = containsGenericType(dest) if destIsGeneric: dest = generateTypeInstance(c, m.bindings, arg, dest) let fdest = typeRel(m, f, dest) - if fdest in {isEqual, isGeneric} and not (dest.kind == tyLent and f.kind in {tyVar, tyOut}): + if fdest in {isEqual, isGeneric} and not (dest.kind == tyLent and f.kind in {tyVar}): markUsed(c, arg.info, c.converters[i]) var s = newSymNode(c.converters[i]) s.typ = c.converters[i].typ @@ -1915,7 +1915,7 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType, var param: PNode = nil if srca == isSubtype: param = implicitConv(nkHiddenSubConv, src, copyTree(arg), m, c) - elif src.kind in {tyVar, tyOut}: + elif src.kind in {tyVar}: # Analyse the converter return type param = newNodeIT(nkHiddenAddr, arg.info, s.typ[1]) param.add copyTree(arg) @@ -1923,7 +1923,7 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType, param = copyTree(arg) result.add param - if dest.kind in {tyVar, tyOut, tyLent}: + if dest.kind in {tyVar, tyLent}: dest.flags.incl tfVarIsPtr result = newDeref(result) @@ -2082,7 +2082,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType, result = implicitConv(nkHiddenSubConv, f, arg, m, c) of isSubrange: inc(m.subtypeMatches) - if f.kind in {tyVar, tyOut}: + if f.kind in {tyVar}: result = arg else: result = implicitConv(nkHiddenStdConv, f, arg, m, c) @@ -2290,7 +2290,7 @@ proc arrayConstr(c: PContext, n: PNode): PType = result = newTypeS(tyArray, c) rawAddSon(result, makeRangeType(c, 0, 0, n.info)) addSonSkipIntLit(result, skipTypes(n.typ, - {tyGenericInst, tyVar, tyOut, tyLent, tyOrdinal})) + {tyGenericInst, tyVar, tyLent, tyOrdinal})) proc arrayConstr(c: PContext, info: TLineInfo): PType = result = newTypeS(tyArray, c) @@ -2327,10 +2327,10 @@ proc matchesAux(c: PContext, n, nOrig: PNode, noMatch() return - if formal.typ.kind in {tyVar, tyOut}: + if formal.typ.kind in {tyVar}: let argConverter = if arg.kind == nkHiddenDeref: arg[0] else: arg if argConverter.kind == nkHiddenCallConv: - if argConverter.typ.kind notin {tyVar, tyOut}: + if argConverter.typ.kind notin {tyVar}: m.firstMismatch.kind = kVarNeeded noMatch() return @@ -2604,7 +2604,7 @@ proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo; if op == attachedDeepCopy: if f.kind in {tyRef, tyPtr}: f = f.lastSon else: - if f.kind in {tyVar, tyOut}: f = f.lastSon + if f.kind in {tyVar}: f = f.lastSon if typeRel(m, f, t) == isNone: localError(c.config, info, "cannot instantiate: '" & dc.name.s & "'") else: diff --git a/compiler/sinkparameter_inference.nim b/compiler/sinkparameter_inference.nim index d5510e7fb0c17..182e443247688 100644 --- a/compiler/sinkparameter_inference.nim +++ b/compiler/sinkparameter_inference.nim @@ -26,7 +26,7 @@ proc checkForSink*(config: ConfigRef; owner: PSym; arg: PNode) = arg.sym.owner == owner and owner.typ != nil and owner.typ.kind == tyProc and arg.sym.typ.hasDestructor and - arg.sym.typ.kind notin {tyVar, tyOut, tySink, tyOwned}: + arg.sym.typ.kind notin {tyVar, tySink, tyOwned}: # Watch out: cannot do this inference for procs with forward # declarations. if sfWasForwarded notin owner.flags: diff --git a/compiler/sizealignoffsetimpl.nim b/compiler/sizealignoffsetimpl.nim index 2938095513d56..4d73923db7939 100644 --- a/compiler/sizealignoffsetimpl.nim +++ b/compiler/sizealignoffsetimpl.nim @@ -240,7 +240,7 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) = else: typ.size = conf.target.ptrSize typ.align = int16(conf.target.ptrSize) - of tyCString, tySequence, tyPtr, tyRef, tyVar, tyOut, tyLent, tyOpenArray: + of tyCString, tySequence, tyPtr, tyRef, tyVar, tyLent, tyOpenArray: let base = typ.lastSon if base == typ: # this is not the correct location to detect ``type A = ptr A`` diff --git a/compiler/spawn.nim b/compiler/spawn.nim index 547cf9abca1dd..9d837b993e81d 100644 --- a/compiler/spawn.nim +++ b/compiler/spawn.nim @@ -50,7 +50,7 @@ proc typeNeedsNoDeepCopy(t: PType): bool = # note that seq[T] is fine, but 'var seq[T]' is not, so we need to skip 'var' # for the stricter check and likewise we can skip 'seq' for a less # strict check: - if t.kind in {tyVar, tyOut, tyLent, tySequence}: t = t.lastSon + if t.kind in {tyVar, tyLent, tySequence}: t = t.lastSon result = not containsGarbageCollectedRef(t) proc addLocalVar(g: ModuleGraph; varSection, varInit: PNode; owner: PSym; typ: PType; @@ -202,7 +202,7 @@ proc setupArgsForConcurrency(g: ModuleGraph; n: PNode; objType: PType; # 'tyOpenArray': var argType = n[i].typ.skipTypes(abstractInst) if i < formals.len: - if formals[i].typ.kind in {tyVar, tyOut, tyLent}: + if formals[i].typ.kind in {tyVar, tyLent}: localError(g.config, n[i].info, "'spawn'ed function cannot have a 'var' parameter") if formals[i].typ.kind in {tyTypeDesc, tyStatic}: continue diff --git a/compiler/suggest.nim b/compiler/suggest.nim index fb60b50a391a2..58b54cc038169 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -260,7 +260,7 @@ proc suggestField(c: PContext, s: PSym; f: PNode; info: TLineInfo; outputs: var proc getQuality(s: PSym): range[0..100] = if s.typ != nil and s.typ.len > 1: - var exp = s.typ[1].skipTypes({tyGenericInst, tyVar, tyOut, tyLent, tyAlias, tySink}) + var exp = s.typ[1].skipTypes({tyGenericInst, tyVar, tyLent, tyAlias, tySink}) if exp.kind == tyVarargs: exp = elemType(exp) if exp.kind in {tyUntyped, tyTyped, tyGenericParam, tyAnything}: return 50 return 100 @@ -331,7 +331,7 @@ proc typeFits(c: PContext, s: PSym, firstArg: PType): bool {.inline.} = let m = s.getModule() if m != nil and sfSystemModule in m.flags: if s.kind == skType: return - var exp = s.typ[1].skipTypes({tyGenericInst, tyVar, tyOut, tyLent, tyAlias, tySink}) + var exp = s.typ[1].skipTypes({tyGenericInst, tyVar, tyLent, tyAlias, tySink}) if exp.kind == tyVarargs: exp = elemType(exp) if exp.kind in {tyUntyped, tyTyped, tyGenericParam, tyAnything}: return result = sigmatch.argtypeMatches(c, s.typ[1], firstArg) @@ -401,7 +401,7 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions) suggestOperations(c, n, field, typ, outputs) else: let orig = typ # skipTypes(typ, {tyGenericInst, tyAlias, tySink}) - typ = skipTypes(typ, {tyGenericInst, tyVar, tyOut, tyLent, tyPtr, tyRef, tyAlias, tySink, tyOwned}) + typ = skipTypes(typ, {tyGenericInst, tyVar, tyLent, tyPtr, tyRef, tyAlias, tySink, tyOwned}) if typ.kind == tyObject: var t = typ while true: diff --git a/compiler/transf.nim b/compiler/transf.nim index c09d4d61816f2..10a2680aefcea 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -422,7 +422,7 @@ proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PNode = result = n[0] if n.typ.skipTypes(abstractVar).kind != tyOpenArray: result.typ = n.typ - elif n.typ.skipTypes(abstractInst).kind in {tyVar, tyOut}: + elif n.typ.skipTypes(abstractInst).kind in {tyVar}: result.typ = toVar(result.typ, n.typ.skipTypes(abstractInst).kind) of nkHiddenStdConv, nkHiddenSubConv, nkConv: var m = n[0][1] @@ -432,7 +432,7 @@ proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PNode = result = n[0] if n.typ.skipTypes(abstractVar).kind != tyOpenArray: result.typ = n.typ - elif n.typ.skipTypes(abstractInst).kind in {tyVar, tyOut}: + elif n.typ.skipTypes(abstractInst).kind in {tyVar}: result.typ = toVar(result.typ, n.typ.skipTypes(abstractInst).kind) else: if n[0].kind == a or n[0].kind == b: @@ -580,7 +580,7 @@ proc putArgInto(arg: PNode, formal: PType): TPutArgInto = return paFastAsgn result = paDirectMapping else: - if skipTypes(formal, abstractInst).kind in {tyVar, tyOut, tyLent}: result = paVarAsgn + if skipTypes(formal, abstractInst).kind in {tyVar, tyLent}: result = paVarAsgn else: result = paFastAsgn proc findWrongOwners(c: PTransf, n: PNode) = @@ -667,7 +667,7 @@ proc transformFor(c: PTransf, n: PNode): PNode = stmtList.add(newAsgnStmt(c, nkFastAsgn, temp, arg)) idNodeTablePut(newC.mapping, formal, temp) of paVarAsgn: - assert(skipTypes(formal.typ, abstractInst).kind in {tyVar, tyOut}) + assert(skipTypes(formal.typ, abstractInst).kind in {tyVar}) idNodeTablePut(newC.mapping, formal, arg) # XXX BUG still not correct if the arg has a side effect! of paComplexOpenarray: diff --git a/compiler/types.nim b/compiler/types.nim index fda99dffe03e3..b8f58c950b300 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -59,9 +59,9 @@ proc equalParams*(a, b: PNode): TParamsEquality const # TODO: Remove tyTypeDesc from each abstractX and (where necessary) # replace with typedescX - abstractPtrs* = {tyVar, tyOut, tyPtr, tyRef, tyGenericInst, tyDistinct, tyOrdinal, + abstractPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias, tyInferred, tySink, tyLent, tyOwned} - abstractVar* = {tyVar, tyOut, tyGenericInst, tyDistinct, tyOrdinal, tyTypeDesc, + abstractVar* = {tyVar, tyGenericInst, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias, tyInferred, tySink, tyLent, tyOwned} abstractRange* = {tyGenericInst, tyRange, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias, tyInferred, tySink, tyOwned} @@ -69,7 +69,7 @@ const abstractInst* = {tyGenericInst, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias, tyInferred, tySink, tyOwned} abstractInstOwned* = abstractInst + {tyOwned} - skipPtrs* = {tyVar, tyOut, tyPtr, tyRef, tyGenericInst, tyTypeDesc, tyAlias, + skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyTypeDesc, tyAlias, tyInferred, tySink, tyLent, tyOwned} # typedescX is used if we're sure tyTypeDesc should be included (or skipped) typedescPtrs* = abstractPtrs + {tyTypeDesc} @@ -545,7 +545,6 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = of tyBuiltInTypeClass: result = case t.base.kind: of tyVar: "var" - of tyOut: "out" of tyRef: "ref" of tyPtr: "ptr" of tySequence: "seq" @@ -643,7 +642,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = result.add(typeToString(t[i])) if i < t.len - 1: result.add(", ") result.add(')') - of tyPtr, tyRef, tyOut, tyVar, tyLent: + of tyPtr, tyRef, tyVar, tyLent: result = typeToStr[t.kind] if t.len >= 2: setLen(result, result.len-1) @@ -706,7 +705,7 @@ proc firstOrd*(conf: ConfigRef; t: PType): Int128 = case t.kind of tyBool, tyChar, tySequence, tyOpenArray, tyString, tyVarargs, tyProxy: result = Zero - of tySet, tyVar, tyOut: result = firstOrd(conf, t[0]) + of tySet, tyVar: result = firstOrd(conf, t[0]) of tyArray: result = firstOrd(conf, t[0]) of tyRange: assert(t.n != nil) # range directly given: @@ -748,7 +747,7 @@ proc firstFloat*(t: PType): BiggestFloat = assert(t.n != nil) # range directly given: assert(t.n.kind == nkRange) getFloatValue(t.n[0]) - of tyVar, tyOut: firstFloat(t[0]) + of tyVar: firstFloat(t[0]) of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tySink, tyStatic, tyInferred, tyUserTypeClasses: firstFloat(lastSon(t)) @@ -760,7 +759,7 @@ proc lastOrd*(conf: ConfigRef; t: PType): Int128 = case t.kind of tyBool: result = toInt128(1'u) of tyChar: result = toInt128(255'u) - of tySet, tyVar, tyOut: result = lastOrd(conf, t[0]) + of tySet, tyVar: result = lastOrd(conf, t[0]) of tyArray: result = lastOrd(conf, t[0]) of tyRange: assert(t.n != nil) # range directly given: @@ -802,7 +801,7 @@ proc lastOrd*(conf: ConfigRef; t: PType): Int128 = proc lastFloat*(t: PType): BiggestFloat = case t.kind of tyFloat..tyFloat128: Inf - of tyVar, tyOut: lastFloat(t[0]) + of tyVar: lastFloat(t[0]) of tyRange: assert(t.n != nil) # range directly given: assert(t.n.kind == nkRange) @@ -822,7 +821,7 @@ proc floatRangeCheck*(x: BiggestFloat, t: PType): bool = true of tyRange: x in firstFloat(t)..lastFloat(t) - of tyVar, tyOut: + of tyVar: floatRangeCheck(x, t[0]) of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tySink, tyStatic, tyInferred, tyUserTypeClasses: @@ -1145,7 +1144,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = assert b[0].len == 0 result = a[0].kind == b[0].kind of tyGenericInvocation, tyGenericBody, tySequence, tyOpenArray, tySet, tyRef, - tyPtr, tyVar, tyOut, tyLent, tySink, tyUncheckedArray, tyArray, tyProc, tyVarargs, + tyPtr, tyVar, tyLent, tySink, tyUncheckedArray, tyArray, tyProc, tyVarargs, tyOrdinal, tyCompositeTypeClass, tyUserTypeClass, tyUserTypeClassInst, tyAnd, tyOr, tyNot, tyAnything, tyOwned: cycleCheck() @@ -1287,7 +1286,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, if containsOrIncl(marker, typ.id): return nil var t = skipTypes(typ, abstractInst-{tyTypeDesc}) case t.kind - of tyVar, tyOut, tyLent: + of tyVar, tyLent: if kind in {skProc, skFunc, skConst}: result = t elif t.kind == tyLent and kind != skResult: @@ -1295,7 +1294,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, else: var t2 = skipTypes(t[0], abstractInst-{tyTypeDesc}) case t2.kind - of tyVar, tyOut, tyLent: + of tyVar, tyLent: if taHeap notin flags: result = t2 # ``var var`` is illegal on the heap of tyOpenArray: if kind != skParam or taIsOpenArray in flags: result = t @@ -1660,7 +1659,7 @@ proc isTupleRecursive(t: PType, cycleDetector: var IntSet): bool = assign(cycleDetectorCopy, cycleDetector) if isTupleRecursive(t[i], cycleDetectorCopy): return true - of tyAlias, tyRef, tyPtr, tyGenericInst, tyVar, tyOut, tyLent, tySink, + of tyAlias, tyRef, tyPtr, tyGenericInst, tyVar, tyLent, tySink, tyArray, tyUncheckedArray, tySequence, tyDistinct: return isTupleRecursive(t.lastSon, cycleDetector) else: diff --git a/compiler/typesrenderer.nim b/compiler/typesrenderer.nim index d58d1dc2dcf56..60f9f6603c175 100644 --- a/compiler/typesrenderer.nim +++ b/compiler/typesrenderer.nim @@ -40,11 +40,6 @@ proc renderType(n: PNode): string = result = renderType(n[0]) else: result = "var" - of nkOutTy: - if n.len == 1: - result = renderType(n[0]) - else: - result = "out" of nkRefTy: if n.len == 1: result = "ref." & renderType(n[0]) diff --git a/compiler/vm.nim b/compiler/vm.nim index 39cea78804916..9b76d798693e4 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1098,7 +1098,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = of opcGetImpl: decodeB(rkNode) var a = regs[rb].node - if a.kind in {nkVarTy, nkOutTy}: a = a[0] + if a.kind == nkVarTy: a = a[0] if a.kind == nkSym: regs[ra].node = if a.sym.ast.isNil: newNode(nkNilLit) else: copyTree(a.sym.ast) diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index 15ac59d9ddb90..6f90b79189f43 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -221,12 +221,6 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo; result.add mapTypeToAst(t[0], info) else: result = mapTypeToBracket("var", mVar, t, info) - of tyOut: - if inst: - result = newNodeX(nkOutTy) - result.add mapTypeToAst(t[0], info) - else: - result = mapTypeToBracket("out", mOut, t, info) of tyLent: result = mapTypeToBracket("lent", mBuiltinType, t, info) of tySink: result = mapTypeToBracket("sink", mBuiltinType, t, info) of tySequence: result = mapTypeToBracket("seq", mSeq, t, info) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 37923982b3813..52b7b6eb3e75f 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -967,7 +967,7 @@ proc whichAsgnOpc(n: PNode; requiresCopy = true): TOpcode = opcAsgnInt of tyFloat..tyFloat128: opcAsgnFloat - of tyRef, tyNil, tyVar, tyOut, tyLent, tyPtr: + of tyRef, tyNil, tyVar, tyLent, tyPtr: opcAsgnRef else: (if requiresCopy: opcAsgnComplex else: opcFastAsgnComplex) @@ -1654,7 +1654,7 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) = template needsRegLoad(): untyped = {gfNode, gfNodeAddr} * flags == {} and - fitsRegister(n.typ.skipTypes({tyVar, tyOut, tyLent, tyStatic})) + fitsRegister(n.typ.skipTypes({tyVar, tyLent, tyStatic})) proc genArrAccessOpcode(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode; flags: TGenFlags) = @@ -1794,7 +1794,7 @@ proc getNullValue(typ: PType, info: TLineInfo; conf: ConfigRef): PNode = of tyCString, tyString: result = newNodeIT(nkStrLit, info, t) result.strVal = "" - of tyVar, tyOut, tyLent, tyPointer, tyPtr, tyUntyped, + of tyVar, tyLent, tyPointer, tyPtr, tyUntyped, tyTyped, tyTypeDesc, tyRef, tyNil: result = newNodeIT(nkNilLit, info, t) of tyProc: diff --git a/compiler/writetracking.nim b/compiler/writetracking.nim index 4c95d9c26409b..44ef3a9375851 100644 --- a/compiler/writetracking.nim +++ b/compiler/writetracking.nim @@ -85,7 +85,7 @@ proc allRoots(n: PNode; result: var seq[ptr TSym]; info: var set[RootInfo]) = assert(typ.n[i].kind == nkSym) let paramType = typ.n[i] if paramType.typ.isCompileTimeOnly: continue - if sfEscapes in paramType.sym.flags or paramType.typ.kind in {tyVar, tyOut}: + if sfEscapes in paramType.sym.flags or paramType.typ.kind in {tyVar}: allRoots(it, result, info) else: allRoots(it, result, info) @@ -164,7 +164,7 @@ proc depsArgs(w: var W; n: PNode) = let paramType = typ.n[i] if paramType.typ.isCompileTimeOnly: continue var destInfo: set[RootInfo] = {} - if sfWrittenTo in paramType.sym.flags or paramType.typ.kind in {tyVar, tyOut}: + if sfWrittenTo in paramType.sym.flags or paramType.typ.kind in {tyVar}: # p(f(x, y), X, g(h, z)) destInfo.incl markAsWrittenTo if sfEscapes in paramType.sym.flags: @@ -247,7 +247,7 @@ proc markWriteOrEscape(w: var W; conf: ConfigRef) = for p in a.dest: if p.kind == skParam and p.owner == w.owner: incl(p.flags, sfWrittenTo) - if w.owner.kind == skFunc and p.typ.kind notin {tyVar, tyOut}: + if w.owner.kind == skFunc and p.typ.kind notin {tyVar}: localError(conf, a.info, "write access to non-var parameter: " & p.name.s) if {rootIsResultOrParam, rootIsHeapAccess, markAsEscaping}*a.destInfo != {}: diff --git a/tests/effects/toutparam.nim b/tests/effects/toutparam.nim index 61337fb0dc515..00572aa6b1542 100644 --- a/tests/effects/toutparam.nim +++ b/tests/effects/toutparam.nim @@ -2,6 +2,7 @@ discard """ cmd: '''nim c --warningAsError[Uninit]:on --skipCfg --skipParentCfg $file''' errormsg: "use explicit initialization of 'x' for clarity [Uninit]" line: 24 + disabled: "true" """ proc gah[T](x: out T) = From a559d1d2f762f39b6411ab632fcd3037de65c3f6 Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 22 Jun 2020 21:27:55 +0200 Subject: [PATCH 14/15] updated the changelog --- changelog.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/changelog.md b/changelog.md index 7c65c9a40a8c4..c5854a57bc266 100644 --- a/changelog.md +++ b/changelog.md @@ -181,9 +181,6 @@ proc mydiv(a, b): int {.raises: [].} = - Added the `thiscall` calling convention as specified by Microsoft. -- Added a new parameter mode, `out T` in order to strengthen the language's - "definite assignment checking". Definite assignment checking is now turned - on by default. - Added `thiscall` calling convention as specified by Microsoft, mostly for hooking purpose - Deprecated `{.unroll.}` pragma, was ignored by the compiler anyways, was a nop. From 22d0e68d48208a3695ddedf2fbb58b3cff9b21b0 Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 23 Jun 2020 10:05:52 +0200 Subject: [PATCH 15/15] undocumented the 'out' parameters --- doc/manual.rst | 40 ------------------------------------- doc/manual_experimental.rst | 4 ++-- 2 files changed, 2 insertions(+), 42 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index 6a3de3812179f..da50e2c56965f 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -3723,46 +3723,6 @@ location is derived from the second parameter (called ``varTy[T, 2]`` which is incompatible with ``varTy[T, 1]``. -Out parameters --------------- - -The type of a parameter may be ``out T``: - -.. code-block:: nim - proc divmod(a, b: int; res, remainder: out int) = - res = a div b - remainder = a mod b - - var - x, y: int - - divmod(8, 5, x, y) # modifies x and y - assert x == 1 - assert y == 3 - -In the example, ``res`` and ``remainder`` are `out parameters`. -Out parameters can be modified by the procedure and the changes are -visible to the caller. The argument passed to an out parameter has to be -an l-value. It is enforced that every code path assigns a value to -every `out` parameter before the routine returns and before a read from -the `out` parameter can be performed. This is the distinguishing difference -between an `out` parameter and a `var` parameter. An `out` parameter is an -output parameter, a `var` parameter is an input-output parameter. - -There is no semantic difference -between ``proc p(x: out T) {.raises: [].}`` and ``proc p(): T {.raises: [].}`` -but how these constructs are mapped to machine code might differ. -An `out` parameter is mapped to a pointer for a routine imported from C/C++, -for example: - -.. code-block:: nim - - type Stat {.importc: "stat_t", header: "stat.h".} = object - proc stat(path: cstring; result: out Stat) {.importc, header: "stat.h".} - ## mapped to 'ptr Stat' - - - NRVO ---- diff --git a/doc/manual_experimental.rst b/doc/manual_experimental.rst index cfc9e1ac26a69..d8efddf947fce 100644 --- a/doc/manual_experimental.rst +++ b/doc/manual_experimental.rst @@ -1828,8 +1828,8 @@ Aliasing restrictions in parameter passing implementation and need to be fleshed out further. "Aliasing" here means that the underlying storage locations overlap in memory -at runtime. An "output parameter" is a parameter of type ``var T`` or ``out T``, -an input parameter is any parameter that is not of type ``var`` nor ``out``. +at runtime. An "output parameter" is a parameter of type ``var T``, +an input parameter is any parameter that is not of type ``var``. 1. Two output parameters should never be aliased. 2. An input and an output parameter should not be aliased.