mirror of
https://github.com/nim-lang/Nim.git
synced 2026-09-01 19:33:42 +00:00
Merge branch 'devel' into araq-ic-fixes2
One conflict, in `canRaiseDisp`, where both sides added to the same guard: * devel (#26145) short-circuits `skMethod` to "can raise", because a base method's inferred effects describe only the base body, not every vtable target; * this branch resets `markCanRaiseBranch` to 5 on entry, so that a `-d: icCanRaiseLog` differential attributes an answer to the branch that actually decided it rather than to whatever the previous call left behind. Both kept: the reset first, then devel's method branch, then the existing flags branch. Marker 5 already means "decided here, neither predicate ran", which is what the new branch does too, so it needs no new number — the comment now says both short-circuits land there. Verified on the merged tree: `tests/ic` 40/40, including devel's new `timportcalias`; the cursor-driven and `PNode`-driven backends still generate byte-identical C (67/67 under `--ic:on`); ccgbugs 146, concepts 48, method 22, destructor 97, arc 140, gc 78, closure 23, iter 71, exception 47, all clean. `tests/generics/tparser_generator.nim` fails, and does NOT come from this merge: it fails the same way on pristine `origin/devel`, built and run in a throwaway worktree to check. The compile succeeds; the spec expects no output and the compiler now emits `typed`-deprecation and unused-import warnings. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FMyRHByv7hhaQJ4Pa1bHbE
This commit is contained in:
@@ -15,9 +15,13 @@ proc canRaiseDisp(p: BProc; n: AnyNode): bool =
|
||||
# keeps whatever the PREVIOUS call left in it and the early return below
|
||||
# attributes this answer to a branch that did not execute — which is how the
|
||||
# first run of this differential came to claim effect-list coverage it did
|
||||
# not have.
|
||||
# not have. Both short-circuits below leave it at 5.
|
||||
markCanRaiseBranch 5
|
||||
if n.kind == nkSym and {sfNeverRaises, sfImportc, sfCompilerProc} * n.sym.flags != {}:
|
||||
if n.kind == nkSym and n.sym.kind == skMethod:
|
||||
# A base method may be overridden by a branch with a wider exception set.
|
||||
# Its inferred effects describe only the base body, not every vtable target.
|
||||
result = true
|
||||
elif n.kind == nkSym and {sfNeverRaises, sfImportc, sfCompilerProc} * n.sym.flags != {}:
|
||||
result = false
|
||||
elif optPanics in p.config.globalOptions or
|
||||
(n.kind == nkSym and sfSystemModule in getModule(n.sym).flags and
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
## for details. Note this is a first implementation and only the "Concept matching"
|
||||
## section has been implemented.
|
||||
|
||||
import ast, semdata, lookups, lineinfos, idents, msgs, renderer, types, layeredtable
|
||||
import ast, semdata, lookups, lineinfos, idents, msgs, renderer, types,
|
||||
layeredtable, semtypinst
|
||||
|
||||
import std/sets
|
||||
|
||||
@@ -71,7 +72,8 @@ proc semConceptDeclaration*(c: PContext; n: PNode): PNode =
|
||||
|
||||
type
|
||||
MatchFlags* = enum
|
||||
mfDontBind # Do not bind generic parameters
|
||||
mfDontBind # Do not export bindings from the concept match
|
||||
mfBindGenericParam # Export inferred invocation parameters despite mfDontBind
|
||||
mfCheckGeneric # formal <- formal comparison as opposed to formal <- operand
|
||||
|
||||
ConceptTypePair = tuple[conceptId, typeId: ItemId]
|
||||
@@ -573,7 +575,17 @@ proc conceptMatchNode(c: PContext; n: PNode; m: var MatchCon): bool =
|
||||
# error was reported earlier.
|
||||
result = false
|
||||
|
||||
proc fixBindings(bindings: var LayeredIdTable; concpt: PType; invocation: PType; m: var MatchCon) =
|
||||
proc resolvedBinding(c: PContext; t: PType; m: MatchCon): PType =
|
||||
## An inferred concept parameter can refer to an implementation-local
|
||||
## generic parameter, for example `Elem[Impl.T]`. Resolve it while the
|
||||
## matcher's private bindings (`Impl.T -> int`) are still available.
|
||||
if t.containsUnresolvedType:
|
||||
prepareMetatypeForSigmatch(c, m.bindings, m.concpt.sym.info, t)
|
||||
else:
|
||||
t
|
||||
|
||||
proc fixBindings(c: PContext; bindings: var LayeredIdTable; concpt: PType;
|
||||
invocation: PType; m: var MatchCon) =
|
||||
# invocation != nil means we have a non-atomic concept:
|
||||
if invocation != nil and invocation.kind == tyGenericInvocation:
|
||||
assert concpt.sym.typ.kind == tyGenericBody
|
||||
@@ -585,8 +597,9 @@ proc fixBindings(bindings: var LayeredIdTable; concpt: PType; invocation: PType;
|
||||
continue
|
||||
let found = m.bindings.lookup(thisSym)
|
||||
if found != nil:
|
||||
when logBindings: echo "Invocation bind: ", thisSym, " ", found
|
||||
bindings.put(thisSym, found)
|
||||
let resolved = resolvedBinding(c, found, m)
|
||||
when logBindings: echo "Invocation bind: ", thisSym, " ", resolved
|
||||
bindings.put(thisSym, resolved)
|
||||
|
||||
# bind even more generic parameters
|
||||
let genBody = invocation.base
|
||||
@@ -602,6 +615,20 @@ proc fixBindings(bindings: var LayeredIdTable; concpt: PType; invocation: PType;
|
||||
bindings.put(invocation[i], boundV)
|
||||
bindings.put(concpt, m.potentialImplementation)
|
||||
|
||||
proc fixConstraintBindings(c: PContext; bindings: var LayeredIdTable;
|
||||
invocation: PType; m: MatchCon) =
|
||||
## Propagates only the dependent parameters of a concept constraint. The
|
||||
## concept itself and its private matcher bindings must remain unbound so
|
||||
## that independent constraints using the same concept don't get coupled.
|
||||
if invocation != nil and invocation.kind == tyGenericInvocation:
|
||||
let genBody = invocation.base
|
||||
assert genBody.kind == tyGenericBody
|
||||
for i in FirstGenericParamAt ..< invocation.kidsLen:
|
||||
if lookup(bindings, invocation[i]) == nil:
|
||||
let boundValue = m.bindings.lookup(genBody[i - 1])
|
||||
if boundValue != nil:
|
||||
bindings.put(invocation[i], resolvedBinding(c, boundValue, m))
|
||||
|
||||
proc processConcept(c: PContext; concpt, invocation: PType, bindings: var LayeredIdTable; m: var MatchCon): bool =
|
||||
m.bindings = m.bindings.newTypeMapLayer()
|
||||
if invocation != nil and invocation.kind == tyGenericInst:
|
||||
@@ -611,8 +638,11 @@ proc processConcept(c: PContext; concpt, invocation: PType, bindings: var Layere
|
||||
if invocation[i].kind != tyVoid:
|
||||
bindParam(c, m, genericBody[i-1], invocation[i])
|
||||
result = conceptMatchNode(c, concpt.conceptBody, m)
|
||||
if result and mfDontBind notin m.flags:
|
||||
fixBindings(bindings, concpt, invocation, m)
|
||||
if result:
|
||||
if mfDontBind notin m.flags:
|
||||
fixBindings(c, bindings, concpt, invocation, m)
|
||||
elif mfBindGenericParam in m.flags:
|
||||
fixConstraintBindings(c, bindings, invocation, m)
|
||||
|
||||
proc conceptMatch*(c: PContext; concpt, arg: PType; bindings: var LayeredIdTable; invocation: PType, flags: set[MatchFlags] = {}): bool =
|
||||
## Entry point from sigmatch. 'concpt' is the concept we try to match (here still a PType but
|
||||
|
||||
@@ -423,6 +423,20 @@ proc genDefaultCall(t: PType; c: Con; info: TLineInfo): PNode =
|
||||
result.add(newSymNode(createMagic(c.graph, c.idgen, "default", mDefault)))
|
||||
result.typ = t
|
||||
|
||||
proc stabilizeBracketIndex(n: PNode; c: var Con; body: var PNode): PNode =
|
||||
## Evaluate a side-effecting index once and return the stable access.
|
||||
doAssert n.kind == nkBracketExpr and not isAtom(n[1])
|
||||
let temp = newSym(skLet, getIdent(c.graph.cache, "bracketTmp"), c.idgen,
|
||||
c.owner, n[1].info)
|
||||
temp.typ = n[1].typ
|
||||
let tempAsNode = newSymNode(temp)
|
||||
body.add newTree(nkLetSection, n[1].info,
|
||||
newTree(nkIdentDefs, tempAsNode,
|
||||
newNodeI(nkEmpty, tempAsNode.info), n[1]))
|
||||
result = copyNode(n)
|
||||
result.add n[0]
|
||||
result.add tempAsNode
|
||||
|
||||
proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode =
|
||||
# generate: (let tmp = v; reset(v); tmp)
|
||||
if (not hasDestructor(c, n.typ)) and c.inEnsureMove == 0:
|
||||
@@ -434,6 +448,10 @@ proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode =
|
||||
else:
|
||||
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
|
||||
|
||||
var n = n
|
||||
if n.kind == nkBracketExpr and not isAtom(n[1]):
|
||||
n = stabilizeBracketIndex(n, c, result)
|
||||
|
||||
var temp = newSym(skLet, getIdent(c.graph.cache, "blitTmp"), c.idgen, c.owner, n.info)
|
||||
temp.typ = n.typ
|
||||
var v = newNodeI(nkLetSection, n.info)
|
||||
@@ -1155,24 +1173,11 @@ proc sameLocation*(a, b: PNode): bool =
|
||||
else: false
|
||||
|
||||
proc genFieldAccessSideEffects(c: var Con; s: var Scope; dest, ri: PNode; flags: set[MoveOrCopyFlag] = {}): PNode =
|
||||
# with side effects
|
||||
var temp = newSym(skLet, getIdent(c.graph.cache, "bracketTmp"), c.idgen, c.owner, ri[1].info)
|
||||
temp.typ = ri[1].typ
|
||||
var v = newNodeI(nkLetSection, ri[1].info)
|
||||
let tempAsNode = newSymNode(temp)
|
||||
|
||||
var vpart = newNodeI(nkIdentDefs, tempAsNode.info, 3)
|
||||
vpart[0] = tempAsNode
|
||||
vpart[1] = newNodeI(nkEmpty, tempAsNode.info)
|
||||
vpart[2] = ri[1]
|
||||
v.add(vpart)
|
||||
|
||||
var newAccess = copyNode(ri)
|
||||
newAccess.add ri[0]
|
||||
newAccess.add tempAsNode
|
||||
|
||||
var snk = c.genSink(s, dest, newAccess, flags)
|
||||
result = newTree(nkStmtList, v, snk, c.genWasMoved(newAccess))
|
||||
result = newNodeI(nkStmtList, ri.info)
|
||||
let newAccess = stabilizeBracketIndex(ri, c, result)
|
||||
let snk = c.genSink(s, dest, newAccess, flags)
|
||||
result.add snk
|
||||
result.add c.genWasMoved(newAccess)
|
||||
|
||||
proc ownsData(c: var Con; s: var Scope; orig: PNode; flags: set[MoveOrCopyFlag]): PNode =
|
||||
var n = orig
|
||||
|
||||
@@ -2160,47 +2160,54 @@ proc checkedForDestructor(t: PType): bool =
|
||||
return true
|
||||
result = false
|
||||
|
||||
proc whereToBindTypeHook(c: PContext; t: PType): PType =
|
||||
proc normalizeTypeHook(t: PType; markAsgn = false): PType =
|
||||
result = t
|
||||
while true:
|
||||
if result.kind in {tyGenericBody, tyGenericInst}: result = result.skipModifier
|
||||
elif result.kind == tyGenericInvocation: result = result[0]
|
||||
else: break
|
||||
if markAsgn:
|
||||
incl(result, tfHasAsgn)
|
||||
if result.kind == tyCompositeTypeClass and result.base.kind == tyGenericBody:
|
||||
result = result.base
|
||||
elif result.kind in {tyGenericBody, tyGenericInst}:
|
||||
result = result.skipModifier
|
||||
elif result.kind == tyGenericInvocation:
|
||||
result = result.genericHead
|
||||
else:
|
||||
break
|
||||
|
||||
proc whereToBindTypeHook(c: PContext; t: PType): PType =
|
||||
result = normalizeTypeHook(t)
|
||||
if result.kind in {tyObject, tyDistinct, tySequence, tyString}:
|
||||
result = canonType(c, result)
|
||||
|
||||
proc bindHookToType(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp;
|
||||
typeToBind: PType): bool =
|
||||
var obj = typeToBind
|
||||
if obj.kind notin {tyObject, tyDistinct, tySequence, tyString}:
|
||||
return false
|
||||
obj = canonType(c, obj)
|
||||
let ao = getAttachedOp(c.graph, obj, op)
|
||||
if ao == s:
|
||||
discard "forward declared hook"
|
||||
elif ao.isNil and not checkedForDestructor(obj):
|
||||
setAttachedOp(c.graph, c.module.position, obj, op, s)
|
||||
else:
|
||||
prevDestructor(c, op, ao, obj, n.info)
|
||||
if obj.owner.getModule != s.getModule:
|
||||
localError(c.config, n.info, errGenerated,
|
||||
"type bound operation `" & s.name.s & "` can be defined only in the same module with its type (" & obj.typeToString() & ")")
|
||||
result = true
|
||||
|
||||
proc bindDupHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
|
||||
let t = s.typ
|
||||
var noError = false
|
||||
let cond = t.len == 2 and t.returnType != nil
|
||||
|
||||
if cond:
|
||||
var obj = t.firstParamType
|
||||
while true:
|
||||
incl(obj, tfHasAsgn)
|
||||
if obj.kind in {tyGenericBody, tyGenericInst}: obj = obj.skipModifier
|
||||
elif obj.kind == tyGenericInvocation: obj = obj.genericHead
|
||||
else: break
|
||||
var obj = normalizeTypeHook(t.firstParamType, markAsgn = true)
|
||||
let res = normalizeTypeHook(t.returnType)
|
||||
|
||||
var res = t.returnType
|
||||
while true:
|
||||
if res.kind in {tyGenericBody, tyGenericInst}: res = res.skipModifier
|
||||
elif res.kind == tyGenericInvocation: res = res.genericHead
|
||||
else: break
|
||||
|
||||
if obj.kind in {tyObject, tyDistinct, tySequence, tyString} and sameType(obj, res):
|
||||
obj = canonType(c, obj)
|
||||
let ao = getAttachedOp(c.graph, obj, op)
|
||||
if ao == s:
|
||||
discard "forward declared destructor"
|
||||
elif ao.isNil and not checkedForDestructor(obj):
|
||||
setAttachedOp(c.graph, c.module.position, obj, op, s)
|
||||
else:
|
||||
prevDestructor(c, op, ao, obj, n.info)
|
||||
noError = true
|
||||
if obj.owner.getModule != s.getModule:
|
||||
localError(c.config, n.info, errGenerated,
|
||||
"type bound operation `" & s.name.s & "` can be defined only in the same module with its type (" & obj.typeToString() & ")")
|
||||
if sameType(obj, res):
|
||||
noError = bindHookToType(c, s, n, op, obj)
|
||||
|
||||
if not noError and sfSystemModule notin s.owner.flags:
|
||||
localError(c.config, n.info, errGenerated,
|
||||
@@ -2230,25 +2237,8 @@ proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
|
||||
t.len >= 2 and t.returnType == nil
|
||||
|
||||
if cond:
|
||||
var obj = t.firstParamType.skipTypes({tyVar})
|
||||
while true:
|
||||
incl(obj, tfHasAsgn)
|
||||
if obj.kind in {tyGenericBody, tyGenericInst}: obj = obj.skipModifier
|
||||
elif obj.kind == tyGenericInvocation: obj = obj.genericHead
|
||||
else: break
|
||||
if obj.kind in {tyObject, tyDistinct, tySequence, tyString}:
|
||||
obj = canonType(c, obj)
|
||||
let ao = getAttachedOp(c.graph, obj, op)
|
||||
if ao == s:
|
||||
discard "forward declared destructor"
|
||||
elif ao.isNil and not checkedForDestructor(obj):
|
||||
setAttachedOp(c.graph, c.module.position, obj, op, s)
|
||||
else:
|
||||
prevDestructor(c, op, ao, obj, n.info)
|
||||
noError = true
|
||||
if obj.owner.getModule != s.getModule:
|
||||
localError(c.config, n.info, errGenerated,
|
||||
"type bound operation `" & s.name.s & "` can be defined only in the same module with its type (" & obj.typeToString() & ")")
|
||||
var obj = normalizeTypeHook(t.firstParamType.skipTypes({tyVar}), markAsgn = true)
|
||||
noError = bindHookToType(c, s, n, op, obj)
|
||||
if not noError and sfSystemModule notin s.owner.flags:
|
||||
case op
|
||||
of attachedTrace:
|
||||
@@ -2315,35 +2305,12 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
|
||||
message(c.config, n.info, warnDeprecated, "Overriding `=` hook is deprecated; Override `=copy` hook instead")
|
||||
let t = s.typ
|
||||
if t.len == 3 and t.returnType == nil and t.firstParamType.kind == tyVar:
|
||||
var obj = t.firstParamType.elementType
|
||||
while true:
|
||||
incl(obj, tfHasAsgn)
|
||||
if obj.kind == tyGenericBody: obj = obj.skipModifier
|
||||
elif obj.kind == tyGenericInvocation: obj = obj.genericHead
|
||||
else: break
|
||||
var objB = t[2]
|
||||
while true:
|
||||
if objB.kind == tyGenericBody: objB = objB.skipModifier
|
||||
elif objB.kind in {tyGenericInvocation, tyGenericInst}:
|
||||
objB = objB.genericHead
|
||||
else: break
|
||||
if obj.kind in {tyObject, tyDistinct, tySequence, tyString} and sameType(obj, objB):
|
||||
var obj = normalizeTypeHook(t.firstParamType.elementType, markAsgn = true)
|
||||
let objB = normalizeTypeHook(t[2])
|
||||
if sameType(obj, objB):
|
||||
# attach these ops to the canonical tySequence
|
||||
obj = canonType(c, obj)
|
||||
#echo "ATTACHING TO ", obj.id, " ", s.name.s, " ", cast[int](obj)
|
||||
let k = if name == "=" or name == "=copy": attachedAsgn else: attachedSink
|
||||
let ao = getAttachedOp(c.graph, obj, k)
|
||||
if ao == s:
|
||||
discard "forward declared op"
|
||||
elif ao.isNil and not checkedForDestructor(obj):
|
||||
setAttachedOp(c.graph, c.module.position, obj, k, s)
|
||||
else:
|
||||
prevDestructor(c, k, ao, obj, n.info)
|
||||
if obj.owner.getModule != s.getModule:
|
||||
localError(c.config, n.info, errGenerated,
|
||||
"type bound operation `" & name & "` can be defined only in the same module with its type (" & obj.typeToString() & ")")
|
||||
|
||||
return
|
||||
if bindHookToType(c, s, n, k, obj): return
|
||||
if sfSystemModule notin s.owner.flags:
|
||||
localError(c.config, n.info, errGenerated,
|
||||
"signature for '" & s.name.s & "' must be proc[T: object](x: var T; y: T)")
|
||||
|
||||
@@ -209,7 +209,11 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: Confi
|
||||
# backend spelling instead of collapsing into the generic Nim builtin:
|
||||
c &= char(t.kind)
|
||||
if t.sym != nil and {sfImportc, sfExportc} * t.sym.flags != {}:
|
||||
c.hashSym(t.sym)
|
||||
# Aliases inherit the external name, but have a different symbol.
|
||||
if t.sym.loc.snippet != "":
|
||||
c &= t.sym.loc.snippet
|
||||
else:
|
||||
c.hashSym(t.sym)
|
||||
of tyObject, tyEnum:
|
||||
if t.typeInstImpl != nil:
|
||||
# prevent against infinite recursions here, see bug #8883:
|
||||
|
||||
@@ -1166,6 +1166,8 @@ proc enterConceptMatch(c: var TCandidate; f,a: PType, flags: TTypeRelFlags): TTy
|
||||
return typeRel(c, prev, a, flags)
|
||||
if trDontBind in flags:
|
||||
conceptFlags.incl mfDontBind
|
||||
if trBindGenericParam in flags:
|
||||
conceptFlags.incl mfBindGenericParam
|
||||
if trCheckGeneric in flags:
|
||||
conceptFlags.incl mfCheckGeneric
|
||||
let mres = concepts.conceptMatch(c.c, concpt, a, c.bindings, container, flags = conceptFlags)
|
||||
|
||||
@@ -3304,13 +3304,21 @@ proc dirInclude(p: var RstParser): PRstNode =
|
||||
## Only the content before the first occurrence of the specified
|
||||
## text (but after any after text) will be included. If text is
|
||||
## not found inclusion will happen until the end of the file.
|
||||
#literal : flag (empty)
|
||||
# The entire included text is inserted into the document as a single
|
||||
# literal block (useful for program listings).
|
||||
#encoding : name of text encoding
|
||||
# The text encoding of the external data file. Defaults to the document's
|
||||
# encoding (if specified).
|
||||
#
|
||||
##
|
||||
## :literal: flag (empty)
|
||||
##
|
||||
## The entire included text is inserted into the document as a single
|
||||
## literal block (useful for program listings).
|
||||
##
|
||||
## :code: language (if empty, `nim` is assumed by default)
|
||||
##
|
||||
## The argument and the included content are passed to the code directive
|
||||
## (useful for program listings).
|
||||
##
|
||||
## :encoding: name of text encoding
|
||||
##
|
||||
## The text encoding of the external data file. Defaults to the document's
|
||||
## encoding (if specified).
|
||||
result = nil
|
||||
var n = parseDirective(p, rnDirective, {hasArg, argIsFile, hasOptions}, nil)
|
||||
var filename = strip(addNodes(n.sons[0]))
|
||||
@@ -3343,6 +3351,19 @@ proc dirInclude(p: var RstParser): PRstNode =
|
||||
if getFieldValue(n, "literal") != "":
|
||||
result = newRstNode(rnLiteralBlock)
|
||||
result.add newLeaf(inputString[startPosition..endPosition])
|
||||
elif getFieldValue(n, "code") != "":
|
||||
result = newRstNode(rnCodeBlock)
|
||||
result.sons.setLen(3)
|
||||
let lang = getFieldValue(n, "code").strip()
|
||||
if lang notin ["", "\x01\x01"]:
|
||||
var codeArg = newRstNode(rnDirArg)
|
||||
codeArg.add(newLeaf(lang))
|
||||
result.sons[0] = codeArg
|
||||
result.sons[1] = newRstNode(rnFieldList)
|
||||
defaultCodeLangNim(p, result)
|
||||
var litBlock = newRstNode(rnLiteralBlock)
|
||||
litBlock.add newLeaf(inputString[startPosition..endPosition])
|
||||
result.sons[2] = litBlock
|
||||
else:
|
||||
var q: RstParser
|
||||
initParser(q, p.s)
|
||||
|
||||
@@ -1254,7 +1254,9 @@ proc del*[T](x: var seq[T], i: Natural) {.noSideEffect.} =
|
||||
a.del(2)
|
||||
assert a == @[10, 11, 14, 13]
|
||||
let xl = x.len - 1
|
||||
movingCopy(x[i], x[xl])
|
||||
# Avoid moving the element onto itself when deleting the last item.
|
||||
if i != xl:
|
||||
movingCopy(x[i], x[xl])
|
||||
setLen(x, xl)
|
||||
|
||||
proc insert*[T](x: var seq[T], item: sink T, i = 0.Natural) {.noSideEffect.} =
|
||||
|
||||
@@ -35,6 +35,20 @@ proc bug20303() =
|
||||
|
||||
bug20303()
|
||||
|
||||
block: # bug #26143
|
||||
var indexCalls = 0
|
||||
|
||||
proc nextIndex(): int =
|
||||
result = indexCalls
|
||||
inc indexCalls
|
||||
|
||||
proc consume(value: sink string) =
|
||||
doAssert value == "A"
|
||||
|
||||
var values = @["A", "B"]
|
||||
consume(values[nextIndex()])
|
||||
doAssert indexCalls == 1
|
||||
|
||||
proc main() = # todo bug with templates
|
||||
block: # bug #11267
|
||||
var a: seq[char] = block: @[]
|
||||
|
||||
5
tests/ccgbugs/mseq_importc_alias.nim
Normal file
5
tests/ccgbugs/mseq_importc_alias.nim
Normal file
@@ -0,0 +1,5 @@
|
||||
proc resizeCints*(s: var seq[cint], n: int) =
|
||||
s.setLen(n)
|
||||
|
||||
proc cintLen*(s: seq[cint]): int =
|
||||
result = s.len
|
||||
15
tests/ccgbugs/tseq_importc_alias_crossmod.nim
Normal file
15
tests/ccgbugs/tseq_importc_alias_crossmod.nim
Normal file
@@ -0,0 +1,15 @@
|
||||
discard """
|
||||
action: run
|
||||
targets: "c cpp"
|
||||
"""
|
||||
|
||||
import mseq_importc_alias
|
||||
|
||||
type CIntAlias = cint
|
||||
|
||||
var fds: seq[CIntAlias]
|
||||
doAssert cintLen(@[1.cint, 2.cint]) == 2
|
||||
doAssert cintLen(fds) == 0
|
||||
resizeCints(fds, 3)
|
||||
fds[1] = CIntAlias(7)
|
||||
doAssert cintLen(fds) == 3
|
||||
20
tests/ccgbugs/tseq_importc_alias_mangle.nim
Normal file
20
tests/ccgbugs/tseq_importc_alias_mangle.nim
Normal file
@@ -0,0 +1,20 @@
|
||||
discard """
|
||||
action: run
|
||||
targets: "c cpp"
|
||||
"""
|
||||
|
||||
type CIntAlias = cint
|
||||
|
||||
var x: (cint,) = (1.cint,)
|
||||
var y: (CIntAlias,) = x
|
||||
x = y
|
||||
doAssert x[0] == 1.cint
|
||||
|
||||
var a: seq[cint]
|
||||
var b: seq[CIntAlias]
|
||||
a.add 1.cint
|
||||
a.add 2.cint
|
||||
b = a
|
||||
a = b
|
||||
doAssert a[0] == 1.cint
|
||||
doAssert b[1] == CIntAlias(2)
|
||||
75
tests/concepts/t26147.nim
Normal file
75
tests/concepts/t26147.nim
Normal file
@@ -0,0 +1,75 @@
|
||||
discard """
|
||||
action: run
|
||||
"""
|
||||
|
||||
type Indexable[T] = concept
|
||||
proc `[]`(a: Self; index: int): T
|
||||
proc len(a: Self): int
|
||||
|
||||
iterator items[T; I: Indexable[T]](indexable: I): T =
|
||||
for index in 0 ..< indexable.len:
|
||||
yield indexable[index]
|
||||
|
||||
type Dummy[T] = distinct seq[T]
|
||||
|
||||
proc `[]`[T](d: Dummy[T], i: int): T = seq[T](d)[i]
|
||||
proc len[T](d: Dummy[T]): int = seq[T](d).len
|
||||
|
||||
var acc = 0
|
||||
for x in Dummy(@[1, 2, 3]):
|
||||
acc += x
|
||||
doAssert acc == 6
|
||||
|
||||
# Inferred concept parameters are resolved through the implementation's own
|
||||
# generic bindings before being exported to the surrounding routine.
|
||||
type
|
||||
Elem[T] = object
|
||||
value: T
|
||||
NestedDummy[T] = ref object
|
||||
data: seq[T]
|
||||
|
||||
proc `[]`[T](d: NestedDummy[T], i: int): Elem[T] =
|
||||
Elem[T](value: d.data[i])
|
||||
proc len[T](d: NestedDummy[T]): int = d.data.len
|
||||
|
||||
iterator directItems[T](indexable: Indexable[T]): T =
|
||||
for index in 0 ..< indexable.len:
|
||||
yield indexable[index]
|
||||
|
||||
var nestedAcc = 0
|
||||
for x in NestedDummy[int](data: @[4, 5, 6]):
|
||||
nestedAcc += x.value
|
||||
doAssert nestedAcc == 15
|
||||
|
||||
var directNestedAcc = 0
|
||||
for x in directItems(NestedDummy[int](data: @[7, 8, 9])):
|
||||
directNestedAcc += x.value
|
||||
doAssert directNestedAcc == 24
|
||||
|
||||
# All dependent parameters inferred while checking a concept constraint must
|
||||
# be propagated to the constrained routine.
|
||||
type
|
||||
KeyValue[K, V] = concept
|
||||
proc key(x: Self): K
|
||||
proc value(x: Self): V
|
||||
Pair[K, V] = object
|
||||
k: K
|
||||
v: V
|
||||
|
||||
proc key[K, V](x: Pair[K, V]): K = x.k
|
||||
proc value[K, V](x: Pair[K, V]): V = x.v
|
||||
|
||||
proc unpack[K, V; P: KeyValue[K, V]](x: P): (K, V) =
|
||||
(x.key, x.value)
|
||||
|
||||
let pair = Pair[int, string](k: 7, v: "seven")
|
||||
doAssert unpack(pair) == (7, "seven")
|
||||
doAssert not compiles(unpack[string, int](pair))
|
||||
|
||||
proc unpackBoth[K1, V1, K2, V2;
|
||||
P1: KeyValue[K1, V1]; P2: KeyValue[K2, V2]](
|
||||
x: P1; y: P2): ((K1, V1), (K2, V2)) =
|
||||
(unpack(x), unpack(y))
|
||||
|
||||
let otherPair = Pair[string, float](k: "eight", v: 8.0)
|
||||
doAssert unpackBoth(pair, otherPair) == ((7, "seven"), ("eight", 8.0))
|
||||
@@ -166,3 +166,99 @@ type Vector*[T] = object
|
||||
# proc `=destroy`*(x: var Vector[int]) = discard # this will remove error
|
||||
proc `=destroy`*[T](x: var Vector[T]) = discard
|
||||
var a: Vector[int] # Error: unresolved generic parameter
|
||||
|
||||
# issue #26132
|
||||
|
||||
block:
|
||||
type UnparameterizedGeneric[T] = object
|
||||
|
||||
proc `=destroy`(x: var UnparameterizedGeneric) = discard
|
||||
proc `=wasMoved`(x: var UnparameterizedGeneric) = discard
|
||||
proc `=trace`(x: var UnparameterizedGeneric; env: pointer) = discard
|
||||
|
||||
var x: UnparameterizedGeneric[int]
|
||||
discard x
|
||||
|
||||
# Exercise every type-bound hook with the generic parameter omitted.
|
||||
block:
|
||||
type
|
||||
Generic[T] = object
|
||||
value: T
|
||||
|
||||
var destroys, moves, traces, copies, sinks, dups: int
|
||||
|
||||
proc `=destroy`(x: var Generic) = inc destroys
|
||||
proc `=wasMoved`(x: var Generic) =
|
||||
inc moves
|
||||
x.value = default(typeof(x.value))
|
||||
proc `=trace`(x: var Generic; env: pointer) = inc traces
|
||||
proc `=copy`(dest: var Generic; src: Generic) =
|
||||
inc copies
|
||||
dest.value = src.value
|
||||
proc `=sink`(dest: var Generic; src: Generic) =
|
||||
inc sinks
|
||||
dest.value = src.value
|
||||
proc `=dup`(src: Generic): Generic =
|
||||
inc dups
|
||||
Generic(value: src.value)
|
||||
proc deepCopy(src: ref Generic): ref Generic = src
|
||||
|
||||
proc exercise[T]() =
|
||||
var first = Generic[T](value: default(T))
|
||||
var second = Generic[T](value: default(T))
|
||||
second = first
|
||||
doAssert second.value == first.value
|
||||
second = Generic[T](value: default(T))
|
||||
doAssert second.value == default(T)
|
||||
`=trace`(first, nil)
|
||||
`=wasMoved`(first)
|
||||
let implicitDuplicate = first
|
||||
discard implicitDuplicate
|
||||
let duplicate = `=dup`(first)
|
||||
discard duplicate
|
||||
let original = new(Generic[T])
|
||||
doAssert deepCopy(original) == original
|
||||
|
||||
exercise[string]()
|
||||
exercise[int]()
|
||||
exercise[seq[int]]()
|
||||
|
||||
doAssert copies > 0
|
||||
doAssert sinks > 0
|
||||
doAssert dups > 0
|
||||
doAssert moves > 0
|
||||
doAssert traces > 0
|
||||
doAssert destroys > 0
|
||||
|
||||
block:
|
||||
type GenericDistinct[T] = distinct Generic[T]
|
||||
|
||||
proc `=destroy`(x: var GenericDistinct) = discard
|
||||
proc `=wasMoved`(x: var GenericDistinct) = discard
|
||||
proc `=trace`(x: var GenericDistinct; env: pointer) = discard
|
||||
proc `=copy`(dest: var GenericDistinct; src: GenericDistinct) = discard
|
||||
proc `=sink`(dest: var GenericDistinct; src: GenericDistinct) = discard
|
||||
proc `=dup`(src: GenericDistinct): GenericDistinct = src
|
||||
proc deepCopy(src: ref GenericDistinct): ref GenericDistinct = src
|
||||
|
||||
var first = GenericDistinct[string](Generic[string](value: "first"))
|
||||
var second = GenericDistinct[string](Generic[string](value: "second"))
|
||||
second = first
|
||||
second = GenericDistinct[string](Generic[string](value: "third"))
|
||||
`=trace`(first, nil)
|
||||
`=wasMoved`(first)
|
||||
let moved = move(first)
|
||||
let duplicate = `=dup`(moved)
|
||||
discard duplicate
|
||||
let original = new(GenericDistinct[string])
|
||||
doAssert deepCopy(original) == original
|
||||
|
||||
block:
|
||||
type GenericPair[A, B] = object
|
||||
left: A
|
||||
right: B
|
||||
|
||||
proc `=destroy`(x: var GenericPair) = discard
|
||||
|
||||
var pair = GenericPair[int, string](left: 42, right: "pair")
|
||||
discard pair
|
||||
|
||||
7
tests/ic/timportcalias.nim
Normal file
7
tests/ic/timportcalias.nim
Normal file
@@ -0,0 +1,7 @@
|
||||
import ../ccgbugs/mseq_importc_alias
|
||||
|
||||
type CIntAlias = cint
|
||||
|
||||
var values: seq[CIntAlias]
|
||||
resizeCints(values, 2)
|
||||
doAssert cintLen(values) == 2
|
||||
20
tests/method/tmethod_virtual_raise.nim
Normal file
20
tests/method/tmethod_virtual_raise.nim
Normal file
@@ -0,0 +1,20 @@
|
||||
discard """
|
||||
output: '''caught'''
|
||||
"""
|
||||
|
||||
type
|
||||
Base = ref object of RootObj
|
||||
Child = ref object of Base
|
||||
|
||||
method run(value: Base): string {.base.} =
|
||||
result = "base"
|
||||
|
||||
method run(value: Child): string =
|
||||
raise newException(ValueError, "child")
|
||||
|
||||
let value: Base = Child()
|
||||
try:
|
||||
discard value.run()
|
||||
quit "virtual method did not raise"
|
||||
except ValueError:
|
||||
echo "caught"
|
||||
24
tests/stdlib/t26134.nim
Normal file
24
tests/stdlib/t26134.nim
Normal file
@@ -0,0 +1,24 @@
|
||||
discard """
|
||||
matrix: "--mm:orc --undef:nimPreviewNonVarDestructor"
|
||||
output: "hello"
|
||||
"""
|
||||
|
||||
# bug #26134
|
||||
|
||||
type MyObject = object
|
||||
|
||||
proc `=destroy`(v: var MyObject) =
|
||||
echo "hello"
|
||||
|
||||
proc remove(v: var seq[MyObject]) =
|
||||
v.del(0)
|
||||
|
||||
proc aaa(v: var seq[MyObject], i: sink MyObject) =
|
||||
v.add(i)
|
||||
|
||||
proc main =
|
||||
var v: seq[MyObject]
|
||||
v.aaa(MyObject())
|
||||
v.remove()
|
||||
|
||||
main()
|
||||
Reference in New Issue
Block a user