Showing with 682 additions and 151 deletions.
  1. +3 −3 build_all.bat
  2. +6 −11 compiler/ccgexprs.nim
  3. +14 −22 compiler/injectdestructors.nim
  4. +1 −8 compiler/jsgen.nim
  5. +2 −1 compiler/semcall.nim
  6. +2 −0 compiler/semexprs.nim
  7. +2 −1 compiler/semgnrc.nim
  8. +1 −0 compiler/semmacrosanity.nim
  9. +7 −1 compiler/sempass2.nim
  10. +19 −0 compiler/semstmts.nim
  11. +17 −0 compiler/semtypes.nim
  12. +2 −1 compiler/semtypinst.nim
  13. +14 −5 compiler/sigmatch.nim
  14. +12 −4 compiler/transf.nim
  15. +1 −2 compiler/trees.nim
  16. +13 −12 compiler/types.nim
  17. +15 −9 compiler/vmgen.nim
  18. +6 −7 koch.nim
  19. +16 −2 lib/posix/posix.nim
  20. +0 −2 lib/posix/posix_haiku.nim
  21. +0 −2 lib/posix/posix_linux_amd64.nim
  22. +5 −7 lib/posix/posix_macos_amd64.nim
  23. +0 −2 lib/posix/posix_nintendoswitch.nim
  24. +5 −7 lib/posix/posix_openbsd_amd64.nim
  25. +0 −7 lib/posix/posix_other.nim
  26. +1 −1 lib/pure/ioselects/ioselectors_poll.nim
  27. +5 −3 lib/pure/net.nim
  28. +2 −3 lib/pure/volatile.nim
  29. +3 −1 lib/system.nim
  30. +1 −1 lib/system/compilation.nim
  31. +1 −1 lib/system/strs_v2.nim
  32. +3 −8 lib/windows/winlean.nim
  33. +2 −2 testament/important_packages.nim
  34. +17 −0 tests/arc/tstringliteral.nim
  35. +36 −0 tests/ccgbugs/t13062.nim
  36. +32 −0 tests/ccgbugs/tunioninit.nim
  37. +13 −0 tests/destructor/tmove.nim
  38. +46 −1 tests/destructor/tnewruntime_strutils.nim
  39. +21 −0 tests/distinct/tcomplexaddressableconv.nim
  40. +16 −0 tests/generics/t19848.nim
  41. +21 −1 tests/generics/tgeneric0.nim
  42. +9 −0 tests/generics/tnestedtemplate.nim
  43. +30 −0 tests/generics/tuninstantiatedgenericcalls.nim
  44. +18 −0 tests/init/tlet.nim
  45. +19 −0 tests/lent/tlent_from_var.nim
  46. +23 −0 tests/macros/t23547.nim
  47. +8 −0 tests/objects/t20972.nim
  48. +13 −0 tests/objects/tobject_default_value.nim
  49. +18 −0 tests/objvariant/tconstobjvariant.nim
  50. +10 −0 tests/overload/m19737.nim
  51. +15 −0 tests/overload/t19737.nim
  52. +15 −10 tests/overload/tvartypeclass.nim
  53. +41 −0 tests/proc/tanonprocresem.nim
  54. +8 −0 tests/stdlib/twronguidtype.nim
  55. +7 −0 tests/varstmt/tvardecl.nim
  56. +49 −0 tests/vm/tconvaddr.nim
  57. +3 −3 tools/ci_generate.nim
  58. +13 −0 tools/deps.nim
6 changes: 3 additions & 3 deletions build_all.bat
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ if not exist %nim_csources% (
cd ..
copy /y bin\nim.exe %nim_csources%
)
bin\nim.exe c --noNimblePath --skipUserCfg --skipParentCfg --hints:off koch
koch boot -d:release --skipUserCfg --skipParentCfg --hints:off
koch tools --skipUserCfg --skipParentCfg --hints:off
bin\nim.exe c --noNimblePath --skipUserCfg --skipParentCfg --hints:off koch
koch boot -d:release --skipUserCfg --skipParentCfg --hints:off
koch tools --skipUserCfg --skipParentCfg --hints:off
17 changes: 6 additions & 11 deletions compiler/ccgexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2362,7 +2362,7 @@ proc genWasMoved(p: BProc; n: PNode) =

