mirror of
https://github.com/nim-lang/Nim.git
synced 2026-08-31 19:03:42 +00:00
Compare commits
1 Commits
ringabout-
...
pr_build_t
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6928aa0d20 |
35
changelog.md
35
changelog.md
@@ -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.
|
||||
|
||||
@@ -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
19
compiler/cbuilder.nim
Normal 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")
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -167,5 +167,4 @@ proc initDefines*(symbols: StringTableRef) =
|
||||
|
||||
defineSymbol("nimHasVtables")
|
||||
defineSymbol("nimHasGenericsOpenSym2")
|
||||
defineSymbol("nimHasGenericsOpenSym3")
|
||||
defineSymbol("nimHasJsNoLambdaLifting")
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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) =
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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})
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)])
|
||||
|
||||
@@ -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}:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
==================
|
||||
|
||||
33
doc/nims.md
33
doc/nims.md
@@ -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
|
||||
|
||||
7
koch.nim
7
koch.nim
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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.
|
||||
##
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
block: # issue #22661
|
||||
template foo(a: typed) =
|
||||
a
|
||||
|
||||
foo:
|
||||
case false
|
||||
of false..true: discard
|
||||
@@ -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
|
||||
@@ -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]#
|
||||
@@ -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')]#
|
||||
@@ -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]
|
||||
'''
|
||||
"""
|
||||
|
||||
|
||||
@@ -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)
|
||||
'''
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{.experimental: "openSym".}
|
||||
{.experimental: "genericsOpenSym".}
|
||||
|
||||
import mopensymimport1
|
||||
|
||||
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{.experimental: "openSym".}
|
||||
{.experimental: "genericsOpenSym".}
|
||||
|
||||
block: # issue #22605, normal call syntax
|
||||
const error = "bad"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -1,9 +0,0 @@
|
||||
proc `++`(n: var int) =
|
||||
n += 1
|
||||
|
||||
var a: int32 = 15
|
||||
|
||||
++a #[tt.Error
|
||||
^ type mismatch: got <int32>]#
|
||||
|
||||
echo a
|
||||
@@ -1 +0,0 @@
|
||||
import std/jsffi
|
||||
@@ -1 +0,0 @@
|
||||
# test the condition where both `js` and `nimscript` are defined (nimscript receives priority)
|
||||
@@ -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()
|
||||
@@ -1,2 +0,0 @@
|
||||
proc count*(s: string): int =
|
||||
s.len
|
||||
@@ -1 +0,0 @@
|
||||
var count*: int = 10
|
||||
@@ -1 +0,0 @@
|
||||
const count* = 3.142
|
||||
@@ -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"
|
||||
@@ -1,8 +0,0 @@
|
||||
# issue #15247
|
||||
|
||||
import mdisambsym1, mdisambsym2, mdisambsym3
|
||||
|
||||
proc twice(n: int): int =
|
||||
n*2
|
||||
|
||||
doAssert twice(count) == 20
|
||||
@@ -1,5 +0,0 @@
|
||||
# issue #12732
|
||||
|
||||
import mmacroamb
|
||||
const s0 = currentPkgDir2 #[tt.Error
|
||||
^ ambiguous identifier: 'currentPkgDir2' -- use one of the following:]#
|
||||
@@ -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]
|
||||
'''
|
||||
"""
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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.}
|
||||
@@ -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])
|
||||
@@ -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()
|
||||
|
||||
@@ -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))
|
||||
@@ -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)
|
||||
@@ -1,3 +0,0 @@
|
||||
type Foo = ref int
|
||||
not nil #[tt.Error
|
||||
^ invalid indentation]#
|
||||
@@ -1,10 +0,0 @@
|
||||
# issue #23565
|
||||
|
||||
func foo: bool =
|
||||
true
|
||||
|
||||
const bar = block:
|
||||
type T = int
|
||||
not foo()
|
||||
|
||||
doAssert not bar
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
@@ -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)
|
||||
@@ -1,2 +0,0 @@
|
||||
template foo*(x: untyped) =
|
||||
echo "got: ", x
|
||||
@@ -1,2 +0,0 @@
|
||||
proc foo*(a: string) =
|
||||
echo "got string: ", a
|
||||
@@ -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())
|
||||
@@ -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]#
|
||||
@@ -1,4 +1,4 @@
|
||||
{.experimental: "openSym".}
|
||||
{.experimental: "templateOpenSym".}
|
||||
|
||||
block: # issue #24002
|
||||
type Result[T, E] = object
|
||||
|
||||
@@ -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"
|
||||
@@ -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".}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user