Compare commits

..

1 Commits

Author SHA1 Message Date
ringabout
6928aa0d20 implements cbuilder 2024-09-16 22:30:36 +08:00
90 changed files with 310 additions and 1391 deletions

View File

@@ -128,7 +128,8 @@ is often an easy workaround.
context changes.
Since this change may affect runtime behavior, the experimental switch
`openSym` needs to be enabled; and a warning is given in the case where an
`openSym`, or `genericsOpenSym` and `templateOpenSym` for only the respective
routines, needs to be enabled; and a warning is given in the case where an
injected symbol would replace a captured symbol not bound by `bind` and
the experimental switch isn't enabled.
@@ -149,7 +150,7 @@ is often an easy workaround.
value # warning: a new `value` has been injected, use `bind` or turn on `experimental:openSym`
echo oldTempl() # "captured"
{.experimental: "openSym".}
{.experimental: "openSym".} # or {.experimental: "genericsOpenSym".} for just generic procs
proc bar[T](): string =
foo(123):
@@ -162,6 +163,8 @@ is often an easy workaround.
return value
assert baz[int]() == "captured"
# {.experimental: "templateOpenSym".} would be needed here if genericsOpenSym was used
template barTempl(): string =
block:
foo(123):
@@ -182,34 +185,6 @@ is often an easy workaround.
experimental feature should still handle `nnkOpenSym`, as the node kind would
simply not be generated as opposed to being removed.
Another experimental switch `genericsOpenSym` exists that enables this behavior
at instantiation time, meaning templates etc can enable it specifically when
they are being called. However this does not generate `nnkOpenSym` nodes
(unless the other switch is enabled) and so doesn't reflect the regular
behavior of the switch.
```nim
const value = "captured"
template foo(x: int, body: untyped): untyped =
let value {.inject.} = "injected"
{.push experimental: "genericsOpenSym".}
body
{.pop.}
proc bar[T](): string =
foo(123):
return value
echo bar[int]() # "injected"
template barTempl(): string =
block:
var res: string
foo(123):
res = value
res
assert barTempl() == "injected"
```
## Compiler changes
- `--nimcache` using a relative path as the argument in a config file is now relative to the config file instead of the current directory.

View File

@@ -1057,11 +1057,8 @@ proc getDeclPragma*(n: PNode): PNode =
proc extractPragma*(s: PSym): PNode =
## gets the pragma node of routine/type/var/let/const symbol `s`
if s.kind in routineKinds: # bug #24167
if s.ast[pragmasPos] != nil and s.ast[pragmasPos].kind != nkEmpty:
result = s.ast[pragmasPos]
else:
result = nil
if s.kind in routineKinds:
result = s.ast[pragmasPos]
elif s.kind in {skType, skVar, skLet, skConst}:
if s.ast != nil and s.ast.len > 0:
if s.ast[0].kind == nkPragmaExpr and s.ast[0].len > 1:

19
compiler/cbuilder.nim Normal file
View File

@@ -0,0 +1,19 @@
type
Snippet = string
Builder = string
template newBuilder(s: string): Builder =
s
proc addField(obj: var Builder; field: Snippet;) =
obj.add field
obj.add ";\n"
template withStruct(obj: var Builder; structOrUnion: string; name: string; inheritance: string; body: typed) =
if inheritance.len > 0:
obj.add "$1 $2 : public $1 {$n" % [structOrUnion, name, inheritance]
else:
obj.add "$1 $2 {$n" % [structOrUnion, name]
body
obj.add("};\n")

View File