proc genMove(p: BProc; n: PNode; d: var TLoc) =
var a: TLoc
initLocExpr(p, n[1].skipAddr, a)
initLocExpr(p, n[1].skipAddr, a, {lfEnforceDeref})
if n.len == 4:
# generated by liftdestructors:
var src: TLoc
Expand Down Expand Up @@ -3118,16 +3118,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
of nkObjConstr: genObjConstr(p, n, d)
of nkCast: genCast(p, n, d)
of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, d)
of nkHiddenAddr:
if n[0].kind == nkDerefExpr:
# addr ( deref ( x )) --> x
var x = n[0][0]
if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
x.typ = n.typ
expr(p, x, d)
return
genAddr(p, n, d)
of nkAddr: genAddr(p, n, d)
of nkAddr, nkHiddenAddr: genAddr(p, n, d)
of nkBracketExpr: genBracketExpr(p, n, d)
of nkDerefExpr, nkHiddenDeref: genDeref(p, n, d)
of nkDotExpr: genRecordField(p, n, d)
Expand Down Expand Up @@ -3312,8 +3303,12 @@ proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode,
isConst: bool, info: TLineInfo) =
case obj.kind
of nkRecList:
let isUnion = tfUnion in t.flags
for it in obj.sons:
getNullValueAux(p, t, it, constOrNil, result, count, isConst, info)
if isUnion:
# generate only 1 field for default value of union
return
of nkRecCase:
getNullValueAux(p, t, obj[0], constOrNil, result, count, isConst, info)
var res = ""
Expand Down
36 changes: 14 additions & 22 deletions compiler/injectdestructors.nim
Original file line number Diff line number Diff line change
Expand Up @@ -795,15 +795,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
result = passCopyToSink(n, c, s)
elif n.kind in {nkBracket, nkObjConstr, nkTupleConstr, nkClosure, nkNilLit} +
nkCallKinds + nkLiterals:
if n.kind in nkCallKinds and n[0].kind == nkSym:
if n[0].sym.magic == mEnsureMove:
inc c.inEnsureMove
result = p(n[1], c, s, sinkArg)
dec c.inEnsureMove
else:
result = p(n, c, s, consumed)
else:
result = p(n, c, s, consumed)
result = p(n, c, s, consumed)
elif ((n.kind == nkSym and isSinkParam(n.sym)) or isAnalysableFieldAccess(n, c.owner)) and
isLastRead(n, c, s) and not (n.kind == nkSym and isCursor(n)):
# Sinked params can be consumed only once. We need to reset the memory
Expand Down Expand Up @@ -878,12 +870,6 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
if mode == normal and (isRefConstr or hasCustomDestructor(c, t)):
result = ensureDestruction(result, n, c, s)
of nkCallKinds:
if n[0].kind == nkSym and n[0].sym.magic == mEnsureMove:
inc c.inEnsureMove
result = p(n[1], c, s, sinkArg)
dec c.inEnsureMove
return

let inSpawn = c.inSpawn
if n[0].kind == nkSym and n[0].sym.magic == mSpawn:
c.inSpawn.inc
Expand All @@ -900,13 +886,19 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
isDangerous = true

result = shallowCopy(n)
for i in 1..<n.len:
if i < L and isCompileTimeOnly(parameters[i]):
result[i] = n[i]
elif i < L and (isSinkTypeForParam(parameters[i]) or inSpawn > 0):
result[i] = p(n[i], c, s, sinkArg)
else:
result[i] = p(n[i], c, s, normal)

if n[0].kind == nkSym and n[0].sym.magic == mEnsureMove:
inc c.inEnsureMove
result[1] = p(n[1], c, s, sinkArg)
dec c.inEnsureMove
else:
for i in 1..<n.len:
if i < L and isCompileTimeOnly(parameters[i]):
result[i] = n[i]
elif i < L and (isSinkTypeForParam(parameters[i]) or inSpawn > 0):
result[i] = p(n[i], c, s, sinkArg)
else:
result[i] = p(n[i], c, s, normal)

