diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ccgcalls.nim | 21 | ||||
-rw-r--r-- | compiler/ccgexprs.nim | 102 | ||||
-rw-r--r-- | compiler/ccgstmts.nim | 2 | ||||
-rw-r--r-- | compiler/ccgtypes.nim | 111 | ||||
-rw-r--r-- | compiler/cgen.nim | 56 | ||||
-rw-r--r-- | compiler/options.nim | 3 | ||||
-rw-r--r-- | compiler/renderer.nim | 9 | ||||
-rw-r--r-- | compiler/sem.nim | 10 | ||||
-rw-r--r-- | compiler/semexprs.nim | 21 | ||||
-rw-r--r-- | compiler/sempass2.nim | 7 | ||||
-rw-r--r-- | compiler/semstmts.nim | 4 | ||||
-rw-r--r-- | compiler/transf.nim | 4 | ||||
-rw-r--r-- | compiler/trees.nim | 2 | ||||
-rw-r--r-- | compiler/typeallowed.nim | 228 | ||||
-rw-r--r-- | compiler/types.nim | 170 | ||||
-rw-r--r-- | compiler/varpartitions.nim | 36 |
16 files changed, 475 insertions, 311 deletions
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 5f99f357d..6d254ca6f 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -141,6 +141,13 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, proc genBoundsCheck(p: BProc; arr, a, b: TLoc) +proc reifiedOpenArray(n: PNode): bool {.inline.} = + let x = trees.getRoot(n) + if x != nil and x.kind == skParam: + result = false + else: + result = true + proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope = var a: TLoc @@ -174,7 +181,12 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope = else: result = "($5*)($1)+(($2)-($4)), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), intLiteral(first), dest] - of tyOpenArray, tyVarargs, tyUncheckedArray, tyCString: + of tyOpenArray, tyVarargs: + if reifiedOpenArray(q[1]): + result = "($4*)($1.d)+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dest] + else: + result = "($4*)($1)+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dest] + of tyUncheckedArray, tyCString: result = "($4*)($1)+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dest] of tyString, tySequence: let atyp = skipTypes(a.t, abstractInst) @@ -188,10 +200,13 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope = else: internalError(p.config, "openArrayLoc: " & typeToString(a.t)) else: - initLocExpr(p, n, a) + initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n, a) case skipTypes(a.t, abstractVar).kind of tyOpenArray, tyVarargs: - result = "$1, $1Len_0" % [rdLoc(a)] + if reifiedOpenArray(n): + result = "$1.d, $1.l" % [rdLoc(a)] + else: + result = "$1, $1Len_0" % [rdLoc(a)] of tyString, tySequence: let ntyp = skipTypes(n.typ, abstractInst) if formalType.skipTypes(abstractInst).kind in {tyVar} and ntyp.kind == tyString and diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index dd4774b2a..8f45452bf 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -271,6 +271,34 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = linefmt(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n", [addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfo(p.module, dest.t, dest.lode.info)]) +proc genOpenArrayConv(p: BProc; d: TLoc; a: TLoc) = + assert d.k != locNone + # getTemp(p, d.t, d) + + case a.t.skipTypes(abstractVar).kind + of tyOpenArray, tyVarargs: + if reifiedOpenArray(a.lode): + linefmt(p, cpsStmts, "$1.d = $2.d; $1.l = $2.l;$n", + [rdLoc(d), a.rdLoc]) + else: + linefmt(p, cpsStmts, "$1.d = $2; $1.l = $2Len_0;$n", + [rdLoc(d), a.rdLoc]) + of tySequence: + linefmt(p, cpsStmts, "$1.d = $2$3; $1.l = $4;$n", + [rdLoc(d), a.rdLoc, dataField(p), lenExpr(p, a)]) + of tyArray: + linefmt(p, cpsStmts, "$1.d = $2; $1.l = $3;$n", + [rdLoc(d), rdLoc(a), rope(lengthOrd(p.config, a.t))]) + of tyString: + let etyp = skipTypes(a.t, abstractInst) + if etyp.kind in {tyVar} and optSeqDestructors in p.config.globalOptions: + linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)]) + + linefmt(p, cpsStmts, "$1.d = $2$3; $1.l = $4;$n", + [rdLoc(d), a.rdLoc, dataField(p), lenExpr(p, a)]) + else: + internalError(p.config, a.lode.info, "cannot handle " & $a.t.kind) + proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = # This function replaces all other methods for generating # the assignment operation in C. @@ -349,7 +377,9 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = of tyOpenArray, tyVarargs: # open arrays are always on the stack - really? What if a sequence is # passed to an open array? - if containsGarbageCollectedRef(dest.t): + if reifiedOpenArray(dest.lode): + genOpenArrayConv(p, dest, src) + elif containsGarbageCollectedRef(dest.t): linefmt(p, cpsStmts, # XXX: is this correct for arrays? "#genericAssignOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n", [addrLoc(p.config, dest), addrLoc(p.config, src), @@ -361,7 +391,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) of tySet: - if mapType(p.config, ty) == ctArray: + if mapSetType(p.config, ty) == ctArray: linefmt(p, cpsStmts, "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, $3);$n", [rdLoc(dest), rdLoc(src), getSize(p.config, dest.t)]) else: @@ -406,7 +436,7 @@ proc genDeepCopy(p: BProc; dest, src: TLoc) = [addrLoc(p.config, dest), addrLocOrTemp(src), genTypeInfo(p.module, dest.t, dest.lode.info)]) of tySet: - if mapType(p.config, ty) == ctArray: + if mapSetType(p.config, ty) == ctArray: linefmt(p, cpsStmts, "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, $3);$n", [rdLoc(dest), rdLoc(src), getSize(p.config, dest.t)]) else: @@ -679,7 +709,7 @@ proc isCppRef(p: BProc; typ: PType): bool {.inline.} = tfVarIsPtr notin skipTypes(typ, abstractInstOwned).flags proc genDeref(p: BProc, e: PNode, d: var TLoc) = - let mt = mapType(p.config, e[0].typ) + let mt = mapType(p.config, e[0].typ, mapTypeChooser(e[0])) if mt in {ctArray, ctPtrToArray} and lfEnforceDeref notin d.flags: # XXX the amount of hacks for C's arrays is incredible, maybe we should # simply wrap them in a struct? --> Losing auto vectorization then? @@ -747,7 +777,7 @@ proc genAddr(p: BProc, e: PNode, d: var TLoc) = initLocExpr(p, e[0], a) putIntoDest(p, d, e, "&" & a.r, a.storage) #Message(e.info, warnUser, "HERE NEW &") - elif mapType(p.config, e[0].typ) == ctArray or isCppRef(p, e.typ): + elif mapType(p.config, e[0].typ, mapTypeChooser(e[0])) == ctArray or isCppRef(p, e.typ): expr(p, e[0], d) else: var a: TLoc @@ -905,10 +935,16 @@ proc genBoundsCheck(p: BProc; arr, a, b: TLoc) = let ty = skipTypes(arr.t, abstractVarRange) case ty.kind of tyOpenArray, tyVarargs: - linefmt(p, cpsStmts, - "if ($2-$1 != -1 && " & - "((NU)($1) >= (NU)($3Len_0) || (NU)($2) >= (NU)($3Len_0))){ #raiseIndexError(); $4}$n", - [rdLoc(a), rdLoc(b), rdLoc(arr), raiseInstr(p)]) + if reifiedOpenArray(arr.lode): + linefmt(p, cpsStmts, + "if ($2-$1 != -1 && " & + "((NU)($1) >= (NU)($3.l) || (NU)($2) >= (NU)($3.l))){ #raiseIndexError(); $4}$n", + [rdLoc(a), rdLoc(b), rdLoc(arr), raiseInstr(p)]) + else: + linefmt(p, cpsStmts, + "if ($2-$1 != -1 && " & + "((NU)($1) >= (NU)($3Len_0) || (NU)($2) >= (NU)($3Len_0))){ #raiseIndexError(); $4}$n", + [rdLoc(a), rdLoc(b), rdLoc(arr), raiseInstr(p)]) of tyArray: let first = intLiteral(firstOrd(p.config, ty)) linefmt(p, cpsStmts, @@ -925,13 +961,22 @@ proc genBoundsCheck(p: BProc; arr, a, b: TLoc) = proc genOpenArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) = var a, b: TLoc initLocExpr(p, x, a) - initLocExpr(p, y, b) # emit range check: - if optBoundsCheck in p.options: - linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len_0)){ #raiseIndexError2($1,$2Len_0-1); $3}$n", - [rdLoc(b), rdLoc(a), raiseInstr(p)]) # BUGFIX: ``>=`` and not ``>``! - inheritLocation(d, a) - putIntoDest(p, d, n, - ropecg(p.module, "$1[$2]", [rdLoc(a), rdCharLoc(b)]), a.storage) + initLocExpr(p, y, b) + if not reifiedOpenArray(x): + # emit range check: + if optBoundsCheck in p.options: + linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len_0)){ #raiseIndexError2($1,$2Len_0-1); $3}$n", + [rdLoc(b), rdLoc(a), raiseInstr(p)]) # BUGFIX: ``>=`` and not ``>``! + inheritLocation(d, a) + putIntoDest(p, d, n, + ropecg(p.module, "$1[$2]", [rdLoc(a), rdCharLoc(b)]), a.storage) + else: + if optBoundsCheck in p.options: + linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2.l)){ #raiseIndexError2($1,$2.l-1); $3}$n", + [rdLoc(b), rdLoc(a), raiseInstr(p)]) # BUGFIX: ``>=`` and not ``>``! + inheritLocation(d, a) + putIntoDest(p, d, n, + ropecg(p.module, "$1.d[$2]", [rdLoc(a), rdCharLoc(b)]), a.storage) proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) = var a, b: TLoc @@ -1675,8 +1720,12 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) = else: putIntoDest(p, d, e, ropecg(p.module, "($2)-($1)+1", [rdLoc(b), rdLoc(c)])) else: - if op == mHigh: unaryExpr(p, e, d, "($1Len_0-1)") - else: unaryExpr(p, e, d, "$1Len_0") + if not reifiedOpenArray(a): + if op == mHigh: unaryExpr(p, e, d, "($1Len_0-1)") + else: unaryExpr(p, e, d, "$1Len_0") + else: + if op == mHigh: unaryExpr(p, e, d, "($1.l-1)") + else: unaryExpr(p, e, d, "$1.l") of tyCString: if op == mHigh: unaryExpr(p, e, d, "($1 ? (#nimCStrLen($1)-1) : -1)") else: unaryExpr(p, e, d, "($1 ? #nimCStrLen($1) : 0)") @@ -2253,13 +2302,12 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = putIntoDest(p, d, e, "((NI)NIM_ALIGNOF($1))" % [getTypeDesc(p.module, t)]) of mOffsetOf: var dotExpr: PNode - block findDotExpr: - if e[1].kind == nkDotExpr: - dotExpr = e[1] - elif e[1].kind == nkCheckedFieldExpr: - dotExpr = e[1][0] - else: - internalError(p.config, e.info, "unknown ast") + if e[1].kind == nkDotExpr: + dotExpr = e[1] + elif e[1].kind == nkCheckedFieldExpr: + dotExpr = e[1][0] + else: + internalError(p.config, e.info, "unknown ast") let t = dotExpr[0].typ.skipTypes({tyTypeDesc}) let tname = getTypeDesc(p.module, t) let member = @@ -2813,8 +2861,10 @@ proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo): Rope = result.add getDefaultValue(p, t.sons[1], info) result.add "}" #result = rope"{}" + of tyOpenArray, tyVarargs: + result = rope"{NIM_NIL, 0}" of tySet: - if mapType(p.config, t) == ctArray: result = rope"{}" + if mapSetType(p.config, t) == ctArray: result = rope"{}" else: result = rope"0" else: globalError(p.config, info, "cannot create null element for: " & $t.kind) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index e40e94d01..48c024b1f 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1556,7 +1556,7 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) = let le = e[0] let ri = e[1] var a: TLoc - discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs)) + discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs), skVar) initLoc(a, locNone, le, OnUnknown) a.flags.incl(lfEnforceDeref) a.flags.incl(lfPrepareForMutation) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index fad6093ed..5b5720934 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -149,7 +149,7 @@ proc mapSetType(conf: ConfigRef; typ: PType): TCTypeKind = of 8: result = ctInt64 else: result = ctArray -proc mapType(conf: ConfigRef; typ: PType): TCTypeKind = +proc mapType(conf: ConfigRef; typ: PType; kind: TSymKind): TCTypeKind = ## Maps a Nim type to a C type case typ.kind of tyNone, tyTyped: result = ctVoid @@ -157,14 +157,17 @@ proc mapType(conf: ConfigRef; typ: PType): TCTypeKind = of tyChar: result = ctChar of tyNil: result = ctPtr of tySet: result = mapSetType(conf, typ) - of tyOpenArray, tyArray, tyVarargs, tyUncheckedArray: result = ctArray + of tyOpenArray, tyVarargs: + if kind == skParam: result = ctArray + else: result = ctStruct + of tyArray, tyUncheckedArray: result = ctArray of tyObject, tyTuple: result = ctStruct of tyUserTypeClasses: doAssert typ.isResolvedUserTypeClass - return mapType(conf, typ.lastSon) + return mapType(conf, typ.lastSon, kind) of tyGenericBody, tyGenericInst, tyGenericParam, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias, tySink, tyInferred, tyOwned: - result = mapType(conf, lastSon(typ)) + result = mapType(conf, lastSon(typ), kind) of tyEnum: if firstOrd(conf, typ) < 0: result = ctInt32 @@ -175,7 +178,7 @@ proc mapType(conf: ConfigRef; typ: PType): TCTypeKind = of 4: result = ctInt32 of 8: result = ctInt64 else: result = ctInt32 - of tyRange: result = mapType(conf, typ[0]) + of tyRange: result = mapType(conf, typ[0], kind) of tyPtr, tyVar, tyLent, tyRef: var base = skipTypes(typ.lastSon, typedescInst) case base.kind @@ -192,14 +195,14 @@ proc mapType(conf: ConfigRef; typ: PType): TCTypeKind = of tyInt..tyUInt64: result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt)) of tyStatic: - if typ.n != nil: result = mapType(conf, lastSon typ) + if typ.n != nil: result = mapType(conf, lastSon typ, kind) else: doAssert(false, "mapType") else: doAssert(false, "mapType") proc mapReturnType(conf: ConfigRef; typ: PType): TCTypeKind = #if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr #else: - result = mapType(conf, typ) + result = mapType(conf, typ, skResult) proc isImportedType(t: PType): bool = result = t.sym != nil and sfImportc in t.sym.flags @@ -209,7 +212,7 @@ proc isImportedCppType(t: PType): bool = result = (t.sym != nil and sfInfixCall in t.sym.flags) or (x.sym != nil and sfInfixCall in x.sym.flags) -proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope +proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKind): Rope proc isObjLackingTypeField(typ: PType): bool {.inline.} = result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and @@ -222,7 +225,7 @@ proc isInvalidReturnType(conf: ConfigRef; rettype: PType): bool = # is necessary for proper code generation of assignments. if rettype == nil: result = true else: - case mapType(conf, rettype) + case mapType(conf, rettype, skResult) of ctArray: result = not (skipTypes(rettype, typedescInst).kind in {tyVar, tyLent, tyRef, tyPtr}) @@ -346,8 +349,8 @@ proc getTypePre(m: BModule, typ: PType; sig: SigHash): Rope = if result == nil: result = cacheGetType(m.typeCache, sig) proc structOrUnion(t: PType): Rope = - let cachedUnion {.global.} = rope("union") - let cachedStruct {.global.} = rope("struct") + let cachedUnion = rope("union") + let cachedStruct = rope("struct") let t = t.skipTypes({tyAlias, tySink}) if tfUnion in t.flags: cachedUnion else: cachedStruct @@ -379,7 +382,7 @@ proc getTypeForward(m: BModule, typ: PType; sig: SigHash): Rope = doAssert m.forwTypeCache[sig] == result else: internalError(m.config, "getTypeForward(" & $typ.kind & ')') -proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope = +proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet; kind: TSymKind): Rope = ## like getTypeDescAux but creates only a *weak* dependency. In other words ## we know we only need a pointer to it so we only generate a struct forward ## declaration: @@ -387,7 +390,7 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope = case etB.kind of tyObject, tyTuple: if isImportedCppType(etB) and t.kind == tyGenericInst: - result = getTypeDescAux(m, t, check) + result = getTypeDescAux(m, t, check, kind) else: result = getTypeForward(m, t, hashType(t)) pushType(m, t) @@ -417,18 +420,18 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope = result = getTypeForward(m, t, sig) & seqStar(m) pushType(m, t) else: - result = getTypeDescAux(m, t, check) + result = getTypeDescAux(m, t, check, kind) proc getSeqPayloadType(m: BModule; t: PType): Rope = var check = initIntSet() - result = getTypeDescWeak(m, t, check) & "_Content" + result = getTypeDescWeak(m, t, check, skParam) & "_Content" #result = getTypeForward(m, t, hashType(t)) & "_Content" proc seqV2ContentType(m: BModule; t: PType; check: var IntSet) = let sig = hashType(t) let result = cacheGetType(m.typeCache, sig) if result == nil: - discard getTypeDescAux(m, t, check) + discard getTypeDescAux(m, t, check, skVar) else: # little hack for now to prevent multiple definitions of the same # Seq_Content: @@ -437,7 +440,7 @@ $3ifndef $2_Content_PP $3define $2_Content_PP struct $2_Content { NI cap; $1 data[SEQ_DECL_SIZE];}; $3endif$N - """, [getTypeDescAux(m, t.skipTypes(abstractInst)[0], check), result, rope"#"]) + """, [getTypeDescAux(m, t.skipTypes(abstractInst)[0], check, skVar), result, rope"#"]) proc paramStorageLoc(param: PSym): TStorageLoc = if param.typ.skipTypes({tyVar, tyLent, tyTypeDesc}).kind notin { @@ -453,7 +456,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope, if t[0] == nil or isInvalidReturnType(m.config, t[0]): rettype = ~"void" else: - rettype = getTypeDescAux(m, t[0], check) + rettype = getTypeDescAux(m, t[0], check, skResult) for i in 1..<t.n.len: if t.n[i].kind != nkSym: internalError(m.config, t.n.info, "genProcParams") var param = t.n[i].sym @@ -462,14 +465,14 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope, fillLoc(param.loc, locParam, t.n[i], mangleParamName(m, param), param.paramStorageLoc) if ccgIntroducedPtr(m.config, param, t[0]): - params.add(getTypeDescWeak(m, param.typ, check)) + params.add(getTypeDescWeak(m, param.typ, check, skParam)) params.add(~"*") incl(param.loc.flags, lfIndirect) param.loc.storage = OnUnknown elif weakDep: - params.add(getTypeDescWeak(m, param.typ, check)) + params.add(getTypeDescWeak(m, param.typ, check, skParam)) else: - params.add(getTypeDescAux(m, param.typ, check)) + params.add(getTypeDescAux(m, param.typ, check, skParam)) params.add(~" ") params.add(param.loc.r) # declare the len field for open arrays: @@ -487,10 +490,10 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope, var arr = t[0] if params != nil: params.add(", ") if mapReturnType(m.config, t[0]) != ctArray: - params.add(getTypeDescWeak(m, arr, check)) + params.add(getTypeDescWeak(m, arr, check, skResult)) params.add("*") else: - params.add(getTypeDescAux(m, arr, check)) + params.add(getTypeDescAux(m, arr, check, skResult)) params.addf(" Result", []) if t.callConv == ccClosure and declareEnvironment: if params != nil: params.add(", ") @@ -562,16 +565,16 @@ proc genRecordFieldsAux(m: BModule, n: PNode, let fieldType = field.loc.lode.typ.skipTypes(abstractInst) if fieldType.kind == tyUncheckedArray: result.addf("$1 $2[SEQ_DECL_SIZE];$n", - [getTypeDescAux(m, fieldType.elemType, check), sname]) + [getTypeDescAux(m, fieldType.elemType, check, skField), sname]) elif fieldType.kind == tySequence: # we need to use a weak dependency here for trecursive_table. - result.addf("$1 $2;$n", [getTypeDescWeak(m, field.loc.t, check), sname]) + result.addf("$1 $2;$n", [getTypeDescWeak(m, field.loc.t, check, skField), sname]) elif field.bitsize != 0: - result.addf("$1 $2:$3;$n", [getTypeDescAux(m, field.loc.t, check), sname, rope($field.bitsize)]) + result.addf("$1 $2:$3;$n", [getTypeDescAux(m, field.loc.t, check, skField), sname, rope($field.bitsize)]) else: # don't use fieldType here because we need the # tyGenericInst for C++ template support - result.addf("$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname]) + result.addf("$1 $2;$n", [getTypeDescAux(m, field.loc.t, check, skField), sname]) else: internalError(m.config, n.info, "genRecordFieldsAux()") proc getRecordFields(m: BModule, typ: PType, check: var IntSet): Rope = @@ -610,7 +613,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope, hasField = true elif m.compileToCpp: appcg(m, result, " : public $1 {$n", - [getTypeDescAux(m, typ[0].skipTypes(skipPtrs), check)]) + [getTypeDescAux(m, typ[0].skipTypes(skipPtrs), check, skField)]) if typ.isException and m.config.exc == excCpp: when false: appcg(m, result, "virtual void raise() { throw *this; }$n", []) # required for polymorphic exceptions @@ -623,7 +626,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope, hasField = true else: appcg(m, result, " {$n $1 Sup;$n", - [getTypeDescAux(m, typ[0].skipTypes(skipPtrs), check)]) + [getTypeDescAux(m, typ[0].skipTypes(skipPtrs), check, skField)]) hasField = true else: result.addf(" {$n", [name]) @@ -643,7 +646,7 @@ proc getTupleDesc(m: BModule, typ: PType, name: Rope, var desc: Rope = nil for i in 0..<typ.len: desc.addf("$1 Field$2;$n", - [getTypeDescAux(m, typ[i], check), rope(i)]) + [getTypeDescAux(m, typ[i], check, skField), rope(i)]) if desc == nil: result.add("char dummy;\L") else: result.add(desc) result.add("};\L") @@ -677,7 +680,20 @@ proc resolveStarsInCppType(typ: PType, idx, stars: int): PType = result = if result.kind == tyGenericInst: result[1] else: result.elemType -proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope = +proc getOpenArrayDesc(m: BModule, t: PType, check: var IntSet; kind: TSymKind): Rope = + let sig = hashType(t) + if kind == skParam: + result = getTypeDescWeak(m, t[0], check, kind) & "*" + else: + result = cacheGetType(m.typeCache, sig) + if result == nil: + result = getTypeName(m, t, sig) + m.typeCache[sig] = result + let elemType = getTypeDescWeak(m, t[0], check, kind) + m.s[cfsTypes].addf("typedef struct {$n$2* d;$nNI l;$n} $1;$n", + [result, elemType]) + +proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKind): Rope = # returns only the type's name var t = origTyp.skipTypes(irrelevantForBackend-{tyOwned}) @@ -696,7 +712,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope = addAbiCheck(m, t, result) result = getTypePre(m, t, sig) - if result != nil: + if result != nil and t.kind != tyOpenArray: excl(check, t.id) return case t.kind @@ -705,7 +721,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope = compileToCpp(m): "&" else: "*" var et = origTyp.skipTypes(abstractInst).lastSon var etB = et.skipTypes(abstractInst) - if mapType(m.config, t) == ctPtrToArray: + if mapType(m.config, t, kind) == ctPtrToArray: if etB.kind == tySet: et = getSysType(m.g.graph, unknownLineInfo, tyUInt8) else: @@ -715,7 +731,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope = case etB.kind of tyObject, tyTuple: if isImportedCppType(etB) and et.kind == tyGenericInst: - result = getTypeDescAux(m, et, check) & star + result = getTypeDescAux(m, et, check, kind) & star else: # no restriction! We have a forward declaration for structs let name = getTypeForward(m, et, hashType et) @@ -723,7 +739,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope = m.typeCache[sig] = result of tySequence: if optSeqDestructors in m.config.globalOptions: - result = getTypeDescWeak(m, et, check) & star + result = getTypeDescWeak(m, et, check, kind) & star m.typeCache[sig] = result else: # no restriction! We have a forward declaration for structs @@ -733,11 +749,10 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope = pushType(m, et) else: # else we have a strong dependency :-( - result = getTypeDescAux(m, et, check) & star + result = getTypeDescAux(m, et, check, kind) & star m.typeCache[sig] = result of tyOpenArray, tyVarargs: - result = getTypeDescWeak(m, t[0], check) & "*" - m.typeCache[sig] = result + result = getOpenArrayDesc(m, t, check, kind) of tyEnum: result = cacheGetType(m.typeCache, sig) if result == nil: @@ -783,7 +798,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope = [result, rettype, desc]) of tySequence: if optSeqDestructors in m.config.globalOptions: - result = getTypeDescWeak(m, t, check) + result = getTypeDescWeak(m, t, check, kind) else: # we cannot use getTypeForward here because then t would be associated # with the name of the struct, not with the pointer to the struct: @@ -804,11 +819,11 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope = if m.compileToCpp: appcg(m, m.s[cfsSeqTypes], cppSeq & " $1 data[SEQ_DECL_SIZE];$n" & - "};$n", [getTypeDescAux(m, t[0], check), result]) + "};$n", [getTypeDescAux(m, t[0], check, kind), result]) else: appcg(m, m.s[cfsSeqTypes], cSeq & " $1 data[SEQ_DECL_SIZE];$n" & - "};$n", [getTypeDescAux(m, t[0], check), result]) + "};$n", [getTypeDescAux(m, t[0], check, kind), result]) else: result = rope("TGenericSeq") result.add(seqStar(m)) @@ -816,7 +831,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope = result = getTypeName(m, origTyp, sig) m.typeCache[sig] = result if not isImportedType(t): - let foo = getTypeDescAux(m, t[0], check) + let foo = getTypeDescAux(m, t[0], check, kind) m.s[cfsTypes].addf("typedef $1 $2[1];$n", [foo, result]) of tyArray: var n: BiggestInt = toInt64(lengthOrd(m.config, t)) @@ -824,7 +839,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope = result = getTypeName(m, origTyp, sig) m.typeCache[sig] = result if not isImportedType(t): - let foo = getTypeDescAux(m, t[1], check) + let foo = getTypeDescAux(m, t[1], check, kind) m.s[cfsTypes].addf("typedef $1 $2[$3];$n", [foo, result, rope(n)]) of tyObject, tyTuple: @@ -840,7 +855,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope = internalAssert m.config, ty.n != nil result.add ty.n.renderTree else: - result.add getTypeDescAux(m, ty, check) + result.add getTypeDescAux(m, ty, check, kind) while i < cppName.data.len: if cppName.data[i] == '\'': @@ -901,16 +916,16 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope = [result, rope(getSize(m.config, t))]) of tyGenericInst, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias, tySink, tyOwned, tyUserTypeClass, tyUserTypeClassInst, tyInferred: - result = getTypeDescAux(m, lastSon(t), check) + result = getTypeDescAux(m, lastSon(t), check, kind) else: internalError(m.config, "getTypeDescAux(" & $t.kind & ')') result = nil # fixes bug #145: excl(check, t.id) -proc getTypeDesc(m: BModule, typ: PType): Rope = +proc getTypeDesc(m: BModule, typ: PType; kind = skParam): Rope = var check = initIntSet() - result = getTypeDescAux(m, typ, check) + result = getTypeDescAux(m, typ, check, kind) type TClosureTypeKind = enum ## In C closures are mapped to 3 different things. @@ -942,7 +957,7 @@ proc finishTypeDescriptions(m: BModule) = if optSeqDestructors in m.config.globalOptions and t.skipTypes(abstractInst).kind == tySequence: seqV2ContentType(m, t, check) else: - discard getTypeDescAux(m, t, check) + discard getTypeDescAux(m, t, check, skParam) inc(i) m.typeStack.setLen 0 diff --git a/compiler/cgen.nim b/compiler/cgen.nim index d40aa32d7..d5e1e020c 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -310,14 +310,19 @@ include ccgtypes # ------------------------------ Manager of temporaries ------------------ +template mapTypeChooser(n: PNode): TSymKind = + (if n.kind == nkSym: n.sym.kind else: skVar) + +template mapTypeChooser(a: TLoc): TSymKind = mapTypeChooser(a.lode) + proc addrLoc(conf: ConfigRef; a: TLoc): Rope = result = a.r - if lfIndirect notin a.flags and mapType(conf, a.t) != ctArray: + if lfIndirect notin a.flags and mapType(conf, a.t, mapTypeChooser(a)) != ctArray: result = "(&" & result & ")" proc byRefLoc(p: BProc; a: TLoc): Rope = result = a.r - if lfIndirect notin a.flags and mapType(p.config, a.t) != ctArray and not + if lfIndirect notin a.flags and mapType(p.config, a.t, mapTypeChooser(a)) != ctArray and not p.module.compileToCpp: result = "(&" & result & ")" @@ -364,7 +369,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: var TLoc, rawConstExpr(p, newNodeIT(nkType, a.lode.info, objType), tmp) linefmt(p, cpsStmts, "#nimCopyMem((void*)$1, (NIM_CONST void*)&$2, sizeof($3));$n", - [rdLoc(a), rdLoc(tmp), getTypeDesc(p.module, objType)]) + [rdLoc(a), rdLoc(tmp), getTypeDesc(p.module, objType, mapTypeChooser(a))]) else: rawConstExpr(p, newNodeIT(nkType, a.lode.info, t), tmp) genAssignment(p, a, tmp, {}) @@ -387,7 +392,7 @@ proc genRefAssign(p: BProc, dest, src: TLoc) proc isComplexValueType(t: PType): bool {.inline.} = let t = t.skipTypes(abstractInst + tyUserTypeClasses) - result = t.kind in {tyArray, tySet, tyTuple, tyObject} or + result = t.kind in {tyArray, tySet, tyTuple, tyObject, tyOpenArray} or (t.kind == tyProc and t.callConv == ccClosure) include ccgreset @@ -420,7 +425,8 @@ proc resetLoc(p: BProc, loc: var TLoc) = # array passed as argument decayed into pointer, bug #7332 # so we use getTypeDesc here rather than rdLoc(loc) linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n", - [addrLoc(p.config, loc), getTypeDesc(p.module, loc.t)]) + [addrLoc(p.config, loc), + getTypeDesc(p.module, loc.t, mapTypeChooser(loc))]) # XXX: We can be extra clever here and call memset only # on the bytes following the m_type field? genObjectInit(p, cpsStmts, loc.t, loc, constructObj) @@ -431,14 +437,14 @@ proc constructLoc(p: BProc, loc: var TLoc, isTemp = false) = linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)]) elif not isComplexValueType(typ): linefmt(p, cpsStmts, "$1 = ($2)0;$n", [rdLoc(loc), - getTypeDesc(p.module, typ)]) + getTypeDesc(p.module, typ, mapTypeChooser(loc))]) else: if not isTemp or containsGarbageCollectedRef(loc.t): # don't use nimZeroMem for temporary values for performance if we can # avoid it: if not isImportedCppType(typ): linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n", - [addrLoc(p.config, loc), getTypeDesc(p.module, typ)]) + [addrLoc(p.config, loc), getTypeDesc(p.module, typ, mapTypeChooser(loc))]) genObjectInit(p, cpsStmts, loc.t, loc, constructObj) proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) = @@ -456,7 +462,7 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) = proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) = inc(p.labels) result.r = "T" & rope(p.labels) & "_" - linefmt(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t), result.r]) + linefmt(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t, skVar), result.r]) result.k = locTemp result.lode = lodeTyp t result.storage = OnStack @@ -466,7 +472,7 @@ proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) = proc getTempCpp(p: BProc, t: PType, result: var TLoc; value: Rope) = inc(p.labels) result.r = "T" & rope(p.labels) & "_" - linefmt(p, cpsStmts, "$1 $2 = $3;$n", [getTypeDesc(p.module, t), result.r, value]) + linefmt(p, cpsStmts, "$1 $2 = $3;$n", [getTypeDesc(p.module, t, skVar), result.r, value]) result.k = locTemp result.lode = lodeTyp t result.storage = OnStack @@ -488,7 +494,7 @@ proc localVarDecl(p: BProc; n: PNode): Rope = if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy) if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0: result.addf("NIM_ALIGN($1) ", [rope(s.alignment)]) - result.add getTypeDesc(p.module, s.typ) + result.add getTypeDesc(p.module, s.typ, skVar) if s.constraint.isNil: if sfRegister in s.flags: result.add(" register") #elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds: @@ -541,7 +547,7 @@ proc assignGlobalVar(p: BProc, n: PNode; value: Rope) = internalError(p.config, n.info, ".threadvar variables cannot have a value") else: var decl: Rope = nil - var td = getTypeDesc(p.module, s.loc.t) + var td = getTypeDesc(p.module, s.loc.t, skVar) if s.constraint.isNil: if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0: decl.addf "NIM_ALIGN($1) ", [rope(s.alignment)] @@ -687,7 +693,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) = initLoc(dest, locTemp, lib.path, OnStack) dest.r = getTempName(m) appcg(m, m.s[cfsDynLibInit],"$1 $2;$n", - [getTypeDesc(m, lib.path.typ), rdLoc(dest)]) + [getTypeDesc(m, lib.path.typ, skVar), rdLoc(dest)]) expr(p, lib.path, dest) m.s[cfsVars].add(p.s(cpsLocals)) @@ -727,7 +733,7 @@ proc symInDynamicLib(m: BModule, sym: PSym) = params.add(rdLoc(a)) params.add(", ") let load = "\t$1 = ($2) ($3$4));$n" % - [tmp, getTypeDesc(m, sym.typ), params, makeCString($extname)] + [tmp, getTypeDesc(m, sym.typ, skVar), params, makeCString($extname)] var last = lastSon(n) if last.kind == nkHiddenStdConv: last = last[1] internalAssert(m.config, last.kind == nkStrLit) @@ -741,8 +747,8 @@ proc symInDynamicLib(m: BModule, sym: PSym) = else: appcg(m, m.s[cfsDynLibInit], "\t$1 = ($2) #nimGetProcAddr($3, $4);$n", - [tmp, getTypeDesc(m, sym.typ), lib.name, makeCString($extname)]) - m.s[cfsVars].addf("$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t)]) + [tmp, getTypeDesc(m, sym.typ, skVar), lib.name, makeCString($extname)]) + m.s[cfsVars].addf("$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t, skVar)]) proc varInDynamicLib(m: BModule, sym: PSym) = var lib = sym.annex @@ -754,9 +760,9 @@ proc varInDynamicLib(m: BModule, sym: PSym) = inc(m.labels, 2) appcg(m, m.s[cfsDynLibInit], "$1 = ($2*) #nimGetProcAddr($3, $4);$n", - [tmp, getTypeDesc(m, sym.typ), lib.name, makeCString($extname)]) + [tmp, getTypeDesc(m, sym.typ, skVar), lib.name, makeCString($extname)]) m.s[cfsVars].addf("$2* $1;$n", - [sym.loc.r, getTypeDesc(m, sym.loc.t)]) + [sym.loc.r, getTypeDesc(m, sym.loc.t, skVar)]) proc symInDynamicLibPartial(m: BModule, sym: PSym) = sym.loc.r = mangleDynLibProc(sym) @@ -1187,7 +1193,7 @@ proc requestConstImpl(p: BProc, sym: PSym) = [getTypeDesc(q, sym.typ), actualConstName, genBracedInit(q.initProc, sym.ast, isConst = true)]) if m.hcrOn: # generate the global pointer with the real name - q.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(m, sym.loc.t), sym.loc.r]) + q.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(m, sym.loc.t, skVar), sym.loc.r]) # register it (but ignore the boolean result of hcrRegisterGlobal) q.initProc.procSec(cpsLocals).addf( "\thcrRegisterGlobal($1, \"$2\", sizeof($3), NULL, (void**)&$2);$n", @@ -1201,13 +1207,13 @@ proc requestConstImpl(p: BProc, sym: PSym) = if q != m and not containsOrIncl(m.declaredThings, sym.id): assert(sym.loc.r != nil) if m.hcrOn: - m.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(m, sym.loc.t), sym.loc.r]); + m.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(m, sym.loc.t, skVar), sym.loc.r]); m.initProc.procSec(cpsLocals).addf( "\t$1 = ($2*)hcrGetGlobal($3, \"$1\");$n", [sym.loc.r, - getTypeDesc(m, sym.loc.t), getModuleDllPath(q, sym)]) + getTypeDesc(m, sym.loc.t, skVar), getModuleDllPath(q, sym)]) else: let headerDecl = "extern NIM_CONST $1 $2;$n" % - [getTypeDesc(m, sym.loc.t), sym.loc.r] + [getTypeDesc(m, sym.loc.t, skVar), sym.loc.r] m.s[cfsData].add(headerDecl) if sfExportc in sym.flags and p.module.g.generatedHeader != nil: p.module.g.generatedHeader.s[cfsData].add(headerDecl) @@ -1247,7 +1253,7 @@ proc genVarPrototype(m: BModule, n: PNode) = if sym.kind in {skLet, skVar, skField, skForVar} and sym.alignment > 0: m.s[cfsVars].addf "NIM_ALIGN($1) ", [rope(sym.alignment)] m.s[cfsVars].add(if m.hcrOn: "static " else: "extern ") - m.s[cfsVars].add(getTypeDesc(m, sym.loc.t)) + m.s[cfsVars].add(getTypeDesc(m, sym.loc.t, skVar)) if m.hcrOn: m.s[cfsVars].add("*") if lfDynamicLib in sym.loc.flags: m.s[cfsVars].add("*") if sfRegister in sym.flags: m.s[cfsVars].add(" register") @@ -1255,7 +1261,7 @@ proc genVarPrototype(m: BModule, n: PNode) = m.s[cfsVars].addf(" $1;$n", [sym.loc.r]) if m.hcrOn: m.initProc.procSec(cpsLocals).addf( "\t$1 = ($2*)hcrGetGlobal($3, \"$1\");$n", [sym.loc.r, - getTypeDesc(m, sym.loc.t), getModuleDllPath(m, sym)]) + getTypeDesc(m, sym.loc.t, skVar), getModuleDllPath(m, sym)]) proc addNimDefines(result: var Rope; conf: ConfigRef) {.inline.} = result.addf("#define NIM_INTBITS $1\L", [ @@ -1613,10 +1619,10 @@ proc hcrGetProcLoadCode(m: BModule, sym, prefix, handle, getProcFunc: string): R prc.typ.sym = nil if not containsOrIncl(m.declaredThings, prc.id): - m.s[cfsVars].addf("static $2 $1;$n", [prc.loc.r, getTypeDesc(m, prc.loc.t)]) + m.s[cfsVars].addf("static $2 $1;$n", [prc.loc.r, getTypeDesc(m, prc.loc.t, skVar)]) result = "\t$1 = ($2) $3($4, $5);$n" % - [tmp, getTypeDesc(m, prc.typ), getProcFunc.rope, handle.rope, makeCString(prefix & sym)] + [tmp, getTypeDesc(m, prc.typ, skVar), getProcFunc.rope, handle.rope, makeCString(prefix & sym)] proc genInitCode(m: BModule) = ## this function is called in cgenWriteModules after all modules are closed, diff --git a/compiler/options.nim b/compiler/options.nim index 14016495f..5b23ac9af 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -162,7 +162,8 @@ type ## which itself requires `nimble install libffi`, see #10150 ## Note: this feature can't be localized with {.push.} vmopsDanger, - strictFuncs + strictFuncs, + views LegacyFeature* = enum allowSemcheckedAstModification, diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 9601bf082..9c7609f9a 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -1035,7 +1035,14 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = gsub(g, n, 1) of nkHiddenStdConv, nkHiddenSubConv: if n.len >= 2: - gsub(g, n[1]) + when false: + # if {renderIds, renderIr} * g.flags != {}: + put(g, tkSymbol, "(conv)") + put(g, tkParLe, "(") + gsub(g, n[1]) + put(g, tkParRi, ")") + else: + gsub(g, n[1]) else: put(g, tkSymbol, "(wrong conv)") of nkHiddenCallConv: diff --git a/compiler/sem.nim b/compiler/sem.nim index 07c76eed4..705e1b72c 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -17,7 +17,7 @@ import intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting, evaltempl, patterns, parampatterns, sempass2, linter, semmacrosanity, lowerings, plugins/active, rod, lineinfos, strtabs, int128, - isolation_check + isolation_check, typeallowed from modulegraphs import ModuleGraph, PPassContext, onUse, onDef, onDefResolveForward @@ -228,9 +228,9 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode, proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode, allowed: TSymFlags): PSym -proc typeAllowedCheck(conf: ConfigRef; info: TLineInfo; typ: PType; kind: TSymKind; +proc typeAllowedCheck(c: PContext; info: TLineInfo; typ: PType; kind: TSymKind; flags: TTypeAllowedFlags = {}) = - let t = typeAllowed(typ, kind, flags) + let t = typeAllowed(typ, kind, c, flags) if t != nil: var err: string if t == typ: @@ -240,10 +240,10 @@ proc typeAllowedCheck(conf: ConfigRef; info: TLineInfo; typ: PType; kind: TSymKi else: err = "invalid type: '$1' in this context: '$2' for $3" % [typeToString(t), typeToString(typ), toHumanStr(kind)] - localError(conf, info, err) + localError(c.config, info, err) proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} = - typeAllowedCheck(c.config, typ.n.info, typ, skProc) + typeAllowedCheck(c, typ.n.info, typ, skProc) proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 0e1c5e9d3..80e04ead4 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -178,7 +178,7 @@ proc checkConvertible(c: PContext, targetTyp: PType, src: PNode): TConvStatus = else: discard -proc isCastable(conf: ConfigRef; dst, src: PType): bool = +proc isCastable(c: PContext; dst, src: PType): bool = ## Checks whether the source type can be cast to the destination type. ## Casting is very unrestrictive; casts are allowed as long as ## castDest.size >= src.size, and typeAllowed(dst, skParam) @@ -193,6 +193,7 @@ proc isCastable(conf: ConfigRef; dst, src: PType): bool = return false if skipTypes(dst, abstractInst).kind == tyBuiltInTypeClass: return false + let conf = c.config if conf.selectedGC in {gcArc, gcOrc}: let d = skipTypes(dst, abstractInst) let s = skipTypes(src, abstractInst) @@ -210,7 +211,7 @@ proc isCastable(conf: ConfigRef; dst, src: PType): bool = result = false elif srcSize < 0: result = false - elif typeAllowed(dst, skParam) != nil: + elif typeAllowed(dst, skParam, c) != nil: result = false elif dst.kind == tyProc and dst.callConv == ccClosure: result = src.kind == tyProc and src.callConv == ccClosure @@ -338,7 +339,7 @@ proc semCast(c: PContext, n: PNode): PNode = let castedExpr = semExprWithType(c, n[1]) if tfHasMeta in targetType.flags: localError(c.config, n[0].info, "cannot cast to a non concrete type: '$1'" % $targetType) - if not isCastable(c.config, targetType, castedExpr.typ): + if not isCastable(c, targetType, castedExpr.typ): let tar = $targetType let alt = typeToString(targetType, preferDesc) let msg = if tar != alt: tar & "=" & alt else: tar @@ -794,7 +795,7 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode = if callee.kind notin {skProc, skFunc, skConverter, skConst} or callee.isGenericRoutine: return - if n.typ != nil and typeAllowed(n.typ, skConst) != nil: return + if n.typ != nil and typeAllowed(n.typ, skConst, c) != nil: return var call = newNodeIT(nkCall, n.info, n.typ) call.add(n[0]) @@ -962,9 +963,9 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = # t.sym != nil # sfAnon notin t.sym.flags # t.kind != tySequence(It is tyProc) - if typ.sym != nil and sfAnon notin typ.sym.flags and + if typ.sym != nil and sfAnon notin typ.sym.flags and typ.kind == tyProc: - msg.add(" = " & + msg.add(" = " & typeToString(typ, preferDesc)) localError(c.config, n.info, msg) return errorNode(c, n) @@ -1600,7 +1601,7 @@ proc takeImplicitAddr(c: PContext, n: PNode; isLent: bool): PNode = proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} = if le.kind == nkHiddenDeref: var x = le[0] - if x.typ.kind in {tyVar, tyLent} and x.kind == nkSym and x.sym.kind == skResult: + if (x.typ.kind in {tyVar, tyLent} or isViewType(x.typ)) and x.kind == nkSym and x.sym.kind == skResult: n[0] = x # 'result[]' --> 'result' n[1] = takeImplicitAddr(c, ri, x.typ.kind == tyLent) x.typ.flags.incl tfVarIsPtr @@ -1732,7 +1733,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode = if cmpTypes(c, lhs.typ, rhsTyp) in {isGeneric, isEqual}: internalAssert c.config, c.p.resultSym != nil # Make sure the type is valid for the result variable - typeAllowedCheck(c.config, n.info, rhsTyp, skResult) + typeAllowedCheck(c, n.info, rhsTyp, skResult) lhs.typ = rhsTyp c.p.resultSym.typ = rhsTyp c.p.owner.typ[0] = rhsTyp @@ -1825,7 +1826,9 @@ proc semYieldVarResult(c: PContext, n: PNode, restype: PType) = tupleConstr[i] = takeImplicitAddr(c, tupleConstr[i], e.kind == tyLent) else: localError(c.config, n[0].info, errXExpected, "tuple constructor") - else: discard + else: + if isViewType(t): + n[0] = takeImplicitAddr(c, n[0], false) proc semYield(c: PContext, n: PNode): PNode = result = n diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index f745f9075..b48d7e29e 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -1243,8 +1243,11 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) = effects[ensuresEffects] = ensuresSpec var mutationInfo = MutationInfo() - if strictFuncs in c.features and not t.hasSideEffect and t.hasDangerousAssign: - t.hasSideEffect = mutatesNonVarParameters(s, body, mutationInfo) + if {strictFuncs, views} * c.features != {}: + var partitions = computeGraphPartitions(s, body) + if not t.hasSideEffect and t.hasDangerousAssign: + t.hasSideEffect = varpartitions.hasSideEffect(partitions, mutationInfo) + checkBorrowedLocations(partitions, g.config) if sfThread in s.flags and t.gcUnsafe: if optThreads in g.config.globalOptions and optThreadAnalysis in g.config.globalOptions: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 2c3ff2bea..14f08b4b3 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -534,7 +534,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = if c.matchedConcept != nil: typFlags.incl taConcept - typeAllowedCheck(c.config, a.info, typ, symkind, typFlags) + typeAllowedCheck(c, a.info, typ, symkind, typFlags) when false: liftTypeBoundOps(c, typ, a.info) instAllTypeBoundOp(c, a.info) @@ -667,7 +667,7 @@ proc semConst(c: PContext, n: PNode): PNode = if def.kind != nkNilLit: if c.matchedConcept != nil: typFlags.incl taConcept - typeAllowedCheck(c.config, a.info, typ, skConst, typFlags) + typeAllowedCheck(c, a.info, typ, skConst, typFlags) var b: PNode if a.kind == nkVarTuple: diff --git a/compiler/transf.nim b/compiler/transf.nim index 8ff0664da..5dd275414 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -494,6 +494,7 @@ proc transformConv(c: PTransf, n: PNode): PNode = result = transformSons(c, n) of tyOpenArray, tyVarargs: result = transform(c, n[1]) + #result = transformSons(c, n) result.typ = takeType(n.typ, n[1].typ) #echo n.info, " came here and produced ", typeToString(result.typ), # " from ", typeToString(n.typ), " and ", typeToString(n[1].typ) @@ -1107,6 +1108,9 @@ proc transformBody*(g: ModuleGraph, prc: PSym, cache: bool): PNode = else: prc.transformedBody = nil + #if prc.name.s == "main": + # echo "transformed into ", renderTree(result, {renderIds}) + proc transformStmt*(g: ModuleGraph; module: PSym, n: PNode): PNode = if nfTransf in n.flags: result = n diff --git a/compiler/trees.nim b/compiler/trees.nim index bfb429f13..c5c1a0d75 100644 --- a/compiler/trees.nim +++ b/compiler/trees.nim @@ -183,7 +183,7 @@ proc getRoot*(n: PNode): PSym = if n.sym.kind in {skVar, skResult, skTemp, skLet, skForVar, skParam}: result = n.sym of nkDotExpr, nkBracketExpr, nkHiddenDeref, nkDerefExpr, - nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr: + nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr, nkHiddenAddr, nkAddr: result = getRoot(n[0]) of nkHiddenStdConv, nkHiddenSubConv, nkConv: result = getRoot(n[1]) diff --git a/compiler/typeallowed.nim b/compiler/typeallowed.nim new file mode 100644 index 000000000..5a192783e --- /dev/null +++ b/compiler/typeallowed.nim @@ -0,0 +1,228 @@ +# +# +# The Nim Compiler +# (c) Copyright 2020 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module contains 'typeAllowed' and friends which check +## for invalid types like 'openArray[var int]'. + +import + intsets, ast, renderer, options, semdata, types + +type + TTypeAllowedFlag* = enum + taField, + taHeap, + taConcept, + taIsOpenArray, + taNoUntyped + taIsTemplateOrMacro + taProcContextIsNotMacro + + TTypeAllowedFlags* = set[TTypeAllowedFlag] + +proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind; + c: PContext; flags: TTypeAllowedFlags = {}): PType + +proc typeAllowedNode(marker: var IntSet, n: PNode, kind: TSymKind, + c: PContext; flags: TTypeAllowedFlags = {}): PType = + if n != nil: + result = typeAllowedAux(marker, n.typ, kind, c, flags) + if result == nil: + case n.kind + of nkNone..nkNilLit: + discard + else: + #if n.kind == nkRecCase and kind in {skProc, skFunc, skConst}: + # return n[0].typ + for i in 0..<n.len: + let it = n[i] + result = typeAllowedNode(marker, it, kind, c, flags) + if result != nil: break + +proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, + c: PContext; flags: TTypeAllowedFlags = {}): PType = + assert(kind in {skVar, skLet, skConst, skProc, skFunc, skParam, skResult}) + # if we have already checked the type, return true, because we stop the + # evaluation if something is wrong: + result = nil + if typ == nil: return nil + if containsOrIncl(marker, typ.id): return nil + var t = skipTypes(typ, abstractInst-{tyTypeDesc}) + case t.kind + of tyVar, tyLent: + if kind in {skProc, skFunc, skConst} and (views notin c.features): + result = t + elif t.kind == tyLent and kind != skResult: + result = t + else: + var t2 = skipTypes(t[0], abstractInst-{tyTypeDesc}) + case t2.kind + of tyVar, tyLent: + if taHeap notin flags: result = t2 # ``var var`` is illegal on the heap + of tyOpenArray: + if (kind != skParam and views notin c.features) or taIsOpenArray in flags: result = t + else: result = typeAllowedAux(marker, t2[0], kind, c, flags+{taIsOpenArray}) + of tyUncheckedArray: + if kind != skParam: result = t + else: result = typeAllowedAux(marker, t2[0], kind, c, flags) + else: + if kind notin {skParam, skResult}: result = t + else: result = typeAllowedAux(marker, t2, kind, c, flags) + of tyProc: + if kind in {skVar, skLet, skConst} and taIsTemplateOrMacro in flags: + result = t + else: + if isInlineIterator(typ) and kind in {skVar, skLet, skConst, skParam, skResult}: + # only closure iterators may be assigned to anything. + result = t + let f = if kind in {skProc, skFunc}: flags+{taNoUntyped} else: flags + for i in 1..<t.len: + if result != nil: break + result = typeAllowedAux(marker, t[i], skParam, c, f-{taIsOpenArray}) + if result.isNil and t[0] != nil: + result = typeAllowedAux(marker, t[0], skResult, c, flags) + of tyTypeDesc: + if kind in {skVar, skLet, skConst} and taProcContextIsNotMacro in flags: + result = t + else: + # XXX: This is still a horrible idea... + result = nil + of tyUntyped, tyTyped: + if kind notin {skParam, skResult} or taNoUntyped in flags: result = t + of tyStatic: + if kind notin {skParam}: result = t + of tyVoid: + if taField notin flags: result = t + of tyTypeClasses: + if tfGenericTypeParam in t.flags or taConcept in flags: #or taField notin flags: + discard + elif t.isResolvedUserTypeClass: + result = typeAllowedAux(marker, t.lastSon, kind, c, flags) + elif kind notin {skParam, skResult}: + result = t + of tyGenericBody, tyGenericParam, tyGenericInvocation, + tyNone, tyForward, tyFromExpr: + result = t + of tyNil: + if kind != skConst and kind != skParam: result = t + of tyString, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString, tyPointer: + result = nil + of tyOrdinal: + if kind != skParam: result = t + of tyGenericInst, tyDistinct, tyAlias, tyInferred: + result = typeAllowedAux(marker, lastSon(t), kind, c, flags) + of tyRange: + if skipTypes(t[0], abstractInst-{tyTypeDesc}).kind notin + {tyChar, tyEnum, tyInt..tyFloat128, tyInt..tyUInt64}: result = t + of tyOpenArray: + # you cannot nest openArrays/sinks/etc. + if (kind != skParam and views notin c.features) or taIsOpenArray in flags: + result = t + else: + result = typeAllowedAux(marker, t[0], kind, c, flags+{taIsOpenArray}) + of tyVarargs, tySink: + # you cannot nest openArrays/sinks/etc. + if kind != skParam or taIsOpenArray in flags: + result = t + else: + result = typeAllowedAux(marker, t[0], kind, c, flags+{taIsOpenArray}) + of tyUncheckedArray: + if kind != skParam and taHeap notin flags: + result = t + else: + result = typeAllowedAux(marker, lastSon(t), kind, c, flags-{taHeap}) + of tySequence: + if t[0].kind != tyEmpty: + result = typeAllowedAux(marker, t[0], kind, c, flags+{taHeap}) + elif kind in {skVar, skLet}: + result = t[0] + of tyArray: + if t[1].kind == tyTypeDesc: + result = t[1] + elif t[1].kind != tyEmpty: + result = typeAllowedAux(marker, t[1], kind, c, flags) + elif kind in {skVar, skLet}: + result = t[1] + of tyRef: + if kind == skConst: result = t + else: result = typeAllowedAux(marker, t.lastSon, kind, c, flags+{taHeap}) + of tyPtr: + result = typeAllowedAux(marker, t.lastSon, kind, c, flags+{taHeap}) + of tySet: + for i in 0..<t.len: + result = typeAllowedAux(marker, t[i], kind, c, flags) + if result != nil: break + of tyObject, tyTuple: + if kind in {skProc, skFunc, skConst} and + t.kind == tyObject and t[0] != nil: + result = t + else: + let flags = flags+{taField} + for i in 0..<t.len: + result = typeAllowedAux(marker, t[i], kind, c, flags) + if result != nil: break + if result.isNil and t.n != nil: + result = typeAllowedNode(marker, t.n, kind, c, flags) + of tyEmpty: + if kind in {skVar, skLet}: result = t + of tyProxy: + # for now same as error node; we say it's a valid type as it should + # prevent cascading errors: + result = nil + of tyOwned: + if t.len == 1 and t[0].skipTypes(abstractInst).kind in {tyRef, tyPtr, tyProc}: + result = typeAllowedAux(marker, t.lastSon, kind, c, flags+{taHeap}) + else: + result = t + of tyOptDeprecated: doAssert false + +proc typeAllowed*(t: PType, kind: TSymKind; c: PContext; flags: TTypeAllowedFlags = {}): PType = + # returns 'nil' on success and otherwise the part of the type that is + # wrong! + var marker = initIntSet() + result = typeAllowedAux(marker, t, kind, c, flags) + +proc isViewTypeAux(marker: var IntSet, t: PType): bool + +proc isViewTypeNode(marker: var IntSet, n: PNode): bool = + case n.kind + of nkSym: + result = isViewTypeAux(marker, n.typ) + of nkOfBranch: + result = isViewTypeNode(marker, n.lastSon) + else: + for child in n: + result = isViewTypeNode(marker, child) + if result: break + +proc isViewTypeAux(marker: var IntSet, t: PType): bool = + if containsOrIncl(marker, t.id): return false + case t.kind + of tyVar, tyLent, tyVarargs, tyOpenArray: + result = true + of tyGenericInst, tyDistinct, tyAlias, tyInferred, tySink, tyOwned, + tyUncheckedArray, tySequence, tyArray, tyRef, tyStatic, tyFromExpr: + result = isViewTypeAux(marker, lastSon(t)) + of tyTuple: + for i in 0..<t.len: + result = isViewTypeAux(marker, t[i]) + if result: break + of tyObject: + result = false + if t.n != nil: + result = isViewTypeNode(marker, t.n) + if t[0] != nil: + result = result or isViewTypeAux(marker, t[0]) + else: + # it doesn't matter what these types contain, 'ptr openArray' is not a + # view type! + result = false + +proc isViewType*(t: PType): bool = + var marker = initIntSet() + result = isViewTypeAux(marker, t) diff --git a/compiler/types.nim b/compiler/types.nim index 44827aa33..b9fc4d4a2 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -329,7 +329,7 @@ proc containsTyRef*(typ: PType): bool = result = searchTypeFor(typ, isTyRef) proc isHiddenPointer(t: PType): bool = - result = t.kind in {tyString, tySequence} + result = t.kind in {tyString, tySequence, tyOpenArray, tyVarargs} proc containsHiddenPointer*(typ: PType): bool = # returns true if typ contains a string, table or sequence (all the things @@ -1240,37 +1240,6 @@ proc commonSuperclass*(a, b: PType): PType = return t y = y[0] -type - TTypeAllowedFlag* = enum - taField, - taHeap, - taConcept, - taIsOpenArray, - taNoUntyped - taIsTemplateOrMacro - taProcContextIsNotMacro - - TTypeAllowedFlags* = set[TTypeAllowedFlag] - -proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, - flags: TTypeAllowedFlags = {}): PType - -proc typeAllowedNode(marker: var IntSet, n: PNode, kind: TSymKind, - flags: TTypeAllowedFlags = {}): PType = - if n != nil: - result = typeAllowedAux(marker, n.typ, kind, flags) - if result == nil: - case n.kind - of nkNone..nkNilLit: - discard - else: - #if n.kind == nkRecCase and kind in {skProc, skFunc, skConst}: - # return n[0].typ - for i in 0..<n.len: - let it = n[i] - result = typeAllowedNode(marker, it, kind, flags) - if result != nil: break - proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]], last: TTypeKind): bool = var a = a @@ -1280,143 +1249,6 @@ proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]], a = a[i] result = a.kind == last -proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, - flags: TTypeAllowedFlags = {}): PType = - assert(kind in {skVar, skLet, skConst, skProc, skFunc, skParam, skResult}) - # if we have already checked the type, return true, because we stop the - # evaluation if something is wrong: - result = nil - if typ == nil: return nil - if containsOrIncl(marker, typ.id): return nil - var t = skipTypes(typ, abstractInst-{tyTypeDesc}) - case t.kind - of tyVar, tyLent: - if kind in {skProc, skFunc, skConst}: - result = t - elif t.kind == tyLent and kind != skResult: - result = t - else: - var t2 = skipTypes(t[0], abstractInst-{tyTypeDesc}) - case t2.kind - of tyVar, tyLent: - if taHeap notin flags: result = t2 # ``var var`` is illegal on the heap - of tyOpenArray: - if kind != skParam or taIsOpenArray in flags: result = t - else: result = typeAllowedAux(marker, t2[0], kind, flags+{taIsOpenArray}) - of tyUncheckedArray: - if kind != skParam: result = t - else: result = typeAllowedAux(marker, t2[0], kind, flags) - else: - if kind notin {skParam, skResult}: result = t - else: result = typeAllowedAux(marker, t2, kind, flags) - of tyProc: - if kind in {skVar, skLet, skConst} and taIsTemplateOrMacro in flags: - result = t - else: - if isInlineIterator(typ) and kind in {skVar, skLet, skConst, skParam, skResult}: - # only closure iterators may be assigned to anything. - result = t - let f = if kind in {skProc, skFunc}: flags+{taNoUntyped} else: flags - for i in 1..<t.len: - if result != nil: break - result = typeAllowedAux(marker, t[i], skParam, f-{taIsOpenArray}) - if result.isNil and t[0] != nil: - result = typeAllowedAux(marker, t[0], skResult, flags) - of tyTypeDesc: - if kind in {skVar, skLet, skConst} and taProcContextIsNotMacro in flags: - result = t - else: - # XXX: This is still a horrible idea... - result = nil - of tyUntyped, tyTyped: - if kind notin {skParam, skResult} or taNoUntyped in flags: result = t - of tyStatic: - if kind notin {skParam}: result = t - of tyVoid: - if taField notin flags: result = t - of tyTypeClasses: - if tfGenericTypeParam in t.flags or taConcept in flags: #or taField notin flags: - discard - elif t.isResolvedUserTypeClass: - result = typeAllowedAux(marker, t.lastSon, kind, flags) - elif kind notin {skParam, skResult}: - result = t - of tyGenericBody, tyGenericParam, tyGenericInvocation, - tyNone, tyForward, tyFromExpr: - result = t - of tyNil: - if kind != skConst and kind != skParam: result = t - of tyString, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString, tyPointer: - result = nil - of tyOrdinal: - if kind != skParam: result = t - of tyGenericInst, tyDistinct, tyAlias, tyInferred: - result = typeAllowedAux(marker, lastSon(t), kind, flags) - of tyRange: - if skipTypes(t[0], abstractInst-{tyTypeDesc}).kind notin - {tyChar, tyEnum, tyInt..tyFloat128, tyInt..tyUInt64}: result = t - of tyOpenArray, tyVarargs, tySink: - # you cannot nest openArrays/sinks/etc. - if kind != skParam or taIsOpenArray in flags: - result = t - else: - result = typeAllowedAux(marker, t[0], kind, flags+{taIsOpenArray}) - of tyUncheckedArray: - if kind != skParam and taHeap notin flags: - result = t - else: - result = typeAllowedAux(marker, lastSon(t), kind, flags-{taHeap}) - of tySequence: - if t[0].kind != tyEmpty: - result = typeAllowedAux(marker, t[0], kind, flags+{taHeap}) - elif kind in {skVar, skLet}: - result = t[0] - of tyArray: - if t[1].kind == tyTypeDesc: - result = t[1] - elif t[1].kind != tyEmpty: - result = typeAllowedAux(marker, t[1], kind, flags) - elif kind in {skVar, skLet}: - result = t[1] - of tyRef: - if kind == skConst: result = t - else: result = typeAllowedAux(marker, t.lastSon, kind, flags+{taHeap}) - of tyPtr: - result = typeAllowedAux(marker, t.lastSon, kind, flags+{taHeap}) - of tySet: - for i in 0..<t.len: - result = typeAllowedAux(marker, t[i], kind, flags) - if result != nil: break - of tyObject, tyTuple: - if kind in {skProc, skFunc, skConst} and - t.kind == tyObject and t[0] != nil: - result = t - else: - let flags = flags+{taField} - for i in 0..<t.len: - result = typeAllowedAux(marker, t[i], kind, flags) - if result != nil: break - if result.isNil and t.n != nil: - result = typeAllowedNode(marker, t.n, kind, flags) - of tyEmpty: - if kind in {skVar, skLet}: result = t - of tyProxy: - # for now same as error node; we say it's a valid type as it should - # prevent cascading errors: - result = nil - of tyOwned: - if t.len == 1 and t[0].skipTypes(abstractInst).kind in {tyRef, tyPtr, tyProc}: - result = typeAllowedAux(marker, t.lastSon, kind, flags+{taHeap}) - else: - result = t - of tyOptDeprecated: doAssert false - -proc typeAllowed*(t: PType, kind: TSymKind; flags: TTypeAllowedFlags = {}): PType = - # returns 'nil' on success and otherwise the part of the type that is - # wrong! - var marker = initIntSet() - result = typeAllowedAux(marker, t, kind, flags) - include sizealignoffsetimpl proc computeSize*(conf: ConfigRef; typ: PType): BiggestInt = diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index 6cf8e1932..756249c8b 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -17,6 +17,7 @@ import ast, types, lineinfos, options, msgs, renderer from trees import getMagic, whichPragma from wordrecg import wNoSideEffect from isolation_check import canAlias +from typeallowed import isViewType type SubgraphFlag = enum @@ -48,7 +49,7 @@ type maxMutation, minConnection: int mutations: seq[int] - Partitions = object + Partitions* = object abstractTime: int s: seq[VarIndex] graphs: seq[MutationInfo] @@ -74,7 +75,7 @@ proc `$`*(config: ConfigRef; g: MutationInfo): string = result.add config $ g.connectedVia result.add " is the statement that connected the mutation to the parameter" -proc hasSideEffect(c: var Partitions; info: var MutationInfo): bool = +proc hasSideEffect*(c: var Partitions; info: var MutationInfo): bool = for g in mitems c.graphs: if g.flags == {isMutated, connectsConstParam} and mutationAfterConnection(g): info = g @@ -505,17 +506,16 @@ proc traverse(c: var Partitions; n: PNode) = else: for child in n: traverse(c, child) -proc mutatesNonVarParameters*(s: PSym; n: PNode; info: var MutationInfo): bool = - var par = Partitions(performCursorInference: false) - if s.kind != skMacro: +proc computeGraphPartitions*(s: PSym; n: PNode; cursorInference = false): Partitions = + result = Partitions(performCursorInference: cursorInference) + if s.kind notin {skModule, skMacro}: let params = s.typ.n for i in 1..<params.len: - registerVariable(par, params[i]) + registerVariable(result, params[i]) if resultPos < s.ast.safeLen: - registerVariable(par, s.ast[resultPos]) + registerVariable(result, s.ast[resultPos]) - traverse(par, n) - result = hasSideEffect(par, info) + traverse(result, n) proc dangerousMutation(g: MutationInfo; v: VarIndex): bool = if isMutated in g.flags: @@ -524,16 +524,16 @@ proc dangerousMutation(g: MutationInfo; v: VarIndex): bool = return true return false -proc computeCursors*(s: PSym; n: PNode; config: ConfigRef) = - var par = Partitions(performCursorInference: true) - if s.kind notin {skMacro, skModule}: - let params = s.typ.n - for i in 1..<params.len: - registerVariable(par, params[i]) - if resultPos < s.ast.safeLen: - registerVariable(par, s.ast[resultPos]) +proc checkBorrowedLocations*(par: var Partitions; config: ConfigRef) = + for i in 0 ..< par.s.len: + let s = par.s[i].sym + if s.kind != skParam and isViewType(s.typ): + let rid = root(par, i) + if par.s[rid].kind == isRootOf and dangerousMutation(par.graphs[par.s[rid].graphIndex], par.s[i]): + localError(config, s.info, config $ par.graphs[par.s[rid].graphIndex]) - traverse(par, n) +proc computeCursors*(s: PSym; n: PNode; config: ConfigRef) = + var par = computeGraphPartitions(s, n, true) for i in 0 ..< par.s.len: let v = addr(par.s[i]) if v.flags == {} and v.sym.kind notin {skParam, skResult} and |