@@ -798,36 +798,59 @@ proc fillObjectFields*(m: BModule; typ: PType) =
proc mangleDynLibProc(sym: PSym): Rope
proc getRecordDescAux(m: BModule; typ: PType, name, baseType: Rope,
check: var IntSet, hasField:var bool): Rope =
result = ""
if typ.kind == tyObject:
if typ.baseClass == nil:
if lacksMTypeField(typ):
appcg(m, result, " {$n", [])
else:
if optTinyRtti in m.config.globalOptions:
appcg(m, result, " {$n#TNimTypeV2* m_type;$n", [])
when defined(nimUseCBuilder):
proc getRecordDescAux(result: var Builder; m: BModule; typ: PType, name, baseType: Rope,
check: var IntSet, hasField: var bool) =
if typ.kind == tyObject:
if typ.baseClass == nil:
if lacksMTypeField(typ):
discard
else:
appcg(m, result, " {$n#TNimType* m_type;$n", [])
if optTinyRtti in m.config.globalOptions:
var field = "" # TODO: handle #
appcg(m, field, "#TNimTypeV2* m_type", [])
result.addField field
else:
var field = ""
appcg(m, field, "#TNimType* m_type", [])
result.addField field
hasField = true
else:
result.addField "$1 Sup" % [baseType]
hasField = true
elif m.compileToCpp:
appcg(m, result, " : public $1 {$n", [baseType])
if typ.isException and m.config.exc == excCpp:
when false:
appcg(m, result, "virtual void raise() { throw *this; }$n", []) # required for polymorphic exceptions
if typ.sym.magic == mException:
# Add cleanup destructor to Exception base class
appcg(m, result, "~$1();$n", [name])
# define it out of the class body and into the procs section so we don't have to
# artificially forward-declare popCurrentExceptionEx (very VERY troublesome for HCR)
appcg(m, cfsProcs, "inline $1::~$1() {if(this->raiseId) #popCurrentExceptionEx(this->raiseId);}$n", [name])
hasField = true
else:
appcg(m, result, " {$n $1 Sup;$n", [baseType])
hasField = true
else:
result.addf(" {$n", [name])
discard
else:
proc getRecordDescAux(m: BModule; typ: PType, name, baseType: Rope,
check: var IntSet, hasField:var bool): Rope =
result = ""
if typ.kind == tyObject:
if typ.baseClass == nil:
if lacksMTypeField(typ):
appcg(m, result, " {$n", [])
else:
if optTinyRtti in m.config.globalOptions:
appcg(m, result, " {$n#TNimTypeV2* m_type;$n", [])
else:
appcg(m, result, " {$n#TNimType* m_type;$n", [])
hasField = true
elif m.compileToCpp:
appcg(m, result, " : public $1 {$n", [baseType])
if typ.isException and m.config.exc == excCpp:
when false:
appcg(m, result, "virtual void raise() { throw *this; }$n", []) # required for polymorphic exceptions
if typ.sym.magic == mException:
# Add cleanup destructor to Exception base class
appcg(m, result, "~$1();$n", [name])
# define it out of the class body and into the procs section so we don't have to
# artificially forward-declare popCurrentExceptionEx (very VERY troublesome for HCR)
appcg(m, cfsProcs, "inline $1::~$1() {if(this->raiseId) #popCurrentExceptionEx(this->raiseId);}$n", [name])
hasField = true
else:
appcg(m, result, " {$n $1 Sup;$n", [baseType])
hasField = true
else:
result.addf(" {$n", [name])
proc getRecordDesc(m: BModule; typ: PType, name: Rope,
check: var IntSet): Rope =
@@ -845,21 +868,52 @@ proc getRecordDesc(m: BModule; typ: PType, name: Rope,
if typ.baseClass != nil:
baseType = getTypeDescAux(m, typ.baseClass.skipTypes(skipPtrs), check, dkField)
if typ.sym == nil or sfCodegenDecl notin typ.sym.flags:
result = structOrUnion & " " & name
result.add(getRecordDescAux(m, typ, name, baseType, check, hasField))
let desc = getRecordFields(m, typ, check)
if not hasField and typ.itemId notin m.g.graph.memberProcsPerType:
if desc == "":
result.add("\tchar dummy;\n")
elif typ.n.len == 1 and typ.n[0].kind == nkSym:
let field = typ.n[0].sym
let fieldType = field.typ.skipTypes(abstractInst)
if fieldType.kind == tyUncheckedArray:
result.add("\tchar dummy;\n")
result.add(desc)
when defined(nimUseCBuilder):
result = newBuilder("")
let isCppInheritance = typ.kind == tyObject and m.compileToCpp and typ.baseClass != nil
withStruct(result, structOrUnion, name, if isCppInheritance: baseType else: ""):
if isCppInheritance:
hasField = true
if typ.isException and m.config.exc == excCpp:
when false:
appcg(m, result, "virtual void raise() { throw *this; }$n", []) # required for polymorphic exceptions
if typ.sym.magic == mException:
# Add cleanup destructor to Exception base class
appcg(m, result, "~$1();$n", [name])
# define it out of the class body and into the procs section so we don't have to
# artificially forward-declare popCurrentExceptionEx (very VERY troublesome for HCR)
appcg(m, cfsProcs, "inline $1::~$1() {if(this->raiseId) #popCurrentExceptionEx(this->raiseId);}$n", [name])
else:
getRecordDescAux(result, m, typ, name, baseType, check, hasField)
let desc = getRecordFields(m, typ, check)
if not hasField and typ.itemId notin m.g.graph.memberProcsPerType:
if desc == "":
result.add("\tchar dummy;\n")
elif typ.n.len == 1 and typ.n[0].kind == nkSym:
let field = typ.n[0].sym
let fieldType = field.typ.skipTypes(abstractInst)
if fieldType.kind == tyUncheckedArray:
result.add("\tchar dummy;\n")
result.add(desc)
else:
result.add(desc)
result.add("};\L")
else:
result.add(desc)
result.add("};\L")
result = structOrUnion & " " & name
result.add(getRecordDescAux(m, typ, name, baseType, check, hasField))
let desc = getRecordFields(m, typ, check)
if not hasField and typ.itemId notin m.g.graph.memberProcsPerType:
if desc == "":
result.add("\tchar dummy;\n")
elif typ.n.len == 1 and typ.n[0].kind == nkSym:
let field = typ.n[0].sym
let fieldType = field.typ.skipTypes(abstractInst)
if fieldType.kind == tyUncheckedArray:
result.add("\tchar dummy;\n")
result.add(desc)
else:
result.add(desc)
result.add("};\L")
else:
let desc = getRecordFields(m, typ, check)
result = runtimeFormat(typ.sym.cgDeclFrmt, [name, desc, baseType])
@@ -868,14 +922,15 @@ proc getRecordDesc(m: BModule; typ: PType, name: Rope,
proc getTupleDesc(m: BModule; typ: PType, name: Rope,
check: var IntSet): Rope =
result = "$1 $2 {$n" % [structOrUnion(typ), name]
var desc: Rope = ""
for i, a in typ.ikids:
desc.addf("$1 Field$2;$n",
[getTypeDescAux(m, a, check, dkField), rope(i)])
if desc == "": result.add("char dummy;\L")
else: result.add(desc)
result.add("};\L")
if kidsLen(typ) > 0:
result = newBuilder("")
withStruct(result, structOrUnion(typ), name, ""):
for i, a in typ.ikids:
result.addField "$1 Field$2" % [getTypeDescAux(m, a, check, dkField), rope(i)]
else:
result = newBuilder("")
withStruct(result, structOrUnion(typ), name, ""):
result.addField "char dummy"
proc scanCppGenericSlot(pat: string, cursor, outIdx, outStars: var int): bool =
# A helper proc for handling cppimport patterns, involving numeric
@@ -932,11 +987,12 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
if t != origTyp and origTyp.sym != nil: useHeader(m, origTyp.sym)
let sig = hashType(origTyp, m.config)
result = getTypePre(m, t, sig)
result = "" # todo move `result = getTypePre(m, t, sig)` here ?
defer: # defer is the simplest in this case
if isImportedType(t) and not m.typeABICache.containsOrIncl(sig):
addAbiCheck(m, t, result)
result = getTypePre(m, t, sig)
if result != "" and t.kind != tyOpenArray:
excl(check, t.id)
if kind == dkRefParam or kind == dkRefGenericParam and origTyp.kind == tyGenericInst:

View File

@@ -373,6 +373,7 @@ proc dataField(p: BProc): Rope =
proc genProcPrototype(m: BModule, sym: PSym)
include cbuilder
include ccgliterals
include ccgtypes
@@ -783,11 +784,15 @@ $1define nimfr_(proc, file) \
TFrame FR_; \
FR_.procname = proc; FR_.filename = file; FR_.line = 0; FR_.len = 0; #nimFrame(&FR_);
$1define nimln_(n) \
FR_.line = n;
$1define nimfrs_(proc, file, slots, length) \
struct {TFrame* prev;NCSTRING procname;NI line;NCSTRING filename;NI len;VarSlot s[slots];} FR_; \
FR_.procname = proc; FR_.filename = file; FR_.line = 0; FR_.len = length; #nimFrame((TFrame*)&FR_);
$1define nimlf_(n, file) \
FR_.line = n; FR_.filename = file;
$1define nimln_(n) \
FR_.line = n;
$1define nimlf_(n, file) \
FR_.line = n; FR_.filename = file;
"""
if p.module.s[cfsFrameDefines].len == 0:

View File

@@ -167,5 +167,4 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimHasVtables")
defineSymbol("nimHasGenericsOpenSym2")
defineSymbol("nimHasGenericsOpenSym3")
defineSymbol("nimHasJsNoLambdaLifting")

View File

@@ -246,8 +246,7 @@ proc importModuleAs(c: PContext; n: PNode, realModule: PSym, importHidden: bool)
result = createModuleAliasImpl(realModule.name)
if importHidden:
result.options.incl optImportHidden
let moduleIdent = if n.kind == nkInfix: n[^1] else: n
c.unusedImports.add((result, moduleIdent.info))
c.unusedImports.add((result, n.info))
c.importModuleMap[result.id] = realModule.id
c.importModuleLookup.mgetOrPut(result.name.id, @[]).addUnique realModule.id

View File

@@ -224,16 +224,10 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool,
proc fillBodyObjTImpl(c: var TLiftCtx; t: PType, body, x, y: PNode) =
if t.baseClass != nil:
let dest = newNodeIT(nkHiddenSubConv, c.info, t.baseClass)
dest.add newNodeI(nkEmpty, c.info)
dest.add x
var src = y
if c.kind in {attachedAsgn, attachedDeepCopy, attachedSink}:
src = newNodeIT(nkHiddenSubConv, c.info, t.baseClass)
src.add newNodeI(nkEmpty, c.info)
src.add y
fillBody(c, skipTypes(t.baseClass, abstractPtrs), body, dest, src)
let obj = newNodeIT(nkHiddenSubConv, c.info, t.baseClass)
obj.add newNodeI(nkEmpty, c.info)
obj.add x
fillBody(c, skipTypes(t.baseClass, abstractPtrs), body, obj, y)
fillBodyObj(c, t.n, body, x, y, enforceDefaultOp = false)
proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =

View File

@@ -629,7 +629,7 @@ proc warningDeprecated*(conf: ConfigRef, info: TLineInfo = gCmdLineInfo, msg = "
message(conf, info, warnDeprecated, msg)
proc internalErrorImpl(conf: ConfigRef; info: TLineInfo, errMsg: string, info2: InstantiationInfo) =
if conf.cmd in {cmdIdeTools, cmdCheck} and conf.structuredErrorHook.isNil: return
if conf.cmd == cmdIdeTools and conf.structuredErrorHook.isNil: return
writeContext(conf, info)
liMessage(conf, info, errInternal, errMsg, doAbort, info2)

View File

@@ -226,8 +226,8 @@ type
strictCaseObjects,
inferGenericTypes,
openSym, # remove nfDisabledOpenSym when this is default
# alternative to above:
genericsOpenSym
# separated alternatives to above:
genericsOpenSym, templateOpenSym,
vtables
LegacyFeature* = enum

View File

@@ -1401,7 +1401,7 @@ proc primary(p: var Parser, mode: PrimaryMode): PNode =
result = primarySuffix(p, result, baseInd, mode)
proc binaryNot(p: var Parser; a: PNode): PNode =
if p.tok.tokType == tkNot and p.tok.indent < 0:
if p.tok.tokType == tkNot:
let notOpr = newIdentNodeP(p.tok.ident, p)
getTok(p)
optInd(p, notOpr)

View File

@@ -800,14 +800,13 @@ proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym =
proc semCustomPragma(c: PContext, n: PNode, sym: PSym): PNode =
var callNode: PNode
case n.kind
of nkIdentKinds:
if n.kind in {nkIdent, nkSym}:
# pragma -> pragma()
callNode = newTree(nkCall, n)
of nkExprColonExpr:
elif n.kind == nkExprColonExpr:
# pragma: arg -> pragma(arg)
callNode = newTree(nkCall, n[0], n[1])
of nkPragmaCallKinds - {nkExprColonExpr}:
elif n.kind in nkPragmaCallKinds:
callNode = n
else:
invalidPragma(c, n)
@@ -1344,16 +1343,6 @@ proc mergePragmas(n, pragmas: PNode) =
else:
for p in pragmas: n[pragmasPos].add p
proc mergeValidPragmas(n, pragmas: PNode, validPragmas: TSpecialWords) =
if n[pragmasPos].kind == nkEmpty:
n[pragmasPos] = newNodeI(nkPragma, n.info)
for p in pragmas:
let prag = whichPragma(p)
if prag in validPragmas:
let copy = copyTree(p)
overwriteLineInfo copy, n.info
n[pragmasPos].add copy
proc implicitPragmas*(c: PContext, sym: PSym, info: TLineInfo,
validPragmas: TSpecialWords) =
if sym != nil and sym.kind != skModule:
@@ -1367,8 +1356,7 @@ proc implicitPragmas*(c: PContext, sym: PSym, info: TLineInfo,
internalError(c.config, info, "implicitPragmas")
inc i
popInfoContext(c.config)
if sym.kind in routineKinds and sym.ast != nil:
mergeValidPragmas(sym.ast, o, validPragmas)
if sym.kind in routineKinds and sym.ast != nil: mergePragmas(sym.ast, o)
if lfExportLib in sym.loc.flags and sfExportc notin sym.flags:
localError(c.config, info, ".dynlib requires .exportc")

View File

@@ -246,18 +246,10 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
candidates.add(getProcHeader(c.config, err.sym, prefer))
candidates.addDeclaredLocMaybe(c.config, err.sym)
candidates.add("\n")
const genericParamMismatches = {kGenericParamTypeMismatch, kExtraGenericParam, kMissingGenericParam}
let isGenericMismatch = err.firstMismatch.kind in genericParamMismatches
var argList = n
if isGenericMismatch and n[0].kind == nkBracketExpr:
argList = n[0]
let nArg =
if err.firstMismatch.arg < argList.len:
argList[err.firstMismatch.arg]
else:
nil
let nArg = if err.firstMismatch.arg < n.len: n[err.firstMismatch.arg] else: nil
let nameParam = if err.firstMismatch.formal != nil: err.firstMismatch.formal.name.s else: ""
if n.len > 1:
const genericParamMismatches = {kGenericParamTypeMismatch, kExtraGenericParam, kMissingGenericParam}
if verboseTypeMismatch notin c.config.legacyFeatures:
case err.firstMismatch.kind
of kUnknownNamedParam:
@@ -317,7 +309,7 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
var wanted = err.firstMismatch.formal.typ
if wanted.kind == tyGenericParam and wanted.genericParamHasConstraints:
wanted = wanted.genericConstraint
let got = arg.typ.skipTypes({tyTypeDesc})
let got = arg.typ
doAssert err.firstMismatch.formal != nil
doAssert wanted != nil
doAssert got != nil
@@ -358,9 +350,17 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
of kMissingGenericParam:
candidates.add("\n missing generic parameter: " & nameParam)
of kTypeMismatch, kGenericParamTypeMismatch, kVarNeeded:
doAssert nArg != nil
var arg: PNode = nArg
let genericMismatch = err.firstMismatch.kind == kGenericParamTypeMismatch
if genericMismatch:
let pos = err.firstMismatch.arg
doAssert n[0].kind == nkBracketExpr and pos < n[0].len
arg = n[0][pos]
else:
arg = nArg
doAssert arg != nil
var wanted = err.firstMismatch.formal.typ
if isGenericMismatch and wanted.kind == tyGenericParam and
if genericMismatch and wanted.kind == tyGenericParam and
wanted.genericParamHasConstraints:
wanted = wanted.genericConstraint
doAssert err.firstMismatch.formal != nil
@@ -368,17 +368,16 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
candidates.addTypeDeclVerboseMaybe(c.config, wanted)
candidates.add "\n but expression '"
if err.firstMismatch.kind == kVarNeeded:
candidates.add renderNotLValue(nArg)
candidates.add renderNotLValue(arg)
candidates.add "' is immutable, not 'var'"
else:
candidates.add renderTree(nArg)
candidates.add renderTree(arg)
candidates.add "' is of type: "
var got = nArg.typ
if isGenericMismatch: got = got.skipTypes({tyTypeDesc})
let got = arg.typ
candidates.addTypeDeclVerboseMaybe(c.config, got)
if nArg.kind in nkSymChoices:
if arg.kind in nkSymChoices:
candidates.add "\n"
candidates.add ambiguousIdentifierMsg(nArg, indent = 2)
candidates.add ambiguousIdentifierMsg(arg, indent = 2)
doAssert wanted != nil
if got != nil:
if got.kind == tyProc and wanted.kind == tyProc:

View File

@@ -75,7 +75,6 @@ type
# overload resolution.
efTypeAllowed # typeAllowed will be called after
efWantNoDefaults
efIgnoreDefaults # var statements without initialization
efAllowSymChoice # symchoice node should not be resolved
TExprFlags* = set[TExprFlag]

View File

@@ -187,7 +187,6 @@ proc semOpenSym(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType,
break
o = o.owner
# nothing found
n.flags.excl nfDisabledOpenSym
if not warnDisabled and isSym:
result = semExpr(c, n, flags, expectedType)
else:
@@ -198,9 +197,7 @@ proc semOpenSym(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType,
proc semSymChoice(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode =
if n.kind == nkOpenSymChoice:
result = semOpenSym(c, n, flags, expectedType,
warnDisabled = nfDisabledOpenSym in n.flags and
genericsOpenSym notin c.features)
result = semOpenSym(c, n, flags, expectedType, warnDisabled = nfDisabledOpenSym in n.flags)
if result != nil:
return
result = n
@@ -3296,12 +3293,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
of nkSym:
let s = n.sym
if nfDisabledOpenSym in n.flags:
let override = genericsOpenSym in c.features
let res = semOpenSym(c, n, flags, expectedType,
warnDisabled = not override)
if res != nil:
assert override
return res
let res = semOpenSym(c, n, flags, expectedType, warnDisabled = true)
assert res == nil
# because of the changed symbol binding, this does not mean that we
# don't have to check the symbol for semantics here again!
result = semSym(c, n, s, flags)
@@ -3314,7 +3307,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
of nkNilLit:
if result.typ == nil:
result.typ = getNilType(c)
if expectedType != nil and expectedType.kind notin {tyUntyped, tyTyped}:
if expectedType != nil:
var m = newCandidate(c, result.typ)
if typeRel(m, expectedType, result.typ) >= isSubtype:
result.typ = expectedType

View File

@@ -74,7 +74,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
else:
result = symChoice(c, n, s, scOpen)
if canOpenSym(s):
if openSym in c.features:
if {openSym, genericsOpenSym} * c.features != {}:
if result.kind == nkSym:
result = newOpenSym(result)
else:
@@ -112,7 +112,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
# we are in a generic context and `prepareNode` will be called
result = newSymNodeTypeDesc(s, c.idgen, n.info)
if canOpenSym(result.sym):
if openSym in c.features:
if {openSym, genericsOpenSym} * c.features != {}:
result = newOpenSym(result)
else:
result.flags.incl nfDisabledOpenSym
@@ -122,7 +122,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
else:
result = newSymNodeTypeDesc(s, c.idgen, n.info)
if canOpenSym(result.sym):
if openSym in c.features:
if {openSym, genericsOpenSym} * c.features != {}:
result = newOpenSym(result)
else:
result.flags.incl nfDisabledOpenSym
@@ -141,7 +141,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
return
result = newSymNodeTypeDesc(s, c.idgen, n.info)
if canOpenSym(result.sym):
if openSym in c.features:
if {openSym, genericsOpenSym} * c.features != {}:
result = newOpenSym(result)
else:
result.flags.incl nfDisabledOpenSym
@@ -153,7 +153,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
# we are in a generic context and `prepareNode` will be called
result = newSymNodeTypeDesc(s, c.idgen, n.info)
if canOpenSym(result.sym):
if openSym in c.features:
if {openSym, genericsOpenSym} * c.features != {}:
result = newOpenSym(result)
else:
result.flags.incl nfDisabledOpenSym
@@ -164,7 +164,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
else:
result = newSymNode(s, n.info)
if canOpenSym(result.sym):
if openSym in c.features:
if {openSym, genericsOpenSym} * c.features != {}:
result = newOpenSym(result)
else:
result.flags.incl nfDisabledOpenSym

View File

@@ -254,8 +254,6 @@ proc instantiateProcType(c: PContext, pt: TypeMapping,
let needsStaticSkipping = resulti.kind == tyFromExpr
let needsTypeDescSkipping = resulti.kind == tyTypeDesc and tfUnresolved in resulti.flags
if resulti.kind == tyFromExpr:
resulti.flags.incl tfNonConstExpr
result[i] = replaceTypeVarsT(cl, resulti)
if needsStaticSkipping:
result[i] = result[i].skipTypes({tyStatic})

View File

@@ -50,8 +50,8 @@ proc semTypeOf(c: PContext; n: PNode): PNode =
m = mode.intVal
result = newNodeI(nkTypeOfExpr, n.info)
inc c.inTypeofContext
defer: dec c.inTypeofContext # compiles can raise an exception
let typExpr = semExprWithType(c, n[1], if m == 1: {efInTypeof} else: {})
dec c.inTypeofContext
result.add typExpr
if typExpr.typ.kind == tyFromExpr:
typExpr.typ.flags.incl tfNonConstExpr

View File

@@ -387,13 +387,10 @@ proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
if e != nil:
result.status = initFull
elif field.ast != nil:
if efIgnoreDefaults notin flags:
result.status = initUnknown
result.defaults.add newTree(nkExprColonExpr, n, field.ast)
else:
result.status = initNone
result.status = initUnknown
result.defaults.add newTree(nkExprColonExpr, n, field.ast)
else:
if {efWantNoDefaults, efIgnoreDefaults} * flags == {}: # cannot compute defaults at the typeRightPass
if efWantNoDefaults notin flags: # cannot compute defaults at the typeRightPass
let defaultExpr = defaultNodeField(c, n, constrCtx.checkDefault)
if defaultExpr != nil:
result.status = initUnknown
@@ -446,7 +443,7 @@ proc defaultConstructionError(c: PContext, t: PType, info: TLineInfo) =
assert objType != nil
if objType.kind == tyObject:
var constrCtx = initConstrContext(objType, newNodeI(nkObjConstr, info))
let initResult = semConstructTypeAux(c, constrCtx, {efIgnoreDefaults})
let initResult = semConstructTypeAux(c, constrCtx, {efWantNoDefaults})
if constrCtx.missingFields.len > 0:
localError(c.config, info,
"The $1 type doesn't have a default value. The following fields must be initialized: $2." % [typeToString(t), listSymbolNames(constrCtx.missingFields)])

View File

@@ -1210,7 +1210,7 @@ proc track(tracked: PEffects, n: PNode) =
if n.sym.typ != nil and tfHasAsgn in n.sym.typ.flags:
tracked.owner.flags.incl sfInjectDestructors
# bug #15038: ensure consistency
if n.typ == nil or (not hasDestructor(n.typ) and sameType(n.typ, n.sym.typ)): n.typ = n.sym.typ
if not hasDestructor(n.typ) and sameType(n.typ, n.sym.typ): n.typ = n.sym.typ
of nkHiddenAddr, nkAddr:
if n[0].kind == nkSym and isLocalSym(tracked, n[0].sym) and
n.typ.kind notin {tyVar, tyLent}:

View File

@@ -233,7 +233,7 @@ proc semTemplSymbol(c: var TemplCtx, n: PNode, s: PSym; isField, isAmbiguous: bo
of OverloadableSyms:
result = symChoice(c.c, n, s, scOpen, isField)
if not isField and result.kind in {nkSym, nkOpenSymChoice}:
if openSym in c.c.features:
if {openSym, templateOpenSym} * c.c.features != {}:
if result.kind == nkSym:
result = newOpenSym(result)
else:
@@ -246,7 +246,7 @@ proc semTemplSymbol(c: var TemplCtx, n: PNode, s: PSym; isField, isAmbiguous: bo
else:
result = newSymNodeTypeDesc(s, c.c.idgen, n.info)
if not isField and s.owner != c.owner:
if openSym in c.c.features:
if {openSym, templateOpenSym} * c.c.features != {}:
result = newOpenSym(result)
else:
result.flags.incl nfDisabledOpenSym
@@ -264,7 +264,7 @@ proc semTemplSymbol(c: var TemplCtx, n: PNode, s: PSym; isField, isAmbiguous: bo
if not isField and not (s.owner == c.owner and
s.typ != nil and s.typ.kind == tyGenericParam) and
result.kind in {nkSym, nkOpenSymChoice}:
if openSym in c.c.features:
if {openSym, templateOpenSym} * c.c.features != {}:
if result.kind == nkSym:
result = newOpenSym(result)
else:
@@ -277,7 +277,7 @@ proc semTemplSymbol(c: var TemplCtx, n: PNode, s: PSym; isField, isAmbiguous: bo
else:
result = newSymNode(s, n.info)
if not isField:
if openSym in c.c.features:
if {openSym, templateOpenSym} * c.c.features != {}:
result = newOpenSym(result)
else:
result.flags.incl nfDisabledOpenSym
@@ -693,7 +693,6 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
pushOwner(c, s)
openScope(c)
n[namePos] = newSymNode(s)
s.ast = n # for implicitPragmas to use
pragmaCallable(c, s, n, templatePragmas)
implicitPragmas(c, s, n.info, templatePragmas)
@@ -764,6 +763,11 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
closeScope(c)
popOwner(c)
# set the symbol AST after pragmas, at least. This stops pragma that have
# been pushed (implicit) to be explicitly added to the template definition
# and misapplied to the body. see #18113
s.ast = n
if sfCustomPragma in s.flags:
if n[bodyPos].kind != nkEmpty:
localError(c.config, n[bodyPos].info, errImplOfXNotAllowed % s.name.s)

View File

@@ -619,8 +619,6 @@ proc semCaseBranch(c: PContext, n, branch: PNode, branchIndex: int,
var b = branch[i]
if b.kind == nkRange:
branch[i] = b
# same check as in semBranchRange for exhaustiveness
covered = covered + getOrdValue(b[1]) + 1 - getOrdValue(b[0])
elif isRange(b):
branch[i] = semCaseBranchRange(c, n, b, covered)
else:
@@ -1866,8 +1864,8 @@ proc semStaticType(c: PContext, childNode: PNode, prev: PType): PType =
proc semTypeOf(c: PContext; n: PNode; prev: PType): PType =
openScope(c)
inc c.inTypeofContext
defer: dec c.inTypeofContext # compiles can raise an exception
let t = semExprWithType(c, n, {efInTypeof})
dec c.inTypeofContext
closeScope(c)
fixupTypeOf(c, prev, t)
result = t.typ
@@ -1884,8 +1882,8 @@ proc semTypeOf2(c: PContext; n: PNode; prev: PType): PType =
else:
m = mode.intVal
inc c.inTypeofContext
defer: dec c.inTypeofContext # compiles can raise an exception
let t = semExprWithType(c, n[1], if m == 1: {efInTypeof} else: {})
dec c.inTypeofContext
closeScope(c)
fixupTypeOf(c, prev, t)
result = t.typ

View File

@@ -1125,21 +1125,9 @@ proc inferStaticsInRange(c: var TCandidate,
doInferStatic(lowerBound, getInt(upperBound) + 1 - lengthOrd(c.c.config, concrete))
template subtypeCheck() =
case result
of isIntConv:
if result <= isSubrange and f.last.skipTypes(abstractInst).kind in {
tyRef, tyPtr, tyVar, tyLent, tyOwned}:
result = isNone
of isSubrange:
discard # XXX should be isNone with preview define, warnings
of isConvertible:
if f.last.skipTypes(abstractInst).kind != tyOpenArray:
# exclude var openarray which compiler supports
result = isNone
of isSubtype:
if f.last.skipTypes(abstractInst).kind in {
tyRef, tyPtr, tyVar, tyLent, tyOwned}:
# compiler can't handle subtype conversions with pointer indirection
result = isNone
else: discard
proc isCovariantPtr(c: var TCandidate, f, a: PType): bool =
# this proc is always called for a pair of matching types
@@ -1291,11 +1279,6 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
if prev == nil: body
else: return typeRel(c, prev, a, flags)
if c.c.inGenericContext > 0 and not c.isNoCall and
(tfUnresolved in a.flags or a.kind in tyTypeClasses):
# cheap check for unresolved arg, not nested
return isNone
case a.kind
of tyOr:
# XXX: deal with the current dual meaning of tyGenericParam
@@ -1540,7 +1523,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
reduceToBase(a)
if effectiveArgType.kind == tyObject:
if sameObjectTypes(f, effectiveArgType):
c.inheritancePenalty = if tfFinal in f.flags: -1 else: 0
c.inheritancePenalty = 0
result = isEqual
# elif tfHasMeta in f.flags: result = recordRel(c, f, a)
elif trIsOutParam notin flags:
@@ -2113,15 +2096,15 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
# not resolved
result = isNone
of tyTypeDesc:
result = typeRel(c, reevaluated.base, a, flags)
result = typeRel(c, a, reevaluated.base, flags)
of tyStatic:
result = typeRel(c, reevaluated.base, a, flags)
result = typeRel(c, a, reevaluated.base, flags)
if result != isNone and reevaluated.n != nil:
if not exprStructuralEquivalent(aOrig.n, reevaluated.n):
result = isNone
else:
# bug #14136: other types are just like 'tyStatic' here:
result = typeRel(c, reevaluated, a, flags)
result = typeRel(c, a, reevaluated, flags)
if result != isNone and reevaluated.n != nil:
if not exprStructuralEquivalent(aOrig.n, reevaluated.n):
result = isNone

View File

@@ -511,12 +511,7 @@ proc transformAddrDeref(c: PTransf, n: PNode, kinds: TNodeKinds): PNode =
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)
: # elimination is harmful to `for tuple unpack` because of newTupleAccess
# it is also harmful to openArrayLoc (var openArray) for strings
): # elimination is harmful to `for tuple unpack` because of newTupleAccess
# addr ( deref ( x )) --> x
result = n[0][0]
if n.typ.skipTypes(abstractVar).kind != tyOpenArray:

View File

@@ -609,10 +609,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
of opcYldVal: assert false
of opcAsgnInt:
decodeB(rkInt)
if regs[rb].kind == rkInt:
regs[ra].intVal = regs[rb].intVal
else:
stackTrace(c, tos, pc, "opcAsgnInt: got " & $regs[rb].kind)
regs[ra].intVal = regs[rb].intVal
of opcAsgnFloat:
decodeB(rkFloat)
regs[ra].floatVal = regs[rb].floatVal
@@ -679,19 +676,16 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
else:
assert regs[rb].kind == rkNode
let nb = regs[rb].node
if nb == nil:
stackTrace(c, tos, pc, errNilAccess)
case nb.kind
of nkCharLit..nkUInt64Lit:
ensureKind(rkInt)
regs[ra].intVal = nb.intVal
of nkFloatLit..nkFloat64Lit:
ensureKind(rkFloat)
regs[ra].floatVal = nb.floatVal
else:
case nb.kind
of nkCharLit..nkUInt64Lit:
ensureKind(rkInt)
regs[ra].intVal = nb.intVal
of nkFloatLit..nkFloat64Lit:
ensureKind(rkFloat)
regs[ra].floatVal = nb.floatVal
else:
ensureKind(rkNode)
regs[ra].node = nb
ensureKind(rkNode)
regs[ra].node = nb
of opcSlice:
# A bodge, but this takes in `toOpenArray(rb, rc, rc)` and emits
# nkTupleConstr(x, y, z) into the `regs[ra]`. These can later be used for calculating the slice we have taken.
@@ -856,30 +850,25 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
of opcLdObj:
# a = b.c
decodeBC(rkNode)
if rb >= regs.len or regs[rb].kind == rkNone or
(regs[rb].kind == rkNode and regs[rb].node == nil) or
(regs[rb].kind == rkNodeAddr and regs[rb].nodeAddr[] == nil):
stackTrace(c, tos, pc, errNilAccess)
let src = if regs[rb].kind == rkNode: regs[rb].node else: regs[rb].nodeAddr[]
case src.kind
of nkEmpty..nkNilLit:
# for nkPtrLit, this could be supported in the future, use something like:
# derefPtrToReg(src.intVal + offsetof(src.typ, rc), typ_field, regs[ra], isAssign = false)
# where we compute the offset in bytes for field rc
stackTrace(c, tos, pc, errNilAccess & " " & $("kind", src.kind, "typ", typeToString(src.typ), "rc", rc))
of nkObjConstr:
let n = src[rc + 1].skipColon
regs[ra].node = n
of nkTupleConstr:
let n = if src.typ != nil and tfTriggersCompileTime in src.typ.flags:
src[rc]
else:
src[rc].skipColon
regs[ra].node = n
else:
let src = if regs[rb].kind == rkNode: regs[rb].node else: regs[rb].nodeAddr[]
case src.kind
of nkEmpty..nkNilLit:
# for nkPtrLit, this could be supported in the future, use something like:
# derefPtrToReg(src.intVal + offsetof(src.typ, rc), typ_field, regs[ra], isAssign = false)
# where we compute the offset in bytes for field rc
stackTrace(c, tos, pc, errNilAccess & " " & $("kind", src.kind, "typ", typeToString(src.typ), "rc", rc))
of nkObjConstr:
let n = src[rc + 1].skipColon
regs[ra].node = n
of nkTupleConstr:
let n = if src.typ != nil and tfTriggersCompileTime in src.typ.flags:
src[rc]
else:
src[rc].skipColon
regs[ra].node = n
else:
let n = src[rc]
regs[ra].node = n
let n = src[rc]
regs[ra].node = n
of opcLdObjAddr:
# a = addr(b.c)
decodeBC(rkNodeAddr)

View File

@@ -245,7 +245,7 @@ proc getTemp(cc: PCtx; tt: PType): TRegister =
proc freeTemp(c: PCtx; r: TRegister) =
let c = c.prc
if r < c.regInfo.len and c.regInfo[r].kind in {slotSomeTemp..slotTempComplex}:
if c.regInfo[r].kind in {slotSomeTemp..slotTempComplex}:
# this seems to cause https://github.com/nim-lang/Nim/issues/10647
c.regInfo[r].inUse = false
@@ -357,13 +357,12 @@ proc genBlock(c: PCtx; n: PNode; dest: var TDest) =
#if c.prc.regInfo[i].kind in {slotFixedVar, slotFixedLet}:
if i != dest:
when not defined(release):
if c.config.cmd != cmdCheck:
if c.prc.regInfo[i].inUse and c.prc.regInfo[i].kind in {slotTempUnknown,
slotTempInt,
slotTempFloat,
slotTempStr,
slotTempComplex}:
raiseAssert "leaking temporary " & $i & " " & $c.prc.regInfo[i].kind
if c.prc.regInfo[i].inUse and c.prc.regInfo[i].kind in {slotTempUnknown,
slotTempInt,
slotTempFloat,
slotTempStr,
slotTempComplex}:
raiseAssert "leaking temporary " & $i & " " & $c.prc.regInfo[i].kind
c.prc.regInfo[i] = (inUse: false, kind: slotEmpty)
c.clearDest(n, dest)
@@ -697,9 +696,6 @@ proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) =
let dest = c.genx(le, {gfNodeAddr})
c.gABC(le, opcWrDeref, dest, 0, value)
c.freeTemp(dest)
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
if sameBackendType(le.typ, le[1].typ):
genAsgnPatch(c, le[1], value)
else:
discard
@@ -872,7 +868,7 @@ proc genAddSubInt(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
genBinaryABC(c, n, dest, opc)
c.genNarrow(n, dest)
proc genConv(c: PCtx; n, arg: PNode; dest: var TDest, flags: TGenFlags = {}; opc=opcConv) =
proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) =
let t2 = n.typ.skipTypes({tyDistinct})
let targ2 = arg.typ.skipTypes({tyDistinct})
@@ -886,7 +882,7 @@ proc genConv(c: PCtx; n, arg: PNode; dest: var TDest, flags: TGenFlags = {}; opc
result = false
if implicitConv():
gen(c, arg, dest, flags)
gen(c, arg, dest)
return
let tmp = c.genx(arg)
@@ -1054,7 +1050,7 @@ proc whichAsgnOpc(n: PNode; requiresCopy = true): TOpcode =
else:
(if requiresCopy: opcAsgnComplex else: opcFastAsgnComplex)
proc genMagic(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}, m: TMagic) =
proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
case m
of mAnd: c.genAndOr(n, opcFJmp, dest)
of mOr: c.genAndOr(n, opcTJmp, dest)
@@ -1193,7 +1189,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}, m: TMag
if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and size < 8):
c.gABC(n, opcNarrowU, dest, TRegister(size*8))
of mCharToStr, mBoolToStr, mCStrToStr, mStrToStr, mEnumToStr:
genConv(c, n, n[1], dest, flags)
genConv(c, n, n[1], dest)
of mEqStr: genBinaryABC(c, n, dest, opcEqStr)
of mEqCString: genBinaryABC(c, n, dest, opcEqCString)
of mLeStr: genBinaryABC(c, n, dest, opcLeStr)
@@ -1533,11 +1529,7 @@ proc setSlot(c: PCtx; v: PSym) =
if v.position == 0:
v.position = getFreeRegister(c, if v.kind == skLet: slotFixedLet else: slotFixedVar, start = 1)
template cannotEval(c: PCtx; n: PNode) =
if c.config.cmd == cmdCheck:
localError(c.config, n.info, "cannot evaluate at compile time: " &
n.renderTree)
return
proc cannotEval(c: PCtx; n: PNode) {.noinline.} =
globalError(c.config, n.info, "cannot evaluate at compile time: " &
n.renderTree)
@@ -1660,9 +1652,6 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
c.freeTemp(cc)
else:
gen(c, ri, dest)
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
if sameBackendType(le.typ, le[1].typ):
genAsgn(c, le[1], ri, requiresCopy)
else:
let dest = c.genx(le, {gfNodeAddr})
genAsgn(c, dest, ri, requiresCopy)
@@ -1753,7 +1742,7 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
s.kind in {skParam, skResult}):
if dest < 0:
dest = s.position + ord(s.kind == skParam)
internalAssert(c.config, c.prc.regInfo.len > dest and c.prc.regInfo[dest].kind < slotSomeTemp)
internalAssert(c.config, c.prc.regInfo[dest].kind < slotSomeTemp)
else:
# we need to generate an assignment:
let requiresCopy = c.prc.regInfo[dest].kind >= slotSomeTemp and
@@ -2175,7 +2164,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
if n[0].kind == nkSym:
let s = n[0].sym
if s.magic != mNone:
genMagic(c, n, dest, flags, s.magic)
genMagic(c, n, dest, s.magic)
elif s.kind == skMethod:
localError(c.config, n.info, "cannot call method " & s.name.s &
" at compile time")
@@ -2232,11 +2221,11 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
unused(c, n, dest)
gen(c, n[0])
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
genConv(c, n, n[1], dest, flags)
genConv(c, n, n[1], dest)
of nkObjDownConv:
genConv(c, n, n[0], dest, flags)
genConv(c, n, n[0], dest)
of nkObjUpConv:
genConv(c, n, n[0], dest, flags)
genConv(c, n, n[0], dest)
of nkVarSection, nkLetSection:
unused(c, n, dest)
genVarSection(c, n)
@@ -2246,7 +2235,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
genLit(c, newSymNode(n[namePos].sym), dest)
of nkChckRangeF, nkChckRange64, nkChckRange:
if skipTypes(n.typ, abstractVar).kind in {tyUInt..tyUInt64}:
genConv(c, n, n[0], dest, flags)
genConv(c, n, n[0], dest)
else:
let
tmp0 = c.genx(n[0])
@@ -2272,7 +2261,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
of nkPar, nkClosure, nkTupleConstr: genTupleConstr(c, n, dest)
of nkCast:
if allowCast in c.features:
genConv(c, n, n[1], dest, flags, opcCast)
genConv(c, n, n[1], dest, opcCast)
else:
genCastIntFloat(c, n, dest)
of nkTypeOfExpr:

View File

@@ -2533,7 +2533,8 @@ renaming the captured symbols should be used instead so that the code is not
affected by context changes.
Since this change may affect runtime behavior, the experimental switch
`openSym` needs to be enabled; and a warning is given in the case where an
`openSym`, or `genericsOpenSym` and `templateOpenSym` for only the respective
routines, needs to be enabled; and a warning is given in the case where an
injected symbol would replace a captured symbol not bound by `bind` and
the experimental switch isn't enabled.
@@ -2554,7 +2555,7 @@ template oldTempl(): string =
value # warning: a new `value` has been injected, use `bind` or turn on `experimental:openSym`
echo oldTempl() # "captured"
{.experimental: "openSym".}
{.experimental: "openSym".} # or {.experimental: "genericsOpenSym".} for just generic procs
proc bar[T](): string =
foo(123):
@@ -2567,6 +2568,8 @@ proc baz[T](): string =
return value
assert baz[int]() == "captured"
# {.experimental: "templateOpenSym".} would be needed here if genericsOpenSym was used
template barTempl(): string =
block:
foo(123):
@@ -2587,34 +2590,6 @@ modified `nnkOpenSymChoice` node but macros that want to support the
experimental feature should still handle `nnkOpenSym`, as the node kind would
simply not be generated as opposed to being removed.
Another experimental switch `genericsOpenSym` exists that enables this behavior
at instantiation time, meaning templates etc can enable it specifically when
they are being called. However this does not generate `nnkOpenSym` nodes
(unless the other switch is enabled) and so doesn't reflect the regular
behavior of the switch.
```nim
const value = "captured"
template foo(x: int, body: untyped): untyped =
let value {.inject.} = "injected"
{.push experimental: "genericsOpenSym".}
body
{.pop.}
proc bar[T](): string =
foo(123):
return value
echo bar[int]() # "injected"
template barTempl(): string =
block:
var res: string
foo(123):
res = value
res
assert barTempl() == "injected"
```
VTable for methods
==================

View File

@@ -61,44 +61,43 @@ Standard library modules
At least the following standard library modules are available:
* [macros](macros.html)
* [os](os.html)
* [strutils](strutils.html)
* [math](math.html)
* [distros](distros.html)
* [sugar](sugar.html)
* [algorithm](algorithm.html)
* [base64](base64.html)
* [bitops](bitops.html)
* [chains](chains.html)
* [colors](colors.html)
* [complex](complex.html)
* [distros](distros.html)
* [std/editdistance](editdistance.html)
* [htmlgen](htmlgen.html)
* [htmlparser](htmlparser.html)
* [httpcore](httpcore.html)
* [json](json.html)
* [lenientops](lenientops.html)
* [macros](macros.html)
* [math](math.html)
* [options](options.html)
* [os](os.html)
* [parsecfg](parsecfg.html)
* [parsecsv](parsecsv.html)
* [parsejson](parsejson.html)
* [parsesql](parsesql.html)
* [parseutils](parseutils.html)
* [punycode](punycode.html)
* [random](random.html)
* [ropes](ropes.html)
* [std/setutils](setutils.html)
* [stats](stats.html)
* [strformat](strformat.html)
* [strmisc](strmisc.html)
* [strscans](strscans.html)
* [strtabs](strtabs.html)
* [strutils](strutils.html)
* [sugar](sugar.html)
* [unicode](unicode.html)
* [unidecode](unidecode.html)
* [uri](uri.html)
* [std/editdistance](editdistance.html)
* [std/wordwrap](wordwrap.html)
* [parsecsv](parsecsv.html)
* [parsecfg](parsecfg.html)
* [parsesql](parsesql.html)
* [xmlparser](xmlparser.html)
* [htmlparser](htmlparser.html)
* [ropes](ropes.html)
* [json](json.html)
* [parsejson](parsejson.html)
* [strtabs](strtabs.html)
* [unidecode](unidecode.html)
In addition to the standard Nim syntax ([system](system.html) module),
NimScripts support the procs and templates defined in the

View File

@@ -1,12 +1,12 @@
#
#
# Maintenance program for Nim
# (c) Copyright 2024 Andreas Rumpf
# (c) Copyright 2017 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# See doc/koch.md for documentation.
# See doc/koch.txt for documentation.
#
const
@@ -52,7 +52,7 @@ const
+-----------------------------------------------------------------+
| Maintenance program for Nim |
| Version $1|
| (c) 2024 Andreas Rumpf |
| (c) 2017 Andreas Rumpf |
+-----------------------------------------------------------------+
Build time: $2, $3
@@ -77,7 +77,6 @@ Possible Commands:
doesn't require network connectivity
nimble builds the Nimble tool
atlas builds the Atlas tool
checksums installs the checksums dependency
fusion installs fusion via Nimble
Boot options:

View File

@@ -161,6 +161,16 @@ proc newAny(value: pointer, rawType: PNimType): Any {.inline.} =
result.value = value
result.rawType = rawType
when declared(system.VarSlot):
proc toAny*(x: VarSlot): Any {.inline.} =
## Constructs an `Any` object from a variable slot `x`.
## This captures `x`'s address, so `x` can be modified with its
## `Any` wrapper! The caller needs to ensure that the wrapper
## **does not** live longer than `x`!
## This is provided for easier reflection capabilities of a debugger.
result.value = x.address
result.rawType = x.typ
proc toAny*[T](x: var T): Any {.inline.} =
## Constructs an `Any` object from `x`. This captures `x`'s address, so
## `x` can be modified with its `Any` wrapper! The caller needs to ensure

View File

@@ -1526,7 +1526,7 @@ proc parseMarkdownCodeblockFields(p: var RstParser): PRstNode =
result = nil
else:
result = newRstNode(rnFieldList)
while currentTok(p).kind notin {tkIndent, tkEof}:
while currentTok(p).kind != tkIndent:
if currentTok(p).kind == tkWhite:
inc p.idx
else:

View File

@@ -839,7 +839,6 @@ proc addHandler*(handler: Logger) =
## each of those threads.
##
## See also:
## * `removeHandler proc`_
## * `getHandlers proc<#getHandlers>`_
runnableExamples:
var logger = newConsoleLogger()
@@ -847,16 +846,6 @@ proc addHandler*(handler: Logger) =
doAssert logger in getHandlers()
handlers.add(handler)
proc removeHandler*(handler: Logger) =
## Removes a logger from the list of registered handlers.
##
## Note that for n times a logger is registered, n calls to this proc
## are required to remove that logger.
for i, hnd in handlers:
if hnd == handler:
handlers.delete(i)
return
proc getHandlers*(): seq[Logger] =
## Returns a list of all the registered handlers.
##

View File

@@ -97,8 +97,6 @@ type
length*: int
addrList*: seq[string]
const IPPROTO_NONE* = IPPROTO_IP ## Use this if your socket type requires a protocol value of zero (e.g. Unix sockets).
when useWinVersion:
let
osInvalidSocket* = winlean.INVALID_SOCKET

View File

@@ -97,7 +97,7 @@ import std/nativesockets
import std/[os, strutils, times, sets, options, monotimes]
import std/ssl_config
export nativesockets.Port, nativesockets.`$`, nativesockets.`==`
export Domain, SockType, Protocol, IPPROTO_NONE
export Domain, SockType, Protocol
const useWinVersion = defined(windows) or defined(nimdoc)
const useNimNetLite = defined(nimNetLite) or defined(freertos) or defined(zephyr) or

View File

@@ -2085,8 +2085,7 @@ when notJSnotNims:
proc cmpMem(a, b: pointer, size: Natural): int =
nimCmpMem(a, b, size).int
when not defined(js) or defined(nimscript):
# nimscript can be defined if config file for js compilation
when not defined(js):
proc cmp(x, y: string): int =
when nimvm:
if x < y: result = -1
@@ -2366,8 +2365,7 @@ proc finished*[T: iterator {.closure.}](x: T): bool {.noSideEffect, inline, magi
from std/private/digitsutils import addInt
export addInt
when defined(js) and not defined(nimscript):
# nimscript can be defined if config file for js compilation
when defined(js):
include "system/jssys"
include "system/reprjs"

View File

@@ -1,4 +1,4 @@
proc succ*[T, V: Ordinal](x: T, y: V = 1): T {.magic: "Succ", noSideEffect.} =
proc succ*[T: Ordinal](x: T, y: int = 1): T {.magic: "Succ", noSideEffect.} =
## Returns the `y`-th successor (default: 1) of the value `x`.
##
## If such a value does not exist, `OverflowDefect` is raised
@@ -7,7 +7,7 @@ proc succ*[T, V: Ordinal](x: T, y: V = 1): T {.magic: "Succ", noSideEffect.} =
assert succ(5) == 6
assert succ(5, 3) == 8
proc pred*[T, V: Ordinal](x: T, y: V = 1): T {.magic: "Pred", noSideEffect.} =
proc pred*[T: Ordinal](x: T, y: int = 1): T {.magic: "Pred", noSideEffect.} =
## Returns the `y`-th predecessor (default: 1) of the value `x`.
##
## If such a value does not exist, `OverflowDefect` is raised
@@ -16,7 +16,7 @@ proc pred*[T, V: Ordinal](x: T, y: V = 1): T {.magic: "Pred", noSideEffect.} =
assert pred(5) == 4
assert pred(5, 3) == 2
proc inc*[T, V: Ordinal](x: var T, y: V = 1) {.magic: "Inc", noSideEffect.} =
proc inc*[T: Ordinal](x: var T, y: int = 1) {.magic: "Inc", noSideEffect.} =
## Increments the ordinal `x` by `y`.
##
## If such a value does not exist, `OverflowDefect` is raised or a compile
@@ -28,7 +28,7 @@ proc inc*[T, V: Ordinal](x: var T, y: V = 1) {.magic: "Inc", noSideEffect.} =
inc(i, 3)
assert i == 6
proc dec*[T, V: Ordinal](x: var T, y: V = 1) {.magic: "Dec", noSideEffect.} =
proc dec*[T: Ordinal](x: var T, y: int = 1) {.magic: "Dec", noSideEffect.} =
## Decrements the ordinal `x` by `y`.
##
## If such a value does not exist, `OverflowDefect` is raised or a compile

View File

@@ -171,16 +171,3 @@ block: # bug #23858
return Object()
discard fn()
doAssert x == 1
block: # bug #24147
type
O = object of RootObj
val: string
OO = object of O
proc `=copy`(dest: var O, src: O) =
dest.val = src.val
let oo = OO(val: "hello world")
var ooCopy : OO
`=copy`(ooCopy, oo)

View File

@@ -820,17 +820,3 @@ block: # bug #23973
doAssert t == a
n()
block: # bug #24141
func reverse(s: var openArray[char]) =
s[0] = 'f'
func rev(s: var string) =
s.reverse
proc main =
var abc = "abc"
abc.rev
doAssert abc == "fbc"
main()

View File

@@ -1,7 +0,0 @@
block: # issue #22661
template foo(a: typed) =
a
foo:
case false
of false..true: discard

View File

@@ -1,9 +1,9 @@
discard """
errormsg: "type mismatch: got <uint8>"
errormsg: "for a 'var' type a variable needs to be passed; but 'uint16(x)' is immutable"
"""
proc toUInt16(x: var uint16) =
discard
var x = uint8(1)
toUInt16 x
toUInt16 x

View File

@@ -1,13 +0,0 @@
discard """
matrix: "-d:testsConciseTypeMismatch"
"""
template v[T](c: SomeOrdinal): T = T(c)
discard v[int, char]('A') #[tt.Error
^ type mismatch
Expression: v[int, char]('A')
[1] 'A': char
Expected one of (first mismatch at [position]):
[2] template v[T](c: SomeOrdinal): T
generic parameter mismatch, expected SomeOrdinal but got 'char' of type: char]#

View File

@@ -1,10 +0,0 @@
template v[T](c: SomeOrdinal): T = T(c)
discard v[int, char]('A') #[tt.Error
^ type mismatch: got <char>
but expected one of:
template v[T](c: SomeOrdinal): T
first type mismatch at position: 2 in generic parameters
required type for SomeOrdinal: SomeOrdinal
but expression 'char' is of type: char
expression: v[int, char]('A')]#

View File

@@ -9,7 +9,7 @@ Expression: newImage[string](320, 200)
Expected one of (first mismatch at [position]):
[1] proc newImage[T: int32 | int64](w, h: int): ref Image[T]
generic parameter mismatch, expected int32 or int64 but got 'string' of type: string
generic parameter mismatch, expected int32 or int64 but got 'string' of type: typedesc[string]
'''
"""

View File

@@ -6,7 +6,7 @@ but expected one of:
proc newImage[T: int32 | int64](w, h: int): ref Image[T]
first type mismatch at position: 1 in generic parameters
required type for T: int32 or int64
but expression 'string' is of type: string
but expression 'string' is of type: typedesc[string]
expression: newImage[string](320, 200)
'''

View File

@@ -1,4 +1,4 @@
{.experimental: "openSym".}
{.experimental: "genericsOpenSym".}
import mopensymimport1

View File

@@ -1,26 +0,0 @@
# issue #16128
import std/[tables, hashes]
type
NodeId*[L] = object
isSource: bool
index: Table[NodeId[L], seq[NodeId[L]]]
func hash*[L](id: NodeId[L]): Hash = discard
func `==`[L](a, b: NodeId[L]): bool = discard
proc makeIndex*[T, L](tree: T) =
var parent = NodeId[L]()
var tmp: Table[NodeId[L], seq[NodeId[L]]]
tmp[parent] = @[parent]
proc simpleTreeDiff*[T, L](source, target: T) =
# Swapping these two lines makes error disappear
var m: Table[NodeId[L], NodeId[L]]
makeIndex[T, L](target)
var tmp: Table[string, seq[string]] # removing this forward declaration also removes error
proc diff(x1, x2: string): auto =
simpleTreeDiff[int, string](12, 12)

View File

@@ -44,15 +44,3 @@ block: # constant condition after dynamic one
doAssert y.a is int
var z: Foo[float]
doAssert z.a is string
block: # issue #4774, but not with threads
const hasThreadSupport = not defined(js)
when hasThreadSupport:
type Channel[T] = object
value: T
type
SomeObj[T] = object
when hasThreadSupport:
channel: ptr Channel[T]
var x: SomeObj[int]
doAssert compiles(x.channel) == hasThreadSupport

View File

@@ -1,4 +1,4 @@
{.experimental: "openSym".}
{.experimental: "genericsOpenSym".}
block: # issue #22605, normal call syntax
const error = "bad"

View File

@@ -451,67 +451,3 @@ block: # real version of above
proc foo[T](x: T, a = Opt.none(int)) = discard
foo(1, a = Opt.none(int))
foo(1)
block: # issue #20880
type
Child[n: static int] = object
data: array[n, int]
Parent[n: static int] = object
child: Child[3*n]
const n = 3
doAssert $(typeof Parent[n*3]()) == "Parent[9]"
doAssert $(typeof Parent[1]().child) == "Child[3]"
doAssert Parent[1]().child.data.len == 3
{.experimental: "dynamicBindSym".}
block: # issue #16774
type SecretWord = distinct uint64
const WordBitWidth = 8 * sizeof(uint64)
func wordsRequired(bits: int): int {.compileTime.} =
## Compute the number of limbs required
# from the **announced** bit length
(bits + WordBitWidth - 1) div WordBitWidth
type
Curve = enum BLS12_381
BigInt[bits: static int] = object
limbs: array[bits.wordsRequired, SecretWord]
const BLS12_381_Modulus = default(BigInt[381])
macro Mod(C: static Curve): untyped =
## Get the Modulus associated to a curve
result = bindSym($C & "_Modulus")
macro getCurveBitwidth(C: static Curve): untyped =
result = nnkDotExpr.newTree(
getAST(Mod(C)),
ident"bits"
)
type Fp[C: static Curve] = object
## Finite Fields / Modular arithmetic
## modulo the curve modulus
mres: BigInt[getCurveBitwidth(C)]
var x: Fp[BLS12_381]
doAssert x.mres.limbs.len == wordsRequired(getCurveBitWidth(BLS12_381))
# minimized, as if we haven't tested it already:
macro makeIntLit(c: static int): untyped =
result = newLit(c)
type Test[T: static int] = object
myArray: array[makeIntLit(T), int]
var y: Test[2]
doAssert y.myArray.len == 2
var z: Test[4]
doAssert z.myArray.len == 4
block: # issue #16175
type
Thing[D: static uint] = object
when D == 0:
kid: char
else:
kid: Thing[D-1]
var t2 = Thing[3]()
doAssert t2.kid is Thing[2.uint]
doAssert t2.kid.kid is Thing[1.uint]
doAssert t2.kid.kid.kid is Thing[0.uint]
doAssert t2.kid.kid.kid.kid is char
var s = Thing[1]()
doAssert s.kid is Thing[0.uint]
doAssert s.kid.kid is char

View File

@@ -32,9 +32,3 @@ block t4175:
const j = 0u - 1u
doAssert i == j
doAssert j + 1u == 0u
block: # https://forum.nim-lang.org/t/12465#76998
var a: int = 1
var x: uint8 = 1
a.inc(x) # Error: type mismatch
doAssert a == 2

View File

@@ -1,16 +0,0 @@
discard """
action: reject
nimout: '''
but expression 'int(a)' is immutable, not 'var'
'''
"""
proc `++`(n: var int) =
n += 1
var a: int32 = 15
++int(a) #[tt.Error
^ type mismatch: got <int>]#
echo a

View File

@@ -1,9 +0,0 @@
proc `++`(n: var int) =
n += 1
var a: int32 = 15
++a #[tt.Error
^ type mismatch: got <int32>]#
echo a

View File

@@ -1 +0,0 @@
import std/jsffi

View File

@@ -1 +0,0 @@
# test the condition where both `js` and `nimscript` are defined (nimscript receives priority)

View File

@@ -1,21 +0,0 @@
block: # issue #17527
iterator items2[IX, T](a: array[IX, T]): lent T {.inline.} =
var i = low(IX)
if i <= high(IX):
while true:
yield a[i]
if i >= high(IX): break
inc(i)
proc main() =
var s: seq[string] = @[]
for i in 0..<3:
for (key, val) in items2([("any", "bar")]):
s.add $(i, key, val)
doAssert s == @[
"(0, \"any\", \"bar\")",
"(1, \"any\", \"bar\")",
"(2, \"any\", \"bar\")"
]
static: main()

View File

@@ -1,2 +0,0 @@
proc count*(s: string): int =
s.len

View File

@@ -1 +0,0 @@
var count*: int = 10

View File

@@ -1 +0,0 @@
const count* = 3.142

View File

@@ -1,10 +0,0 @@
# issue #12732
import std/macros
const getPrivate3_tmp* = 0
const foobar1* = 0 # comment this or make private and it'll compile fine
macro foobar4*(): untyped =
newLit "abc"
template currentPkgDir2*: string = foobar4()
macro currentPkgDir2*(dir: string): untyped =
newLit "abc2"

View File

@@ -1,8 +0,0 @@
# issue #15247
import mdisambsym1, mdisambsym2, mdisambsym3
proc twice(n: int): int =
n*2
doAssert twice(count) == 20

View File

@@ -1,5 +0,0 @@
# issue #12732
import mmacroamb
const s0 = currentPkgDir2 #[tt.Error
^ ambiguous identifier: 'currentPkgDir2' -- use one of the following:]#

View File

@@ -7,12 +7,12 @@ mused2a.nim(12, 6) Hint: 'fn1' is declared but not used [XDeclaredButNotUsed]
mused2a.nim(16, 5) Hint: 'fn4' is declared but not used [XDeclaredButNotUsed]
mused2a.nim(20, 7) Hint: 'fn7' is declared but not used [XDeclaredButNotUsed]
mused2a.nim(23, 6) Hint: 'T1' is declared but not used [XDeclaredButNotUsed]
mused2a.nim(1, 12) Warning: imported and not used: 'strutils' [UnusedImport]
mused2a.nim(3, 10) Warning: imported and not used: 'os' [UnusedImport]
mused2a.nim(1, 11) Warning: imported and not used: 'strutils' [UnusedImport]
mused2a.nim(3, 9) Warning: imported and not used: 'os' [UnusedImport]
mused2a.nim(5, 23) Warning: imported and not used: 'typetraits2' [UnusedImport]
mused2a.nim(6, 10) Warning: imported and not used: 'setutils' [UnusedImport]
mused2a.nim(6, 9) Warning: imported and not used: 'setutils' [UnusedImport]
tused2.nim(42, 8) Warning: imported and not used: 'mused2a' [UnusedImport]
tused2.nim(45, 12) Warning: imported and not used: 'strutils' [UnusedImport]
tused2.nim(45, 11) Warning: imported and not used: 'strutils' [UnusedImport]
'''
"""

View File

@@ -1,10 +0,0 @@
discard """
errormsg: "The MPlayerObj type doesn't have a default value. The following fields must be initialized: foo."
"""
type
MPlayerObj* {.requiresInit.} = object
foo: range[5..10] = 5
var a: MPlayerObj
echo a.foo

View File

@@ -1,145 +0,0 @@
import
std/[macros, tables, hashes]
export
macros
type
FieldDescription* = object
name*: NimNode
isPublic*: bool
isDiscriminator*: bool
typ*: NimNode
pragmas*: NimNode
caseField*: NimNode
caseBranch*: NimNode
{.push raises: [].}
func isTuple*(t: NimNode): bool =
t.kind == nnkBracketExpr and t[0].kind == nnkSym and eqIdent(t[0], "tuple")
macro isTuple*(T: type): untyped =
newLit(isTuple(getType(T)[1]))
proc collectFieldsFromRecList(result: var seq[FieldDescription],
n: NimNode,
parentCaseField: NimNode = nil,
parentCaseBranch: NimNode = nil,
isDiscriminator = false) =
case n.kind
of nnkRecList:
for entry in n:
collectFieldsFromRecList result, entry,
parentCaseField, parentCaseBranch
of nnkRecWhen:
for branch in n:
case branch.kind:
of nnkElifBranch:
collectFieldsFromRecList result, branch[1],
parentCaseField, parentCaseBranch
of nnkElse:
collectFieldsFromRecList result, branch[0],
parentCaseField, parentCaseBranch
else:
doAssert false
of nnkRecCase:
collectFieldsFromRecList result, n[0],
parentCaseField,
parentCaseBranch,
isDiscriminator = true
for i in 1 ..< n.len:
let branch = n[i]
case branch.kind
of nnkOfBranch:
collectFieldsFromRecList result, branch[^1], n[0], branch
of nnkElse:
collectFieldsFromRecList result, branch[0], n[0], branch
else:
doAssert false
of nnkIdentDefs:
let fieldType = n[^2]
for i in 0 ..< n.len - 2:
var field: FieldDescription
field.name = n[i]
field.typ = fieldType
field.caseField = parentCaseField
field.caseBranch = parentCaseBranch
field.isDiscriminator = isDiscriminator
if field.name.kind == nnkPragmaExpr:
field.pragmas = field.name[1]
field.name = field.name[0]
if field.name.kind == nnkPostfix:
field.isPublic = true
field.name = field.name[1]
result.add field
of nnkSym:
result.add FieldDescription(
name: n,
typ: getType(n),
caseField: parentCaseField,
caseBranch: parentCaseBranch,
isDiscriminator: isDiscriminator)
of nnkNilLit, nnkDiscardStmt, nnkCommentStmt, nnkEmpty:
discard
else:
doAssert false, "Unexpected nodes in recordFields:\n" & n.treeRepr
proc collectFieldsInHierarchy(result: var seq[FieldDescription],
objectType: NimNode) =
var objectType = objectType
objectType.expectKind {nnkObjectTy, nnkRefTy}
if objectType.kind == nnkRefTy:
objectType = objectType[0]
objectType.expectKind nnkObjectTy
var baseType = objectType[1]
if baseType.kind != nnkEmpty:
baseType.expectKind nnkOfInherit
baseType = baseType[0]
baseType.expectKind nnkSym
baseType = getImpl(baseType)
baseType.expectKind nnkTypeDef
baseType = baseType[2]
baseType.expectKind {nnkObjectTy, nnkRefTy}
collectFieldsInHierarchy result, baseType
let recList = objectType[2]
collectFieldsFromRecList result, recList
proc recordFields*(typeImpl: NimNode): seq[FieldDescription] =
if typeImpl.isTuple:
for i in 1 ..< typeImpl.len:
result.add FieldDescription(typ: typeImpl[i], name: ident("Field" & $(i - 1)))
return
let objectType = case typeImpl.kind
of nnkObjectTy: typeImpl
of nnkTypeDef: typeImpl[2]
else:
macros.error("object type expected", typeImpl)
return
collectFieldsInHierarchy(result, objectType)
macro field*(obj: typed, fieldName: static string): untyped =
newDotExpr(obj, ident fieldName)
proc skipPragma*(n: NimNode): NimNode =
if n.kind == nnkPragmaExpr: n[0]
else: n
{.pop.}

View File

@@ -1,13 +0,0 @@
block: # issue #13799
type
X[A, B] = object
a: A
b: B
Y[A] = X[A, int]
template s(T: type X): X = T()
template t[A, B](T: type X[A, B]): X[A, B] = T()
proc works1(): Y[int] = s(X[int, int])
proc works2(): Y[int] = t(X[int, int])
proc works3(): Y[int] = t(Y[int])
proc broken(): Y[int] = s(Y[int])

View File

@@ -16,26 +16,3 @@ block: # bug #8568
proc g(a: D|E): string = "foo D|E"
proc g(a: D): string = "foo D"
doAssert g(D[int]()) == "foo D"
type Obj1[T] = object
v: T
converter toObj1[T](t: T): Obj1[T] = return Obj1[T](v: t)
block: # issue #10019
proc fun1[T](elements: seq[T]): string = "fun1 seq"
proc fun1(o: object|tuple): string = "fun1 object|tuple"
proc fun2[T](elements: openArray[T]): string = "fun2 openarray"
proc fun2(o: object): string = "fun2 object"
proc fun_bug[T](elements: openArray[T]): string = "fun_bug openarray"
proc fun_bug(o: object|tuple):string = "fun_bug object|tuple"
proc main() =
var x = @["hello", "world"]
block:
# no ambiguity error shown here even though this would compile if we remove either 1st or 2nd overload of fun1
doAssert fun1(x) == "fun1 seq"
block:
# ditto
doAssert fun2(x) == "fun2 openarray"
block:
# Error: ambiguous call; both t0065.fun_bug(elements: openarray[T])[declared in t0065.nim(17, 5)] and t0065.fun_bug(o: object or tuple)[declared in t0065.nim(20, 5)] match for: (array[0..1, string])
doAssert fun_bug(x) == "fun_bug openarray"
main()

View File

@@ -1,19 +0,0 @@
import macros
block: # issue #7385
type CustomSeq[T] = object
data: seq[T]
macro `[]`[T](s: CustomSeq[T], args: varargs[untyped]): untyped =
## The end goal is to replace the joker "_" by something else
result = newIntLitNode(10)
proc foo1(): CustomSeq[int] =
result.data.newSeq(10)
# works since no overload matches first argument with type `CustomSeq`
# except magic `[]`, which always matches without checking arguments
doAssert result[_] == 10
doAssert foo1() == CustomSeq[int](data: newSeq[int](10))
proc foo2[T](): CustomSeq[T] =
result.data.newSeq(10)
# works fine with generic return type
doAssert result[_] == 10
doAssert foo2[int]() == CustomSeq[int](data: newSeq[int](10))

View File

@@ -1,207 +0,0 @@
discard """
action: compile
"""
# https://github.com/status-im/nimbus-eth2/pull/6554#issuecomment-2354977102
# failed with "for a 'var' type a variable needs to be passed; but 'uint64(result)' is immutable"
import
std/[typetraits, macros]
type
DefaultFlavor = object
template serializationFormatImpl(Name: untyped) {.dirty.} =
type Name = object
template serializationFormat(Name: untyped) =
serializationFormatImpl(Name)
template setReader(Format, FormatReader: distinct type) =
when arity(FormatReader) > 1:
template Reader(T: type Format, F: distinct type = DefaultFlavor): type = FormatReader[F]
else:
template ReaderType(T: type Format): type = FormatReader
template Reader(T: type Format): type = FormatReader
template useDefaultReaderIn(T: untyped, Flavor: type) =
mixin Reader
template readValue(r: var Reader(Flavor), value: var T) =
mixin readRecordValue
readRecordValue(r, value)
import mvaruintconv
type
FieldTag[RecordType: object; fieldName: static string] = distinct void
func declval*(T: type): T {.compileTime.} =
default(ptr T)[]
macro enumAllSerializedFieldsImpl(T: type, body: untyped): untyped =
var typeAst = getType(T)[1]
var typeImpl: NimNode
let isSymbol = not typeAst.isTuple
if not isSymbol:
typeImpl = typeAst
else:
typeImpl = getImpl(typeAst)
result = newStmtList()
var i = 0
for field in recordFields(typeImpl):
let
fieldIdent = field.name
realFieldName = newLit($fieldIdent.skipPragma)
fieldName = realFieldName
fieldIndex = newLit(i)
let fieldNameDefs =
if isSymbol:
quote:
const fieldName {.inject, used.} = `fieldName`
const realFieldName {.inject, used.} = `realFieldName`
else:
quote:
const fieldName {.inject, used.} = $`fieldIndex`
const realFieldName {.inject, used.} = $`fieldIndex`
let field =
if isSymbol:
quote do: declval(`T`).`fieldIdent`
else:
quote do: declval(`T`)[`fieldIndex`]
result.add quote do:
block:
`fieldNameDefs`
template FieldType: untyped {.inject, used.} = typeof(`field`)
`body`
# echo repr(result)
template enumAllSerializedFields(T: type, body): untyped =
enumAllSerializedFieldsImpl(T, body)
type
FieldReader[RecordType, Reader] = tuple[
fieldName: string,
reader: proc (rec: var RecordType, reader: var Reader)
{.gcsafe, nimcall.}
]
proc totalSerializedFieldsImpl(T: type): int =
mixin enumAllSerializedFields
enumAllSerializedFields(T): inc result
template totalSerializedFields(T: type): int =
(static(totalSerializedFieldsImpl(T)))
template GetFieldType(FT: type FieldTag): type =
typeof field(declval(FT.RecordType), FT.fieldName)
proc makeFieldReadersTable(RecordType, ReaderType: distinct type,
numFields: static[int]):
array[numFields, FieldReader[RecordType, ReaderType]] =
mixin enumAllSerializedFields, handleReadException
var idx = 0
enumAllSerializedFields(RecordType):
proc readField(obj: var RecordType, reader: var ReaderType)
{.gcsafe, nimcall.} =
mixin readValue
type F = FieldTag[RecordType, realFieldName]
field(obj, realFieldName) = reader.readValue(GetFieldType(F))
result[idx] = (fieldName, readField)
inc idx
proc fieldReadersTable(RecordType, ReaderType: distinct type): auto =
mixin readValue
type T = RecordType
const numFields = totalSerializedFields(T)
var tbl {.threadvar.}: ref array[numFields, FieldReader[RecordType, ReaderType]]
if tbl == nil:
tbl = new typeof(tbl)
tbl[] = makeFieldReadersTable(RecordType, ReaderType, numFields)
return addr(tbl[])
proc readValue(reader: var auto, T: type): T =
mixin readValue
reader.readValue(result)
template decode(Format: distinct type,
input: string,
RecordType: distinct type): auto =
mixin Reader
block: # https://github.com/nim-lang/Nim/issues/22874
var reader: Reader(Format)
reader.readValue(RecordType)
template readValue(Format: type,
ValueType: type): untyped =
mixin Reader, init, readValue
var reader: Reader(Format)
readValue reader, ValueType
template parseArrayImpl(numElem: untyped,
actionValue: untyped) =
actionValue
serializationFormat Json
template createJsonFlavor(FlavorName: untyped,
skipNullFields = false) {.dirty.} =
type FlavorName = object
template Reader(T: type FlavorName): type = Reader(Json, FlavorName)
type
JsonReader[Flavor = DefaultFlavor] = object
Json.setReader JsonReader
template parseArray(r: var JsonReader; body: untyped) =
parseArrayImpl(idx): body
template parseArray(r: var JsonReader; idx: untyped; body: untyped) =
parseArrayImpl(idx): body
proc readRecordValue[T](r: var JsonReader, value: var T) =
type
ReaderType {.used.} = type r
T = type value
discard T.fieldReadersTable(ReaderType)
proc readValue[T](r: var JsonReader, value: var T) =
mixin readValue
when value is seq:
r.parseArray:
readValue(r, value[0])
elif value is object:
readRecordValue(r, value)
type
RemoteSignerInfo = object
id: uint32
RemoteKeystore = object
proc readValue(reader: var JsonReader, value: var RemoteKeystore) =
discard reader.readValue(seq[RemoteSignerInfo])
createJsonFlavor RestJson
useDefaultReaderIn(RemoteSignerInfo, RestJson)
proc readValue(reader: var JsonReader[RestJson], value: var uint64) =
discard reader.readValue(string)
discard Json.decode("", RemoteKeystore)
block: # https://github.com/nim-lang/Nim/issues/22874
var reader: Reader(RestJson)
discard reader.readValue(RemoteSignerInfo)

View File

@@ -1,3 +0,0 @@
type Foo = ref int
not nil #[tt.Error
^ invalid indentation]#

View File

@@ -1,10 +0,0 @@
# issue #23565
func foo: bool =
true
const bar = block:
type T = int
not foo()
doAssert not bar

View File

@@ -531,10 +531,3 @@ block:
check(a)
check(b)
block: # https://forum.nim-lang.org/t/12522, backticks
template `mypragma`() {.pragma.}
# Error: invalid pragma: `mypragma`
type Test = object
field {.`mypragma`.}: int
doAssert Test().field.hasCustomPragma(mypragma)

View File

@@ -124,21 +124,3 @@ foo31()
foo41()
{.pop.}
import macros
block:
{.push deprecated.}
template test() = discard
test()
{.pop.}
macro foo(): bool =
let ast = getImpl(bindSym"test")
var found = false
if ast[4].kind == nnkPragma:
for x in ast[4]:
if x.eqIdent"deprecated":
found = true
break
result = newLit(found)
doAssert foo()

View File

@@ -43,13 +43,3 @@ block: # ditto but may be wrong minimization
# alternative version, also causes instantiation issue
proc baz[T](x: typeof(foo[T]())) = discard
baz[int](Foo[int]())
block: # issue #21346
type K[T] = object
template s[T](x: int) = doAssert T is K[K[int]]
proc b1(n: bool | bool) = s[K[K[int]]](3)
proc b2(n: bool) = s[K[K[int]]](3)
template b3(n: bool) = s[K[K[int]]](3)
b1(false) # Error: cannot instantiate K; got: <T> but expected: <T>
b2(false) # Builds, on its own
b3(false)

View File

@@ -67,32 +67,3 @@ block: # issue #24099, modified to work but using float32
## Compares colors with given accuracy.
abs(a[0] - b[0]) < e and abs(a[1] - b[1]) < e and abs(a[2] - b[2]) < e
doAssert ColorRGBU([1.float32, 1, 1]) ~= ColorRGBU([1.float32, 1, 1])
block: # issue #13270
type
A = object
B = object
proc f(a: A) = discard
proc g[T](value: T, cb: (proc(a: T)) = f) =
cb value
g A()
# This should fail because there is no f(a: B) overload available
doAssert not compiles(g B())
block: # issue #24121
type
Foo = distinct int
Bar = distinct int
FooBar = Foo | Bar
proc foo[T: distinct](x: T): string = "a"
proc foo(x: Foo): string = "b"
proc foo(x: Bar): string = "c"
proc bar(x: FooBar, y = foo(x)): string = y
doAssert bar(Foo(123)) == "b"
doAssert bar(Bar(123)) == "c"
proc baz[T: FooBar](x: T, y = foo(x)): string = y
doAssert baz(Foo(123)) == "b"
doAssert baz(Bar(123)) == "c"

View File

@@ -250,19 +250,3 @@ block: # `when` in static signature
proc foo[T](): T = test()
proc bar[T](x = foo[T]()): T = x
doAssert bar[int]() == 123
block: # issue #22276
type Foo = enum A, B
macro test(y: static[Foo]): untyped =
if y == A:
result = parseExpr("proc (x: int)")
else:
result = parseExpr("proc (x: float)")
proc foo(y: static[Foo], x: test(y)) = # We want to make the type of `x` depend on what `y` is
x(9)
foo(A, proc (x: int) = doAssert x == 9)
var a: int
foo(A, proc (x: int) =
a = x * 2)
doAssert a == 18
foo(B, proc (x: float) = doAssert x == 9)

View File

@@ -1,54 +0,0 @@
# issue #12405
import std/[marshal, streams, times, tables, os, assertions]
type AiredEpisodeState * = ref object
airedAt * : DateTime
tvShowId * : string
seasonNumber * : int
number * : int
title * : string
type ShowsWatchlistState * = ref object
aired * : seq[AiredEpisodeState]
type UiState * = ref object
shows: ShowsWatchlistState
# Helpers to marshal and unmarshal
proc load * ( state : var UiState, file : string ) =
var strm = newFileStream( file, fmRead )
strm.load( state )
strm.close()
proc store * ( state : UiState, file : string ) =
var strm = newFileStream( file, fmWrite )
strm.store( state )
strm.close()
# 1. We fill the state initially
var state : UiState = UiState( shows: ShowsWatchlistState( aired: @[] ) )
# VERY IMPORTANT: For some reason, small numbers (like 2 or 3) don't trigger the bug. Anything above 7 or 8 on my machine triggers though
for i in 0..30:
var episode = AiredEpisodeState( airedAt: now(), tvShowId: "1", seasonNumber: 1, number: 1, title: "string" )
state.shows.aired.add( episode )
# 2. Store it in a file with the marshal module, and then load it back up
store( state, "tmarshalsegfault_data" )
load( state, "tmarshalsegfault_data" )
removeFile("tmarshalsegfault_data")
# 3. VERY IMPORTANT: Without this line, for some reason, everything works fine
state.shows.aired[ 0 ] = AiredEpisodeState( airedAt: now(), tvShowId: "1", seasonNumber: 1, number: 1, title: "string" )
# 4. And formatting the airedAt date will now trigger the exception
for ep in state.shows.aired:
let x = $ep.seasonNumber & "x" & $ep.number & " (" & $ep.airedAt & ")"
let y = $ep.seasonNumber & "x" & $ep.number & " (" & $ep.airedAt & ")"
doAssert x == y

View File

@@ -16,8 +16,6 @@ discard """
[Suite] RST escaping
[Suite] RST inline markup
[Suite] Misc isssues
'''
matrix: "--mm:refc; --mm:orc"
"""
@@ -1982,13 +1980,3 @@ suite "RST inline markup":
rnLeaf ')'
""")
check(warnings[] == @["input(1, 5) Warning: broken link 'f'"])
suite "Misc isssues":
test "Markdown CodeblockFields in one line (lacking enclosing ```)":
let message = """
```llvm-profdata merge first.profraw second.profraw third.profraw <more stuff maybe> -output data.profdata```"""
try:
echo rstgen.rstToHtml(message, {roSupportMarkdown}, nil)
except EParseError:
discard

View File

@@ -1,35 +0,0 @@
import std/[assertions, net, os, osproc]
# XXX: Make this test run on Windows too when we add support for Unix sockets on Windows
when defined(posix) and not defined(nimNetLite):
const nim = getCurrentCompilerExe()
let
dir = currentSourcePath().parentDir()
serverPath = dir / "unixsockettest"
let (_, err) = execCmdEx(nim & " c " & quoteShell(dir / "unixsockettest.nim"))
doAssert err == 0
let svproc = startProcess(serverPath, workingDir = dir)
doAssert svproc.running()
# Wait for the server to open the socket and listen from it
sleep(400)
block unixSocketSendRecv:
let
unixSocketPath = dir / "usox"
socket = newSocket(AF_UNIX, SOCK_STREAM, IPPROTO_NONE)
socket.connectUnix(unixSocketPath)
# for a blocking Unix socket this should never fail
socket.send("data sent through the socket\c\l", maxRetries = 0)
var resp: string
socket.readLine(resp)
doAssert resp == "Hello from server"
socket.send("bye\c\l")
socket.readLine(resp)
doAssert resp == "bye"
socket.close()
svproc.close()

View File

@@ -1,26 +0,0 @@
import std/[assertions, net, os]
let unixSocketPath = getCurrentDir() / "usox"
removeFile(unixSocketPath)
let socket = newSocket(AF_UNIX, SOCK_STREAM, IPPROTO_NONE)
socket.bindUnix(unixSocketPath)
socket.listen()
var
clientSocket: Socket
data: string
socket.accept(clientSocket)
clientSocket.readLine(data)
doAssert data == "data sent through the socket"
clientSocket.send("Hello from server\c\l")
clientSocket.readLine(data)
doAssert data == "bye"
clientSocket.send("bye\c\l")
clientSocket.close()
socket.close()
removeFile(unixSocketPath)

View File

@@ -1,2 +0,0 @@
template foo*(x: untyped) =
echo "got: ", x

View File

@@ -1,2 +0,0 @@
proc foo*(a: string) =
echo "got string: ", a

View File

@@ -1,19 +0,0 @@
discard """
output: '''
got: 0
'''
"""
# issue #19277
import m19277_1, m19277_2
template injector(val: untyped): untyped =
template subtemplate: untyped = val
subtemplate()
template methodCall(val: untyped): untyped = val
{.push raises: [Defect].}
foo(injector(0).methodCall())

View File

@@ -1,19 +0,0 @@
discard """
matrix: "--skipParentCfg --filenames:legacyRelProj --hints:off"
action: reject
"""
# issue #24112, needs --experimental:openSym disabled
block: # simplified
type
SomeObj = ref object # Doesn't error if you make SomeObj be non-ref
template foo = yield SomeObj()
when compiles(foo): discard
import std/asyncdispatch
block:
proc someProc(): Future[void] {.async.} = discard
proc foo() =
await someProc() #[tt.Error
^ Can only 'await' inside a proc marked as 'async'. Use 'waitFor' when calling an 'async' proc in a non-async scope instead]#

View File

@@ -1,4 +1,4 @@
{.experimental: "openSym".}
{.experimental: "templateOpenSym".}
block: # issue #24002
type Result[T, E] = object

View File

@@ -1,39 +0,0 @@
discard """
matrix: "--skipParentCfg --filenames:legacyRelProj"
"""
const value = "captured"
template fooOld(x: int, body: untyped): untyped =
let value {.inject.} = "injected"
body
template foo(x: int, body: untyped): untyped =
let value {.inject.} = "injected"
{.push experimental: "genericsOpenSym".}
body
{.pop.}
proc old[T](): string =
fooOld(123):
return value
doAssert old[int]() == "captured"
template oldTempl(): string =
block:
var res: string
fooOld(123):
res = value
res
doAssert oldTempl() == "captured"
proc bar[T](): string =
foo(123):
return value
doAssert bar[int]() == "injected"
template barTempl(): string =
block:
var res: string
foo(123):
res = value
res
doAssert barTempl() == "injected"

View File

@@ -1,12 +1,9 @@
discard """
cmd: '''nim c --hint:Processing:off $file'''
nimout: '''
tunused_imports.nim(14, 10) Warning: BEGIN [User]
tunused_imports.nim(41, 10) Warning: END [User]
tunused_imports.nim(37, 8) Warning: imported and not used: 'strutils' [UnusedImport]
tunused_imports.nim(38, 13) Warning: imported and not used: 'strtabs' [UnusedImport]
tunused_imports.nim(38, 22) Warning: imported and not used: 'cstrutils' [UnusedImport]
tunused_imports.nim(39, 12) Warning: imported and not used: 'macrocache' [UnusedImport]
tunused_imports.nim(11, 10) Warning: BEGIN [User]
tunused_imports.nim(36, 10) Warning: END [User]
tunused_imports.nim(34, 8) Warning: imported and not used: 'strutils' [UnusedImport]
'''
action: "compile"
"""
@@ -35,7 +32,5 @@ macro bar(): untyped =
bar()
import strutils
import std/[strtabs, cstrutils]
import std/macrocache
{.warning: "END".}

View File

@@ -325,9 +325,3 @@ block: # bug #22180
else:
(ref A)(nil)
doAssert y.isNil
block: # issue #24164, related regression
proc foo(x: proc ()) = discard
template bar(x: untyped = nil) =
foo(x)
bar()

View File

@@ -2,7 +2,7 @@ discard """
errormsg: "type mismatch: got <int>"
nimout: '''tprevent_forloopvar_mutations.nim(16, 3) Error: type mismatch: got <int>
but expected one of:
proc inc[T, V: Ordinal](x: var T; y: V = 1)
proc inc[T: Ordinal](x: var T; y: int = 1)
first type mismatch at position: 1
required type for x: var T: Ordinal
but expression 'i' is immutable, not 'var'

View File

@@ -1,49 +0,0 @@
block: # issue #24097
type Foo = distinct int
proc foo(x: var Foo) =
int(x) += 1
proc bar(x: var int) =
x += 1
static:
var x = Foo(1)
int(x) = int(x) + 1
doAssert x.int == 2
int(x) += 1
doAssert x.int == 3
foo(x)
doAssert x.int == 4
bar(int(x)) # need vmgen flags propagated for this
doAssert x.int == 5
type Bar = object
x: Foo
static:
var obj = Bar(x: Foo(1))
int(obj.x) = int(obj.x) + 1
doAssert obj.x.int == 2
int(obj.x) += 1
doAssert obj.x.int == 3
foo(obj.x)
doAssert obj.x.int == 4
bar(int(obj.x)) # need vmgen flags propagated for this
doAssert obj.x.int == 5
static:
var arr = @[Foo(1)]
int(arr[0]) = int(arr[0]) + 1
doAssert arr[0].int == 2
int(arr[0]) += 1
doAssert arr[0].int == 3
foo(arr[0])
doAssert arr[0].int == 4
bar(int(arr[0])) # need vmgen flags propagated for this
doAssert arr[0].int == 5
proc testResult(): Foo =
result = Foo(1)
int(result) = int(result) + 1
doAssert result.int == 2
int(result) += 1
doAssert result.int == 3
foo(result)
doAssert result.int == 4
bar(int(result)) # need vmgen flags propagated for this
doAssert result.int == 5
doAssert testResult().int == 5

View File

@@ -27,10 +27,3 @@ block:
proc p(x: int): int = x
type Foo = typeof(p(fail(123)))
block: # issue #24150, related regression
proc w(T: type): T {.compileTime.} = default(ptr T)[]
template y(v: auto): auto = typeof(v) is int
discard compiles(y(w int))
proc s(): int {.compileTime.} = discard
discard s()