when false:
if isDangerous:
Expand Down
9 changes: 1 addition & 8 deletions compiler/jsgen.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1519,15 +1519,8 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
else: internalError(p.config, n[0].info, "expr(nkBracketExpr, " & $kindOfIndexedExpr & ')')
of nkObjDownConv:
gen(p, n[0], r)
of nkHiddenDeref:
of nkHiddenDeref, nkDerefExpr:
gen(p, n[0], r)
of nkDerefExpr:
var x = n[0]
if n.kind == nkHiddenAddr:
x = n[0][0]
if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
x.typ = n.typ
gen(p, x, r)
of nkHiddenAddr:
gen(p, n[0], r)
of nkConv:
Expand Down
3 changes: 2 additions & 1 deletion compiler/semcall.nim
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,8 @@ proc semResolvedCall(c: PContext, x: TCandidate,
instGenericConvertersSons(c, result, x)
markConvertersUsed(c, result)
result[0] = newSymNode(finalCallee, getCallLineInfo(result[0]))
result.typ = finalCallee.typ[0]
if finalCallee.magic notin {mArrGet, mArrPut}:
result.typ = finalCallee.typ[0]
updateDefaultParams(result)

proc canDeref(n: PNode): bool {.inline.} =
Expand Down
2 changes: 2 additions & 0 deletions compiler/semexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1850,6 +1850,8 @@ proc takeImplicitAddr(c: PContext, n: PNode; isLent: bool): PNode =
else:
localError(c.config, n.info, errExprHasNoAddress)
result = newNodeIT(nkHiddenAddr, n.info, if n.typ.kind in {tyVar, tyLent}: n.typ else: makePtrType(c, n.typ))
if n.typ.kind in {tyVar, tyLent}:
n.typ = n.typ.elementType
result.add(n)

proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} =
Expand Down
3 changes: 2 additions & 1 deletion compiler/semgnrc.nim
Original file line number Diff line number Diff line change
Expand Up @@ -577,7 +577,8 @@ proc semGenericStmt(c: PContext, n: PNode,
else:
body = getBody(c.graph, s)
else: body = n[bodyPos]
n[bodyPos] = semGenericStmtScope(c, body, flags, ctx)
let bodyFlags = if n.kind == nkTemplateDef: flags + {withinMixin} else: flags
n[bodyPos] = semGenericStmtScope(c, body, bodyFlags, ctx)
closeScope(c)
of nkPragma, nkPragmaExpr: discard
of nkExprColonExpr, nkExprEqExpr:
Expand Down
1 change: 1 addition & 0 deletions compiler/semmacrosanity.nim
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ proc annotateType*(n: PNode, t: PType; conf: ConfigRef) =
of nkObjConstr:
let x = t.skipTypes(abstractPtrs)
n.typ = t
n[0].typ = t
for i in 1..<n.len:
var j = i-1
let field = x.ithField(j)
Expand Down
8 changes: 7 additions & 1 deletion compiler/sempass2.nim
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ proc varDecl(a: PEffects; n: PNode) {.inline.} =
proc skipHiddenDeref(n: PNode): PNode {.inline.} =
result = if n.kind == nkHiddenDeref: n[0] else: n


proc initVar(a: PEffects, n: PNode; volatileCheck: bool) =
let n = skipHiddenDeref(n)
if n.kind != nkSym: return
Expand Down Expand Up @@ -1144,7 +1145,12 @@ proc track(tracked: PEffects, n: PNode) =
let last = lastSon(child)
track(tracked, last)
of nkCaseStmt: trackCase(tracked, n)
of nkWhen, nkIfStmt, nkIfExpr: trackIf(tracked, n)
of nkWhen: # This should be a "when nimvm" node.
let oldState = tracked.init.len
track(tracked, n[0][1])
tracked.init.setLen(oldState)
track(tracked, n[1][0])
of nkIfStmt, nkIfExpr: trackIf(tracked, n)
of nkBlockStmt, nkBlockExpr: trackBlock(tracked, n[1])
of nkWhileStmt:
# 'while true' loop?
Expand Down
19 changes: 19 additions & 0 deletions compiler/semstmts.nim
Original file line number Diff line number Diff line change
Expand Up @@ -780,6 +780,24 @@ proc makeVarTupleSection(c: PContext, n, a, def: PNode, typ: PType, symkind: TSy
proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
var b: PNode
result = copyNode(n)

# transform var x, y = 12 into var x = 12; var y = 12
# bug #18104; transformation should be finished before templates expansion
# TODO: move warnings for tuple here
var transformed = copyNode(n)
for i in 0..<n.len:
var a = n[i]
if a.kind == nkIdentDefs and a.len > 3 and a[^1].kind != nkEmpty:
for j in 0..<a.len-2:
var b = newNodeI(nkIdentDefs, a.info)
b.add a[j]
b.add a[^2]
b.add copyTree(a[^1])
transformed.add b
else:
transformed.add a
let n = transformed

for i in 0..<n.len:
var a = n[i]
if c.config.cmd == cmdIdeTools: suggestStmt(c, a)
Expand Down Expand Up @@ -2253,6 +2271,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
of nkEmpty:
s = newSym(kind, c.cache.idAnon, c.idgen, c.getCurrOwner, n.info)
s.flags.incl sfUsed
s.flags.incl sfGenSym
n[namePos] = newSymNode(s)
of nkSym:
s = n[namePos].sym
Expand Down
17 changes: 17 additions & 0 deletions compiler/semtypes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,22 @@ proc isRecursiveType(t: PType, cycleDetector: var IntSet): bool =
else:
return false

proc annotateClosureConv(n: PNode) =
case n.kind
of {nkNone..nkNilLit}:
discard
of nkTupleConstr:
if n.typ.kind == tyProc and n.typ.callConv == ccClosure and
n[0].typ.kind == tyProc and n[0].typ.callConv != ccClosure:
# restores `transf.generateThunk`
n[0] = newTreeIT(nkHiddenSubConv, n[0].info, n.typ,
newNodeI(nkEmpty, n[0].info), n[0])
n.transitionSonsKind(nkClosure)
n.flags.incl nfTransf
else:
for i in 0..<n.len:
annotateClosureConv(n[i])

proc fitDefaultNode(c: PContext, n: PNode): PType =
inc c.inStaticContext
let expectedType = if n[^2].kind != nkEmpty: semTypeNode(c, n[^2], nil) else: nil
Expand All @@ -243,6 +259,7 @@ proc fitDefaultNode(c: PContext, n: PNode): PType =
# `changeType` to infer types for constant values
# that's also the reason why we don't use `semExpr` to check
# the type since two overlapping error messages might be produced
annotateClosureConv(n)
result = n[^1].typ
else:
result = n[^1].typ
Expand Down
3 changes: 2 additions & 1 deletion compiler/semtypinst.nim
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
result.kind = tyUserTypeClassInst

of tyGenericBody:
if cl.allowMetaTypes: return
localError(
cl.c.config,
cl.info,
Expand Down Expand Up @@ -651,7 +652,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =

for i in 0..<result.len:
if result[i] != nil:
if result[i].kind == tyGenericBody:
if result[i].kind == tyGenericBody and not cl.allowMetaTypes:
localError(cl.c.config, if t.sym != nil: t.sym.info else: cl.info,
"cannot instantiate '" &
typeToString(result[i], preferDesc) &
Expand Down
19 changes: 14 additions & 5 deletions compiler/sigmatch.nim
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,7 @@ proc concreteType(c: TCandidate, t: PType; f: PType = nil): PType =
else: result = t
of tyGenericParam, tyAnything, tyConcept:
result = t
if c.isNoCall: return
while true:
result = PType(idTableGet(c.bindings, t))
if result == nil:
Expand Down Expand Up @@ -1220,10 +1221,15 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,

of tyFromExpr:
if c.c.inGenericContext > 0:
# generic type bodies can sometimes compile call expressions
# prevent expressions with unresolved types from
# being passed as parameters
return isNone
if not c.isNoCall:
# generic type bodies can sometimes compile call expressions
# prevent expressions with unresolved types from
# being passed as parameters
return isNone
else:
# Foo[templateCall(T)] shouldn't fail early if Foo has a constraint
# and we can't evaluate `templateCall(T)` yet
return isGeneric
else: discard
case f.kind
of tyEnum:
Expand Down Expand Up @@ -1743,9 +1749,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
let target = f[0]
let targetKind = target.kind
var effectiveArgType = reduceToBase(a)
# the skipped child of tyBuiltInTypeClass can be structured differently,
# newConstraint constructs them with no children
let typeClassArg = effectiveArgType.kind == tyBuiltInTypeClass
effectiveArgType = effectiveArgType.skipTypes({tyBuiltInTypeClass})
if targetKind == effectiveArgType.kind:
if effectiveArgType.isEmptyContainer:
if not typeClassArg and effectiveArgType.isEmptyContainer:
return isNone
if targetKind == tyProc:
if target.flags * {tfIterator} != effectiveArgType.flags * {tfIterator}:
Expand Down
16 changes: 12 additions & 4 deletions compiler/transf.nim
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,17 @@ proc transformAddrDeref(c: PTransf, n: PNode, kinds: TNodeKinds, isAddr = false)
elif n.typ.skipTypes(abstractInst).kind in {tyVar}:
result.typ = toVar(result.typ, n.typ.skipTypes(abstractInst).kind, c.idgen)
else:
if n[0].kind in kinds:
if n[0].kind in kinds and
not (n[0][0].kind == nkSym and n[0][0].sym.kind == skForVar and
n[0][0].typ.skipTypes(abstractVar).kind == tyTuple
) and not (n[0][0].kind == nkSym and n[0][0].sym.kind == skParam and
n.typ.kind == tyVar and
n.typ.skipTypes(abstractVar).kind == tyOpenArray and
n[0][0].typ.skipTypes(abstractVar).kind == tyString) and
not (isAddr and n.typ.kind == tyVar and n[0][0].typ.kind == tyRef and
n[0][0].kind == nkObjConstr)
: # elimination is harmful to `for tuple unpack` because of newTupleAccess
# it is also harmful to openArrayLoc (var openArray) for strings
# addr ( deref ( x )) --> x
result = n[0][0]
if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
Expand Down Expand Up @@ -1035,9 +1045,7 @@ proc transform(c: PTransf, n: PNode, noConstFold = false): PNode =
of nkBreakStmt: result = transformBreak(c, n)
of nkCallKinds:
result = transformCall(c, n)
of nkHiddenAddr:
result = transformAddrDeref(c, n, {nkHiddenDeref}, isAddr = true)
of nkAddr:
of nkAddr, nkHiddenAddr:
result = transformAddrDeref(c, n, {nkDerefExpr, nkHiddenDeref}, isAddr = true)
of nkDerefExpr:
result = transformAddrDeref(c, n, {nkAddr, nkHiddenAddr})
Expand Down
3 changes: 1 addition & 2 deletions compiler/trees.nim
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,7 @@ proc stupidStmtListExpr*(n: PNode): bool =
proc dontInlineConstant*(orig, cnst: PNode): bool {.inline.} =
# symbols that expand to a complex constant (array, etc.) should not be
# inlined, unless it's the empty array:
result = orig.kind != cnst.kind and
cnst.kind in {nkCurly, nkPar, nkTupleConstr, nkBracket, nkObjConstr} and
result = cnst.kind in {nkCurly, nkPar, nkTupleConstr, nkBracket, nkObjConstr} and
cnst.len > ord(cnst.kind == nkObjConstr)

proc isRunnableExamples*(n: PNode): bool =
Expand Down
25 changes: 13 additions & 12 deletions compiler/types.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1226,28 +1226,29 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
b = skipTypes(b[^1], {tyAlias})
assert(a != nil)
assert(b != nil)
if a.kind != b.kind:
case c.cmp
of dcEq: return false
of dcEqIgnoreDistinct:
a = a.skipTypes({tyDistinct, tyGenericInst})
b = b.skipTypes({tyDistinct, tyGenericInst})
if a.kind != b.kind: return false
of dcEqOrDistinctOf:
a = a.skipTypes({tyDistinct, tyGenericInst})
if a.kind != b.kind: return false
case c.cmp
of dcEq:
if a.kind != b.kind: return false
of dcEqIgnoreDistinct:
a = a.skipTypes({tyDistinct, tyGenericInst})
b = b.skipTypes({tyDistinct, tyGenericInst})
if a.kind != b.kind: return false
of dcEqOrDistinctOf:
a = a.skipTypes({tyDistinct, tyGenericInst})
if a.kind != b.kind: return false

#[
The following code should not run in the case either side is an generic alias,
but it's not presently possible to distinguish the genericinsts from aliases of
objects ie `type A[T] = SomeObject`
]#
# this is required by tunique_type but makes no sense really:
if tyDistinct notin {x.kind, y.kind} and x.kind == tyGenericInst and IgnoreTupleFields notin c.flags:
if c.cmp == dcEq and x.kind == tyGenericInst and
IgnoreTupleFields notin c.flags and tyDistinct != y.kind:
let
lhs = x.skipGenericAlias
rhs = y.skipGenericAlias
if rhs.kind != tyGenericInst or lhs.base != rhs.base:
if rhs.kind != tyGenericInst or lhs.base != rhs.base or rhs.kidsLen != lhs.kidsLen:
return false
for i in 1..<lhs.len - 1:
let ff = rhs[i]
Expand Down
Loading