destructors: first step towards fixing #9617 (#10341)

This commit is contained in:
cooldome 2019-01-18 07:51:22 +00:00 • committed by Andreas Rumpf
commit 1e63f1edb3
6 changed files with 110 additions and 67 deletions

View file

@ -14,7 +14,7 @@
type type
TLiftCtx = object TLiftCtx = object
c: PContext graph: ModuleGraph
info: TLineInfo # for construction info: TLineInfo # for construction
kind: TTypeAttachedOp kind: TTypeAttachedOp
fn: PSym fn: PSym
@ -22,7 +22,7 @@ type
recurse: bool recurse: bool
proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode)
proc liftBody(c: PContext; typ: PType; kind: TTypeAttachedOp; proc liftBody(g: ModuleGraph; typ: PType; kind: TTypeAttachedOp;
info: TLineInfo): PSym {.discardable.} info: TLineInfo): PSym {.discardable.}
proc at(a, i: PNode, elemType: PType): PNode = proc at(a, i: PNode, elemType: PType): PNode =
@ -33,7 +33,7 @@ proc at(a, i: PNode, elemType: PType): PNode =
proc liftBodyTup(c: var TLiftCtx; t: PType; body, x, y: PNode) = proc liftBodyTup(c: var TLiftCtx; t: PType; body, x, y: PNode) =
for i in 0 ..< t.len: for i in 0 ..< t.len:
let lit = lowerings.newIntLit(c.c.graph, x.info, i) let lit = lowerings.newIntLit(c.graph, x.info, i)
liftBodyAux(c, t.sons[i], body, x.at(lit, t.sons[i]), y.at(lit, t.sons[i])) liftBodyAux(c, t.sons[i], body, x.at(lit, t.sons[i]), y.at(lit, t.sons[i]))
proc dotField(x: PNode, f: PSym): PNode = proc dotField(x: PNode, f: PSym): PNode =
@ -77,22 +77,22 @@ proc liftBodyObj(c: var TLiftCtx; n, body, x, y: PNode) =
of nkRecList: of nkRecList:
for t in items(n): liftBodyObj(c, t, body, x, y) for t in items(n): liftBodyObj(c, t, body, x, y)
else: else:
illFormedAstLocal(n, c.c.config) illFormedAstLocal(n, c.graph.config)
proc genAddr(c: PContext; x: PNode): PNode = proc genAddr(g: ModuleGraph; x: PNode): PNode =
if x.kind == nkHiddenDeref: if x.kind == nkHiddenDeref:
checkSonsLen(x, 1, c.config) checkSonsLen(x, 1, g.config)
result = x.sons[0] result = x.sons[0]
else: else:
result = newNodeIT(nkHiddenAddr, x.info, makeVarType(c, x.typ)) result = newNodeIT(nkHiddenAddr, x.info, makeVarType(x.typ.owner, x.typ))
addSon(result, x) addSon(result, x)
proc newAsgnCall(c: PContext; op: PSym; x, y: PNode): PNode = proc newAsgnCall(g: ModuleGraph; op: PSym; x, y: PNode): PNode =
#if sfError in op.flags: #if sfError in op.flags:
# localError(c.config, x.info, "usage of '$1' is a user-defined error" % op.name.s) # localError(c.config, x.info, "usage of '$1' is a user-defined error" % op.name.s)
result = newNodeI(nkCall, x.info) result = newNodeI(nkCall, x.info)
result.add newSymNode(op) result.add newSymNode(op)
result.add genAddr(c, x) result.add genAddr(g, x)
result.add y result.add y
proc newAsgnStmt(le, ri: PNode): PNode = proc newAsgnStmt(le, ri: PNode): PNode =
@ -105,10 +105,10 @@ proc newOpCall(op: PSym; x: PNode): PNode =
result.add(newSymNode(op)) result.add(newSymNode(op))
result.add x result.add x
proc destructorCall(c: PContext; op: PSym; x: PNode): PNode = proc destructorCall(g: ModuleGraph; op: PSym; x: PNode): PNode =
result = newNodeIT(nkCall, x.info, op.typ.sons[0]) result = newNodeIT(nkCall, x.info, op.typ.sons[0])
result.add(newSymNode(op)) result.add(newSymNode(op))
result.add genAddr(c, x) result.add genAddr(g, x)
proc newDeepCopyCall(op: PSym; x, y: PNode): PNode = proc newDeepCopyCall(op: PSym; x, y: PNode): PNode =
result = newAsgnStmt(x, newOpCall(op, y)) result = newAsgnStmt(x, newOpCall(op, y))
@ -127,13 +127,13 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
else: else:
op = field op = field
if op == nil: if op == nil:
op = liftBody(c.c, t, c.kind, c.info) op = liftBody(c.graph, t, c.kind, c.info)
if sfError in op.flags: if sfError in op.flags:
incl c.fn.flags, sfError incl c.fn.flags, sfError
else: else:
markUsed(c.c.config, c.info, op, c.c.graph.usageSym) markUsed(c.graph.config, c.info, op, c.graph.usageSym)
onUse(c.info, op) onUse(c.info, op)
body.add newAsgnCall(c.c, op, x, y) body.add newAsgnCall(c.graph, op, x, y)
result = true result = true
proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool = proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
@ -141,9 +141,9 @@ proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
of attachedDestructor: of attachedDestructor:
let op = t.destructor let op = t.destructor
if op != nil: if op != nil:
markUsed(c.c.config, c.info, op, c.c.graph.usageSym) markUsed(c.graph.config, c.info, op, c.graph.usageSym)
onUse(c.info, op) onUse(c.info, op)
body.add destructorCall(c.c, op, x) body.add destructorCall(c.graph, op, x)
result = true result = true
of attachedAsgn: of attachedAsgn:
result = considerAsgnOrSink(c, t, body, x, y, t.assignment) result = considerAsgnOrSink(c, t, body, x, y, t.assignment)
@ -152,7 +152,7 @@ proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
of attachedDeepCopy: of attachedDeepCopy:
let op = t.deepCopy let op = t.deepCopy
if op != nil: if op != nil:
markUsed(c.c.config, c.info, op, c.c.graph.usageSym) markUsed(c.graph.config, c.info, op, c.graph.usageSym)
onUse(c.info, op) onUse(c.info, op)
body.add newDeepCopyCall(op, x, y) body.add newDeepCopyCall(op, x, y)
result = true result = true
@ -169,13 +169,13 @@ proc addVar(father, v, value: PNode) =
addSon(father, vpart) addSon(father, vpart)
proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode = proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode =
var temp = newSym(skTemp, getIdent(c.c.cache, lowerings.genPrefix), c.fn, c.info) var temp = newSym(skTemp, getIdent(c.graph.cache, lowerings.genPrefix), c.fn, c.info)
temp.typ = getSysType(c.c.graph, body.info, tyInt) temp.typ = getSysType(c.graph, body.info, tyInt)
incl(temp.flags, sfFromGeneric) incl(temp.flags, sfFromGeneric)
var v = newNodeI(nkVarSection, c.info) var v = newNodeI(nkVarSection, c.info)
result = newSymNode(temp) result = newSymNode(temp)
v.addVar(result, lowerings.newIntLit(c.c.graph, body.info, first)) v.addVar(result, lowerings.newIntLit(c.graph, body.info, first))
body.add v body.add v
proc genBuiltin(g: ModuleGraph; magic: TMagic; name: string; i: PNode): PNode = proc genBuiltin(g: ModuleGraph; magic: TMagic; name: string; i: PNode): PNode =
@ -185,22 +185,22 @@ proc genBuiltin(g: ModuleGraph; magic: TMagic; name: string; i: PNode): PNode =
proc genWhileLoop(c: var TLiftCtx; i, dest: PNode): PNode = proc genWhileLoop(c: var TLiftCtx; i, dest: PNode): PNode =
result = newNodeI(nkWhileStmt, c.info, 2) result = newNodeI(nkWhileStmt, c.info, 2)
let cmp = genBuiltin(c.c.graph, mLeI, "<=", i) let cmp = genBuiltin(c.graph, mLeI, "<=", i)
cmp.add genHigh(c.c.graph, dest) cmp.add genHigh(c.graph, dest)
cmp.typ = getSysType(c.c.graph, c.info, tyBool) cmp.typ = getSysType(c.graph, c.info, tyBool)
result.sons[0] = cmp result.sons[0] = cmp
result.sons[1] = newNodeI(nkStmtList, c.info) result.sons[1] = newNodeI(nkStmtList, c.info)
proc addIncStmt(c: var TLiftCtx; body, i: PNode) = proc addIncStmt(c: var TLiftCtx; body, i: PNode) =
let incCall = genBuiltin(c.c.graph, mInc, "inc", i) let incCall = genBuiltin(c.graph, mInc, "inc", i)
incCall.add lowerings.newIntLit(c.c.graph, c.info, 1) incCall.add lowerings.newIntLit(c.graph, c.info, 1)
body.add incCall body.add incCall
proc newSeqCall(c: PContext; x, y: PNode): PNode = proc newSeqCall(g: ModuleGraph; x, y: PNode): PNode =
# don't call genAddr(c, x) here: # don't call genAddr(c, x) here:
result = genBuiltin(c.graph, mNewSeq, "newSeq", x) result = genBuiltin(g, mNewSeq, "newSeq", x)
let lenCall = genBuiltin(c.graph, mLengthSeq, "len", y) let lenCall = genBuiltin(g, mLengthSeq, "len", y)
lenCall.typ = getSysType(c.graph, x.info, tyInt) lenCall.typ = getSysType(g, x.info, tyInt)
result.add lenCall result.add lenCall
proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) = proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
@ -211,7 +211,7 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
defaultOp(c, t, body, x, y) defaultOp(c, t, body, x, y)
of tyArray: of tyArray:
if tfHasAsgn in t.flags: if tfHasAsgn in t.flags:
let i = declareCounter(c, body, firstOrd(c.c.config, t)) let i = declareCounter(c, body, firstOrd(c.graph.config, t))
let whileLoop = genWhileLoop(c, i, x) let whileLoop = genWhileLoop(c, i, x)
let elemType = t.lastSon let elemType = t.lastSon
liftBodyAux(c, elemType, whileLoop.sons[1], x.at(i, elemType), liftBodyAux(c, elemType, whileLoop.sons[1], x.at(i, elemType),
@ -223,12 +223,12 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
of tySequence: of tySequence:
# note that tfHasAsgn is propagated so we need the check on # note that tfHasAsgn is propagated so we need the check on
# 'selectedGC' here to determine if we have the new runtime. # 'selectedGC' here to determine if we have the new runtime.
if c.c.config.selectedGC == gcDestructors: if c.graph.config.selectedGC == gcDestructors:
discard considerOverloadedOp(c, t, body, x, y) discard considerOverloadedOp(c, t, body, x, y)
elif tfHasAsgn in t.flags: elif tfHasAsgn in t.flags:
if c.kind != attachedDestructor: if c.kind != attachedDestructor:
body.add newSeqCall(c.c, x, y) body.add newSeqCall(c.graph, x, y)
let i = declareCounter(c, body, firstOrd(c.c.config, t)) let i = declareCounter(c, body, firstOrd(c.graph.config, t))
let whileLoop = genWhileLoop(c, i, x) let whileLoop = genWhileLoop(c, i, x)
let elemType = t.lastSon let elemType = t.lastSon
liftBodyAux(c, elemType, whileLoop.sons[1], x.at(i, elemType), liftBodyAux(c, elemType, whileLoop.sons[1], x.at(i, elemType),
@ -258,20 +258,20 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
# have to go through some indirection; we delegate this to the codegen: # have to go through some indirection; we delegate this to the codegen:
let call = newNodeI(nkCall, c.info, 2) let call = newNodeI(nkCall, c.info, 2)
call.typ = t call.typ = t
call.sons[0] = newSymNode(createMagic(c.c.graph, "deepCopy", mDeepCopy)) call.sons[0] = newSymNode(createMagic(c.graph, "deepCopy", mDeepCopy))
call.sons[1] = y call.sons[1] = y
body.add newAsgnStmt(x, call) body.add newAsgnStmt(x, call)
of tyVarargs, tyOpenArray: of tyVarargs, tyOpenArray:
localError(c.c.config, c.info, "cannot copy openArray") localError(c.graph.config, c.info, "cannot copy openArray")
of tyFromExpr, tyProxy, tyBuiltInTypeClass, tyUserTypeClass, of tyFromExpr, tyProxy, tyBuiltInTypeClass, tyUserTypeClass,
tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot, tyAnything, tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot, tyAnything,
tyGenericParam, tyGenericBody, tyNil, tyExpr, tyStmt, tyGenericParam, tyGenericBody, tyNil, tyExpr, tyStmt,
tyTypeDesc, tyGenericInvocation, tyForward: tyTypeDesc, tyGenericInvocation, tyForward:
internalError(c.c.config, c.info, "assignment requested for type: " & typeToString(t)) internalError(c.graph.config, c.info, "assignment requested for type: " & typeToString(t))
of tyOrdinal, tyRange, tyInferred, of tyOrdinal, tyRange, tyInferred,
tyGenericInst, tyStatic, tyVar, tyLent, tyAlias, tySink: tyGenericInst, tyStatic, tyVar, tyLent, tyAlias, tySink:
liftBodyAux(c, lastSon(t), body, x, y) liftBodyAux(c, lastSon(t), body, x, y)
of tyOptAsRef: internalError(c.c.config, "liftBodyAux") of tyOptAsRef: internalError(c.graph.config, "liftBodyAux")
proc newProcType(info: TLineInfo; owner: PSym): PType = proc newProcType(info: TLineInfo; owner: PSym): PType =
result = newType(tyProc, owner) result = newType(tyProc, owner)
@ -287,54 +287,54 @@ proc addParam(procType: PType; param: PSym) =
addSon(procType.n, newSymNode(param)) addSon(procType.n, newSymNode(param))
rawAddSon(procType, param.typ) rawAddSon(procType, param.typ)
proc liftBodyDistinctType(c: PContext; typ: PType; kind: TTypeAttachedOp; info: TLineInfo): PSym = proc liftBodyDistinctType(g: ModuleGraph; typ: PType; kind: TTypeAttachedOp; info: TLineInfo): PSym =
assert typ.kind == tyDistinct assert typ.kind == tyDistinct
let baseType = typ[0] let baseType = typ[0]
case kind case kind
of attachedAsgn: of attachedAsgn:
if baseType.assignment == nil: if baseType.assignment == nil:
discard liftBody(c, baseType, kind, info) discard liftBody(g, baseType, kind, info)
typ.assignment = baseType.assignment typ.assignment = baseType.assignment
result = typ.assignment result = typ.assignment
of attachedSink: of attachedSink:
if baseType.sink == nil: if baseType.sink == nil:
discard liftBody(c, baseType, kind, info) discard liftBody(g, baseType, kind, info)
typ.sink = baseType.sink typ.sink = baseType.sink
result = typ.sink result = typ.sink
of attachedDeepCopy: of attachedDeepCopy:
if baseType.deepCopy == nil: if baseType.deepCopy == nil:
discard liftBody(c, baseType, kind, info) discard liftBody(g, baseType, kind, info)
typ.deepCopy = baseType.deepCopy typ.deepCopy = baseType.deepCopy
result = typ.deepCopy result = typ.deepCopy
of attachedDestructor: of attachedDestructor:
if baseType.destructor == nil: if baseType.destructor == nil:
discard liftBody(c, baseType, kind, info) discard liftBody(g, baseType, kind, info)
typ.destructor = baseType.destructor typ.destructor = baseType.destructor
result = typ.destructor result = typ.destructor
proc liftBody(c: PContext; typ: PType; kind: TTypeAttachedOp; proc liftBody(g: ModuleGraph; typ: PType; kind: TTypeAttachedOp;
info: TLineInfo): PSym = info: TLineInfo): PSym =
if typ.kind == tyDistinct: if typ.kind == tyDistinct:
return liftBodyDistinctType(c, typ, kind, info) return liftBodyDistinctType(g, typ, kind, info)
var a: TLiftCtx var a: TLiftCtx
a.info = info a.info = info
a.c = c a.graph = g
a.kind = kind a.kind = kind
let body = newNodeI(nkStmtList, info) let body = newNodeI(nkStmtList, info)
let procname = case kind let procname = case kind
of attachedAsgn: getIdent(c.cache, "=") of attachedAsgn: getIdent(g.cache, "=")
of attachedSink: getIdent(c.cache, "=sink") of attachedSink: getIdent(g.cache, "=sink")
of attachedDeepCopy: getIdent(c.cache, "=deepcopy") of attachedDeepCopy: getIdent(g.cache, "=deepcopy")
of attachedDestructor: getIdent(c.cache, "=destroy") of attachedDestructor: getIdent(g.cache, "=destroy")
result = newSym(skProc, procname, typ.owner, info) result = newSym(skProc, procname, typ.owner, info)
a.fn = result a.fn = result
a.asgnForType = typ a.asgnForType = typ
let dest = newSym(skParam, getIdent(c.cache, "dest"), result, info) let dest = newSym(skParam, getIdent(g.cache, "dest"), result, info)
let src = newSym(skParam, getIdent(c.cache, "src"), result, info) let src = newSym(skParam, getIdent(g.cache, "src"), result, info)
dest.typ = makeVarType(c, typ) dest.typ = makeVarType(typ.owner, typ)
src.typ = typ src.typ = typ
result.typ = newProcType(info, typ.owner) result.typ = newProcType(info, typ.owner)
@ -345,7 +345,7 @@ proc liftBody(c: PContext; typ: PType; kind: TTypeAttachedOp;
liftBodyAux(a, typ, body, newSymNode(dest).newDeref, newSymNode(src)) liftBodyAux(a, typ, body, newSymNode(dest).newDeref, newSymNode(src))
# recursion is handled explicitly, do not register the type based operation # recursion is handled explicitly, do not register the type based operation
# before 'liftBodyAux': # before 'liftBodyAux':
if c.config.selectedGC == gcDestructors and if g.config.selectedGC == gcDestructors and
typ.kind in {tySequence, tyString} and body.len == 0: typ.kind in {tySequence, tyString} and body.len == 0:
discard "do not cache it yet" discard "do not cache it yet"
else: else:
@ -364,17 +364,17 @@ proc liftBody(c: PContext; typ: PType; kind: TTypeAttachedOp;
incl result.flags, sfFromGeneric incl result.flags, sfFromGeneric
proc getAsgnOrLiftBody(c: PContext; typ: PType; info: TLineInfo): PSym = proc getAsgnOrLiftBody(g: ModuleGraph; typ: PType; info: TLineInfo): PSym =
let t = typ.skipTypes({tyGenericInst, tyVar, tyLent, tyAlias, tySink}) let t = typ.skipTypes({tyGenericInst, tyVar, tyLent, tyAlias, tySink})
result = t.assignment result = t.assignment
if result.isNil: if result.isNil:
result = liftBody(c, t, attachedAsgn, info) result = liftBody(g, t, attachedAsgn, info)
proc overloadedAsgn(c: PContext; dest, src: PNode): PNode = proc overloadedAsgn(g: ModuleGraph; dest, src: PNode): PNode =
let a = getAsgnOrLiftBody(c, dest.typ, dest.info) let a = getAsgnOrLiftBody(g, dest.typ, dest.info)
result = newAsgnCall(c, a, dest, src) result = newAsgnCall(g, a, dest, src)
proc liftTypeBoundOps*(c: PContext; typ: PType; info: TLineInfo) = proc liftTypeBoundOps*(g: ModuleGraph; typ: PType; info: TLineInfo) =
## In the semantic pass this is called in strategic places ## In the semantic pass this is called in strategic places
## to ensure we lift assignment, destructors and moves properly. ## to ensure we lift assignment, destructors and moves properly.
## The later 'destroyer' pass depends on it. ## The later 'destroyer' pass depends on it.
@ -386,11 +386,11 @@ proc liftTypeBoundOps*(c: PContext; typ: PType; info: TLineInfo) =
let typ = typ.skipTypes({tyGenericInst, tyAlias}) let typ = typ.skipTypes({tyGenericInst, tyAlias})
# we generate the destructor first so that other operators can depend on it: # we generate the destructor first so that other operators can depend on it:
if typ.destructor == nil: if typ.destructor == nil:
liftBody(c, typ, attachedDestructor, info) liftBody(g, typ, attachedDestructor, info)
if typ.assignment == nil: if typ.assignment == nil:
liftBody(c, typ, attachedAsgn, info) liftBody(g, typ, attachedAsgn, info)
if typ.sink == nil: if typ.sink == nil:
liftBody(c, typ, attachedSink, info) liftBody(g, typ, attachedSink, info)
#proc patchResolvedTypeBoundOp*(c: PContext; n: PNode): PNode = #proc patchResolvedTypeBoundOp*(g: ModuleGraph; n: PNode): PNode =
# if n.kind == nkCall and # if n.kind == nkCall and

View file

@ -286,6 +286,13 @@ proc makeVarType*(c: PContext, baseType: PType; kind = tyVar): PType =
result = newTypeS(kind, c) result = newTypeS(kind, c)
addSonSkipIntLit(result, baseType) addSonSkipIntLit(result, baseType)
proc makeVarType*(owner: PSym, baseType: PType; kind = tyVar): PType =
if baseType.kind == kind:
result = baseType
else:
result = newType(kind, owner)
addSonSkipIntLit(result, baseType)
proc makeTypeDesc*(c: PContext, typ: PType): PType = proc makeTypeDesc*(c: PContext, typ: PType): PType =
if typ.kind == tyTypeDesc: if typ.kind == tyTypeDesc:
result = typ result = typ

View file

@ -802,7 +802,7 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
result = magicsAfterOverloadResolution(c, result, flags) result = magicsAfterOverloadResolution(c, result, flags)
if result.typ != nil and if result.typ != nil and
not (result.typ.kind == tySequence and result.typ.sons[0].kind == tyEmpty): not (result.typ.kind == tySequence and result.typ.sons[0].kind == tyEmpty):
liftTypeBoundOps(c, result.typ, n.info) liftTypeBoundOps(c.graph, result.typ, n.info)
#result = patchResolvedTypeBoundOp(c, result) #result = patchResolvedTypeBoundOp(c, result)
if c.matchedConcept == nil: if c.matchedConcept == nil:
result = evalAtCompileTime(c, result) result = evalAtCompileTime(c, result)
@ -1592,7 +1592,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
typeMismatch(c.config, n.info, lhs.typ, rhsTyp) typeMismatch(c.config, n.info, lhs.typ, rhsTyp)
n.sons[1] = fitNode(c, le, rhs, goodLineInfo(n[1])) n.sons[1] = fitNode(c, le, rhs, goodLineInfo(n[1]))
liftTypeBoundOps(c, lhs.typ, lhs.info) liftTypeBoundOps(c.graph, lhs.typ, lhs.info)
#liftTypeBoundOps(c, n.sons[0].typ, n.sons[0].info) #liftTypeBoundOps(c, n.sons[0].typ, n.sons[0].info)
fixAbstractType(c, n) fixAbstractType(c, n)

View file

@ -476,7 +476,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
# this can only happen for errornous var statements: # this can only happen for errornous var statements:
if typ == nil: continue if typ == nil: continue
typeAllowedCheck(c.config, a.info, typ, symkind, if c.matchedConcept != nil: {taConcept} else: {}) typeAllowedCheck(c.config, a.info, typ, symkind, if c.matchedConcept != nil: {taConcept} else: {})
liftTypeBoundOps(c, typ, a.info) liftTypeBoundOps(c.graph, typ, a.info)
var tup = skipTypes(typ, {tyGenericInst, tyAlias, tySink}) var tup = skipTypes(typ, {tyGenericInst, tyAlias, tySink})
if a.kind == nkVarTuple: if a.kind == nkVarTuple:
if tup.kind != tyTuple: if tup.kind != tyTuple:
@ -1479,7 +1479,8 @@ proc canonType(c: PContext, t: PType): PType =
result = t result = t
proc semOverride(c: PContext, s: PSym, n: PNode) = proc semOverride(c: PContext, s: PSym, n: PNode) =
case s.name.s.normalize let name = s.name.s.normalize
case name
of "=destroy": of "=destroy":
let t = s.typ let t = s.typ
var noError = false var noError = false
@ -1498,6 +1499,9 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
localError(c.config, n.info, errGenerated, localError(c.config, n.info, errGenerated,
"cannot bind another '" & s.name.s & "' to: " & typeToString(obj)) "cannot bind another '" & s.name.s & "' to: " & typeToString(obj))
noError = true noError = true
if obj.owner.getModule != s.getModule:
localError(c.config, n.info, errGenerated,
"type bound operation `=destroy` can be defined only in the same module with its type (" & obj.typeToString() & ")")
if not noError and sfSystemModule notin s.owner.flags: if not noError and sfSystemModule notin s.owner.flags:
localError(c.config, n.info, errGenerated, localError(c.config, n.info, errGenerated,
"signature for '" & s.name.s & "' must be proc[T: object](x: var T)") "signature for '" & s.name.s & "' must be proc[T: object](x: var T)")
@ -1521,6 +1525,11 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
else: else:
localError(c.config, n.info, errGenerated, localError(c.config, n.info, errGenerated,
"cannot bind 'deepCopy' to: " & typeToString(t)) "cannot bind 'deepCopy' to: " & typeToString(t))
if t.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 (" & t.typeToString() & ")")
else: else:
localError(c.config, n.info, errGenerated, localError(c.config, n.info, errGenerated,
"signature for 'deepCopy' must be proc[T: ptr|ref](x: T): T") "signature for 'deepCopy' must be proc[T: ptr|ref](x: T): T")
@ -1551,6 +1560,10 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
else: else:
localError(c.config, n.info, errGenerated, localError(c.config, n.info, errGenerated,
"cannot bind another '" & s.name.s & "' to: " & typeToString(obj)) "cannot bind another '" & s.name.s & "' to: " & typeToString(obj))
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 return
if sfSystemModule notin s.owner.flags: if sfSystemModule notin s.owner.flags:
localError(c.config, n.info, errGenerated, localError(c.config, n.info, errGenerated,

View file

@ -0,0 +1,3 @@
type
MyTestObject*[T] = object
p: ptr T

View file

@ -0,0 +1,20 @@
discard """
joinable: false
cmd: "nim check $file"
errormsg: "type bound operation `=deepcopy` can be defined only in the same module with its type (MyTestObject)"
nimout: '''
terror_module.nim(14, 1) Error: type bound operation `=destroy` can be defined only in the same module with its type (MyTestObject)
terror_module.nim(16, 1) Error: type bound operation `=sink` can be defined only in the same module with its type (MyTestObject)
terror_module.nim(18, 1) Error: type bound operation `=` can be defined only in the same module with its type (MyTestObject)
terror_module.nim(20, 1) Error: type bound operation `=deepcopy` can be defined only in the same module with its type (MyTestObject)
'''
"""
import helper
proc `=destroy`[T](x: var MyTestObject[T]) = discard
proc `=sink`[T](x: var MyTestObject[T], y:MyTestObject[T]) = discard
proc `=`[T](x: var MyTestObject[T], y: MyTestObject[T]) = discard
proc `=deepcopy`[T](x: ptr MyTestObject[T]): ptr MyTestObject[T] = discard