diff options
author | Araq <rumpf_a@web.de> | 2019-04-18 00:53:02 +0200 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2019-04-18 00:53:02 +0200 |
commit | 750f50b6c04e275207ec5d1aace478369e1acf9e (patch) | |
tree | 3b429bf844f776513adf1d48dceab1ac21f27d69 /compiler | |
parent | fb3681b42543639e67a5b1d8dd60412e354b7a46 (diff) | |
download | Nim-750f50b6c04e275207ec5d1aace478369e1acf9e.tar.gz |
destructors: internal compiler refactoring
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ast.nim | 24 | ||||
-rw-r--r-- | compiler/ccgtypes.nim | 8 | ||||
-rw-r--r-- | compiler/injectdestructors.nim | 34 | ||||
-rw-r--r-- | compiler/liftdestructors.nim | 69 | ||||
-rw-r--r-- | compiler/semdata.nim | 6 | ||||
-rw-r--r-- | compiler/semstmts.nim | 14 | ||||
-rw-r--r-- | compiler/semtypinst.nim | 25 |
7 files changed, 77 insertions, 103 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 75e67ac67..c98b2a576 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -877,6 +877,13 @@ type TTypeSeq* = seq[PType] TLockLevel* = distinct int16 + + TTypeAttachedOp* = enum ## as usual, order is important here + attachedDestructor, + attachedAsgn, + attachedSink, + attachedDeepCopy + TType* {.acyclic.} = object of TIdObj # \ # types are identical iff they have the # same id; there may be multiple copies of a type @@ -897,12 +904,7 @@ type owner*: PSym # the 'owner' of the type sym*: PSym # types have the sym associated with them # it is used for converting types to strings - destructor*: PSym # destructor. warning: nil here may not necessary - # mean that there is no destructor. - # see instantiateDestructor in semdestruct.nim - deepCopy*: PSym # overriden 'deepCopy' operation - assignment*: PSym # overriden '=' operation - sink*: PSym # overriden '=sink' operation + attachedOps*: array[TTypeAttachedOp, PSym] # destructors, etc. methods*: seq[(int,PSym)] # attached methods size*: BiggestInt # the size of the type in bytes # -1 means that the size is unkwown @@ -1275,6 +1277,7 @@ const UnspecifiedLockLevel* = TLockLevel(-1'i16) MaxLockLevel* = 1000'i16 UnknownLockLevel* = TLockLevel(1001'i16) + AttachedOpToStr*: array[TTypeAttachedOp, string] = ["=destroy", "=", "=sink", "=deepcopy"] proc `$`*(x: TLockLevel): string = if x.ord == UnspecifiedLockLevel.ord: result = "<unspecified>" @@ -1341,10 +1344,7 @@ proc assignType*(dest, src: PType) = dest.n = src.n dest.size = src.size dest.align = src.align - dest.destructor = src.destructor - dest.deepCopy = src.deepCopy - dest.sink = src.sink - dest.assignment = src.assignment + dest.attachedOps = src.attachedOps dest.lockLevel = src.lockLevel # this fixes 'type TLock = TSysLock': if src.sym != nil: @@ -1831,3 +1831,7 @@ proc addParam*(procType: PType; param: PSym) = param.position = procType.len-1 addSon(procType.n, newSymNode(param)) rawAddSon(procType, param.typ) + +template destructor*(t: PType): PSym = t.attachedOps[attachedDestructor] +template assignment*(t: PType): PSym = t.attachedOps[attachedAsgn] +template asink*(t: PType): PSym = t.attachedOps[attachedSink] diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index fb0f7dbf4..7d5a761bc 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -1346,10 +1346,10 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope = # results are not deterministic! genTupleInfo(m, t, origType, result, info) else: internalError(m.config, "genTypeInfo(" & $t.kind & ')') - if t.deepCopy != nil: - genDeepCopyProc(m, t.deepCopy, result) - elif origType.deepCopy != nil: - genDeepCopyProc(m, origType.deepCopy, result) + if t.attachedOps[attachedDeepCopy] != nil: + genDeepCopyProc(m, t.attachedOps[attachedDeepCopy], result) + elif origType.attachedOps[attachedDeepCopy] != nil: + genDeepCopyProc(m, origType.attachedOps[attachedDeepCopy], result) result = prefixTI.rope & result & ")".rope proc genTypeSection(m: BModule, n: PNode) = diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 7901ed4dc..1f225aee4 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -136,7 +136,7 @@ to do it. import intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees, strutils, options, dfa, lowerings, tables, modulegraphs, msgs, - lineinfos, parampatterns + lineinfos, parampatterns, sighashes const InterestingSyms = {skVar, skResult, skLet, skForVar, skTemp} @@ -314,24 +314,34 @@ proc makePtrType(c: Con, baseType: PType): PType = result = newType(tyPtr, c.owner) addSonSkipIntLit(result, baseType) -template genOp(opr, opname, ri) = - let op = opr +proc genOp(c: Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode = + var op = t.attachedOps[kind] + + when false: + if op == nil: + # give up and find the canonical type instead: + let h = sighashes.hashType(t, {CoType, CoConsiderOwned}) + let canon = c.graph.canonTypes.getOrDefault(h) + if canon != nil: + op = canon.attachedOps[kind] + if op == nil: - globalError(c.graph.config, dest.info, "internal error: '" & opname & + globalError(c.graph.config, dest.info, "internal error: '" & AttachedOpToStr[kind] & "' operator not found for type " & typeToString(t)) elif op.ast[genericParamsPos].kind != nkEmpty: - globalError(c.graph.config, dest.info, "internal error: '" & opname & + globalError(c.graph.config, dest.info, "internal error: '" & AttachedOpToStr[kind] & "' operator is generic") - if sfError in op.flags: checkForErrorPragma(c, t, ri, opname) + if sfError in op.flags: checkForErrorPragma(c, t, ri, AttachedOpToStr[kind]) let addrExp = newNodeIT(nkHiddenAddr, dest.info, makePtrType(c, dest.typ)) addrExp.add(dest) result = newTree(nkCall, newSymNode(op), addrExp) proc genSink(c: Con; t: PType; dest, ri: PNode): PNode = let t = t.skipTypes({tyGenericInst, tyAlias, tySink}) - let op = if t.sink != nil: t.sink else: t.assignment - if op != nil: - genOp(op, "=sink", ri) + let k = if t.attachedOps[attachedSink] != nil: attachedSink + else: attachedAsgn + if t.attachedOps[k] != nil: + result = genOp(c, t, k, dest, ri) else: # in rare cases only =destroy exists but no sink or assignment # (see Pony object in tmove_objconstr.nim) @@ -342,15 +352,15 @@ proc genCopy(c: Con; t: PType; dest, ri: PNode): PNode = if tfHasOwned in t.flags: checkForErrorPragma(c, t, ri, "=") let t = t.skipTypes({tyGenericInst, tyAlias, tySink}) - genOp(t.assignment, "=", ri) + result = genOp(c, t, attachedAsgn, dest, ri) proc genCopyNoCheck(c: Con; t: PType; dest, ri: PNode): PNode = let t = t.skipTypes({tyGenericInst, tyAlias, tySink}) - genOp(t.assignment, "=", ri) + result = genOp(c, t, attachedAsgn, dest, ri) proc genDestroy(c: Con; t: PType; dest: PNode): PNode = let t = t.skipTypes({tyGenericInst, tyAlias, tySink}) - genOp(t.destructor, "=destroy", nil) + result = genOp(c, t, attachedDestructor, dest, nil) proc addTopVar(c: var Con; v: PNode) = c.topLevelVars.add newTree(nkIdentDefs, v, c.emptyNode, c.emptyNode) diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 310263875..5fbf86071 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -197,7 +197,7 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool = assert t.typeInst != nil # patch generic destructor: op = c.c.instTypeBoundOp(c.c, op, t.typeInst, c.info, attachedAsgn, 1) - t.destructor = op + t.attachedOps[attachedDestructor] = op markUsed(c.graph.config, c.info, op, c.graph.usageSym) onUse(c.info, op) @@ -207,9 +207,9 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool = of attachedAsgn: result = considerAsgnOrSink(c, t, body, x, y, t.assignment) of attachedSink: - result = considerAsgnOrSink(c, t, body, x, y, t.sink) + result = considerAsgnOrSink(c, t, body, x, y, t.asink) of attachedDeepCopy: - let op = t.deepCopy + let op = t.attachedOps[attachedDeepCopy] if op != nil: markUsed(c.graph.config, c.info, op, c.graph.usageSym) onUse(c.info, op) @@ -323,8 +323,8 @@ proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add moveCall # alternatively we could do this: when false: - doAssert t.sink != nil - body.add newAsgnCall(c.graph, t.sink, x, y) + doAssert t.asink != nil + body.add newAsgnCall(c.graph, t.asink, x, y) of attachedDestructor: doAssert t.destructor != nil body.add destructorCall(c.graph, t.destructor, x) @@ -502,27 +502,10 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) = proc produceSymDistinctType(c: PContext; typ: PType; kind: TTypeAttachedOp; info: TLineInfo): PSym = assert typ.kind == tyDistinct let baseType = typ[0] - case kind - of attachedAsgn: - if baseType.assignment == nil: - discard produceSym(c, baseType, kind, info) - typ.assignment = baseType.assignment - result = typ.assignment - of attachedSink: - if baseType.sink == nil: - discard produceSym(c, baseType, kind, info) - typ.sink = baseType.sink - result = typ.sink - of attachedDeepCopy: - if baseType.deepCopy == nil: - discard produceSym(c, baseType, kind, info) - typ.deepCopy = baseType.deepCopy - result = typ.deepCopy - of attachedDestructor: - if baseType.destructor == nil: - discard produceSym(c, baseType, kind, info) - typ.destructor = baseType.destructor - result = typ.destructor + if baseType.attachedOps[kind] == nil: + discard produceSym(c, baseType, kind, info) + typ.attachedOps[kind] = baseType.attachedOps[kind] + result = typ.attachedOps[kind] proc produceSym(c: PContext; typ: PType; kind: TTypeAttachedOp; info: TLineInfo): PSym = @@ -536,11 +519,7 @@ proc produceSym(c: PContext; typ: PType; kind: TTypeAttachedOp; a.c = c let g = c.graph let body = newNodeI(nkStmtList, info) - let procname = case kind - of attachedAsgn: getIdent(g.cache, "=") - of attachedSink: getIdent(g.cache, "=sink") - of attachedDeepCopy: getIdent(g.cache, "=deepcopy") - of attachedDestructor: getIdent(g.cache, "=destroy") + let procname = getIdent(g.cache, AttachedOpToStr[kind]) result = newSym(skProc, procname, typ.owner, info) a.fn = result @@ -557,11 +536,7 @@ proc produceSym(c: PContext; typ: PType; kind: TTypeAttachedOp; result.typ.addParam src # register this operation already: - case kind - of attachedAsgn: typ.assignment = result - of attachedSink: typ.sink = result - of attachedDeepCopy: typ.deepCopy = result - of attachedDestructor: typ.destructor = result + typ.attachedOps[kind] = result var tk: TTypeKind if optNimV2 in c.graph.config.globalOptions: @@ -636,23 +611,15 @@ proc createTypeBoundOps(c: PContext; orig: PType; info: TLineInfo) = # 5. We have a (custom) generic destructor. let typ = canon.skipTypes({tyGenericInst, tyAlias}) # we generate the destructor first so that other operators can depend on it: - if typ.destructor == nil: - discard produceSym(c, typ, attachedDestructor, info) - else: - inst(typ.destructor, typ) - if typ.assignment == nil: - discard produceSym(c, typ, attachedAsgn, info) - else: - inst(typ.assignment, typ) - if typ.sink == nil: - discard produceSym(c, typ, attachedSink, info) - else: - inst(typ.sink, typ) + for k in attachedDestructor..attachedSink: + if typ.attachedOps[k] == nil: + discard produceSym(c, typ, k, info) + else: + inst(typ.attachedOps[k], typ) if overwrite: - orig.destructor = typ.destructor - orig.assignment = typ.assignment - orig.sink = typ.sink + for k in attachedDestructor..attachedSink: + orig.attachedOps[k] = typ.attachedOps[k] if not isTrival(orig.destructor): #or not isTrival(orig.assignment) or diff --git a/compiler/semdata.nim b/compiler/semdata.nim index f7a7f20dc..4b269dd4a 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -72,12 +72,6 @@ type TExprFlags* = set[TExprFlag] - TTypeAttachedOp* = enum - attachedAsgn, - attachedSink, - attachedDeepCopy, - attachedDestructor - PContext* = ref TContext TContext* = object of TPassContext # a context represents a module enforceVoidContext*: PType diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 067b3bc9c..4054fd71a 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1568,7 +1568,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) = if obj.kind in {tyObject, tyDistinct, tySequence, tyString}: obj = canonType(c, obj) if obj.destructor.isNil: - obj.destructor = s + obj.attachedOps[attachedDestructor] = s else: prevDestructor(c, obj.destructor, obj, n.info) noError = true @@ -1592,7 +1592,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) = elif t.kind == tyGenericInvocation: t = t.sons[0] else: break if t.kind in {tyObject, tyDistinct, tyEnum, tySequence, tyString}: - if t.deepCopy.isNil: t.deepCopy = s + if t.attachedOps[attachedDeepCopy].isNil: t.attachedOps[attachedDeepCopy] = s else: localError(c.config, n.info, errGenerated, "cannot bind another 'deepCopy' to: " & typeToString(t)) @@ -1631,11 +1631,11 @@ proc semOverride(c: PContext, s: PSym, n: PNode) = # attach these ops to the canonical tySequence obj = canonType(c, obj) #echo "ATTACHING TO ", obj.id, " ", s.name.s, " ", cast[int](obj) - let opr = if s.name.s == "=": addr(obj.assignment) else: addr(obj.sink) - if opr[].isNil: - opr[] = s + let k = if name == "=": attachedAsgn else: attachedSink + if obj.attachedOps[k].isNil: + obj.attachedOps[k] = s else: - prevDestructor(c, opr[], obj, n.info) + prevDestructor(c, obj.attachedOps[k], 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() & ")") @@ -1828,7 +1828,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, if sfOverriden in s.flags or s.name.s[0] == '=': semOverride(c, s, n) if s.name.s[0] in {'.', '('}: - if s.name.s in [".", ".()", ".="] and {destructor, dotOperators} * c.features == {}: + if s.name.s in [".", ".()", ".="] and {Feature.destructor, dotOperators} * c.features == {}: localError(c.config, n.info, "the overloaded " & s.name.s & " operator has to be enabled with {.experimental: \"dotOperators\".}") elif s.name.s == "()" and callOperator notin c.features: diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 931a54f96..5d2c4203c 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -380,13 +380,13 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = if newbody.isGenericAlias: newbody = newbody.skipGenericAlias rawAddSon(result, newbody) checkPartialConstructedType(cl.c.config, cl.info, newbody) - let dc = newbody.deepCopy + let dc = newbody.attachedOps[attachedDeepCopy] if not cl.allowMetaTypes: - if dc != nil and sfFromGeneric notin newbody.deepCopy.flags: + if dc != nil and sfFromGeneric notin newbody.attachedOps[attachedDeepCopy].flags: # 'deepCopy' needs to be instantiated for # generics *when the type is constructed*: - newbody.deepCopy = cl.c.instTypeBoundOp(cl.c, dc, result, cl.info, - attachedDeepCopy, 1) + newbody.attachedOps[attachedDeepCopy] = cl.c.instTypeBoundOp(cl.c, dc, result, cl.info, + attachedDeepCopy, 1) if bodyIsNew and newbody.typeInst == nil: #doassert newbody.typeInst == nil newbody.typeInst = result @@ -592,7 +592,8 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = skipIntLiteralParams(result) of tySequence: - if cl.isReturnType and cl.c.config.selectedGc == gcDestructors and result.destructor.isNil and + if cl.isReturnType and cl.c.config.selectedGc == gcDestructors and + result.attachedOps[attachedDestructor].isNil and result[0].kind != tyEmpty and optNimV2 notin cl.c.config.globalOptions: let s = cl.c.graph.sysTypes[tySequence] var old = copyType(s, s.owner, keepId=false) @@ -601,9 +602,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = old.n = nil old.flags = {tfHasAsgn} old.addSonSkipIntLit result[0] - result.destructor = old.destructor - result.assignment = old.assignment - result.sink = old.sink + result.attachedOps = old.attachedOps cl.c.typesWithOps.add((result, old)) else: discard @@ -619,19 +618,19 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = result.n = replaceObjBranches(cl, result.n) template typeBound(c, newty, oldty, field, info) = - let opr = newty.field + let opr = newty.attachedOps[field] if opr != nil and sfFromGeneric notin opr.flags: # '=' needs to be instantiated for generics when the type is constructed: #echo "DESTROY: instantiating ", astToStr(field), " for ", typeToString(oldty) - newty.field = c.instTypeBoundOp(c, opr, oldty, info, attachedAsgn, 1) + newty.attachedOps[field] = c.instTypeBoundOp(c, opr, oldty, info, attachedAsgn, 1) proc instAllTypeBoundOp*(c: PContext, info: TLineInfo) = var i = 0 while i < c.typesWithOps.len: let (newty, oldty) = c.typesWithOps[i] - typeBound(c, newty, oldty, destructor, info) - typeBound(c, newty, oldty, sink, info) - typeBound(c, newty, oldty, assignment, info) + typeBound(c, newty, oldty, attachedDestructor, info) + typeBound(c, newty, oldty, attachedSink, info) + typeBound(c, newty, oldty, attachedAsgn, info) inc i setLen(c.typesWithOps, 0) |