diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/condsyms.nim | 1 | ||||
-rw-r--r-- | compiler/lambdalifting.nim | 2 | ||||
-rw-r--r-- | compiler/nim.cfg (renamed from compiler/nim.nim.cfg) | 0 | ||||
-rw-r--r-- | compiler/parampatterns.nim | 20 | ||||
-rw-r--r-- | compiler/rodread.nim | 2 | ||||
-rw-r--r-- | compiler/semdestruct.nim | 9 | ||||
-rw-r--r-- | compiler/semexprs.nim | 11 | ||||
-rw-r--r-- | compiler/semfold.nim | 16 | ||||
-rw-r--r-- | compiler/semgnrc.nim | 128 | ||||
-rw-r--r-- | compiler/seminst.nim | 7 | ||||
-rw-r--r-- | compiler/semmagic.nim | 6 | ||||
-rw-r--r-- | compiler/semstmts.nim | 22 | ||||
-rw-r--r-- | compiler/semtempl.nim | 23 | ||||
-rw-r--r-- | compiler/semtypes.nim | 5 | ||||
-rw-r--r-- | compiler/transf.nim | 83 | ||||
-rw-r--r-- | compiler/vm.nim | 2 | ||||
-rw-r--r-- | compiler/vmgen.nim | 5 |
17 files changed, 230 insertions, 112 deletions
diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index aecbde66e..297b865b2 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -90,3 +90,4 @@ proc initDefines*() = defineSymbol("nimnode") defineSymbol("nimnomagic64") defineSymbol("nimvarargstyped") + defineSymbol("nimtypedescfixed") diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index d11776cf6..c669fc745 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -184,7 +184,7 @@ proc addHiddenParam(routine: PSym, param: PSym) = var params = routine.ast.sons[paramsPos] # -1 is correct here as param.position is 0 based but we have at position 0 # some nkEffect node: - param.position = params.len-1 + param.position = routine.typ.n.len-1 addSon(params, newSymNode(param)) incl(routine.typ.flags, tfCapturesEnv) assert sfFromGeneric in param.flags diff --git a/compiler/nim.nim.cfg b/compiler/nim.cfg index 64631a437..64631a437 100644 --- a/compiler/nim.nim.cfg +++ b/compiler/nim.cfg diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim index b7fe269df..ae391945a 100644 --- a/compiler/parampatterns.nim +++ b/compiler/parampatterns.nim @@ -178,13 +178,14 @@ type arDiscriminant, # is a discriminant arStrange # it is a strange beast like 'typedesc[var T]' -proc isAssignable*(owner: PSym, n: PNode): TAssignableResult = +proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult = ## 'owner' can be nil! result = arNone case n.kind of nkSym: - # don't list 'skLet' here: - if n.sym.kind in {skVar, skResult, skTemp}: + let kinds = if isUnsafeAddr: {skVar, skResult, skTemp, skParam, skLet} + else: {skVar, skResult, skTemp} + if n.sym.kind in kinds: if owner != nil and owner.id == n.sym.owner.id and sfGlobal notin n.sym.flags: result = arLocalLValue @@ -200,7 +201,7 @@ proc isAssignable*(owner: PSym, n: PNode): TAssignableResult = {tyVar, tyPtr, tyRef}: result = arLValue else: - result = isAssignable(owner, n.sons[0]) + result = isAssignable(owner, n.sons[0], isUnsafeAddr) if result != arNone and sfDiscriminant in n.sons[1].sym.flags: result = arDiscriminant of nkBracketExpr: @@ -208,23 +209,24 @@ proc isAssignable*(owner: PSym, n: PNode): TAssignableResult = {tyVar, tyPtr, tyRef}: result = arLValue else: - result = isAssignable(owner, n.sons[0]) + result = isAssignable(owner, n.sons[0], isUnsafeAddr) of nkHiddenStdConv, nkHiddenSubConv, nkConv: # Object and tuple conversions are still addressable, so we skip them # XXX why is 'tyOpenArray' allowed here? if skipTypes(n.typ, abstractPtrs-{tyTypeDesc}).kind in {tyOpenArray, tyTuple, tyObject}: - result = isAssignable(owner, n.sons[1]) + result = isAssignable(owner, n.sons[1], isUnsafeAddr) elif compareTypes(n.typ, n.sons[1].typ, dcEqIgnoreDistinct): # types that are equal modulo distinction preserve l-value: - result = isAssignable(owner, n.sons[1]) + result = isAssignable(owner, n.sons[1], isUnsafeAddr) of nkHiddenDeref, nkDerefExpr, nkHiddenAddr: result = arLValue of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr: - result = isAssignable(owner, n.sons[0]) + result = isAssignable(owner, n.sons[0], isUnsafeAddr) of nkCallKinds: # builtin slice keeps lvalue-ness: - if getMagic(n) == mSlice: result = isAssignable(owner, n.sons[1]) + if getMagic(n) == mSlice: + result = isAssignable(owner, n.sons[1], isUnsafeAddr) else: discard diff --git a/compiler/rodread.nim b/compiler/rodread.nim index 92ce00240..e4530c2cc 100644 --- a/compiler/rodread.nim +++ b/compiler/rodread.nim @@ -898,6 +898,8 @@ proc getBody*(s: PSym): PNode = ## it may perform an expensive reload operation. Otherwise it's a simple ## accessor. assert s.kind in routineKinds + # prevent crashes due to incorrect macro transformations (bug #2377) + if s.ast.isNil or bodyPos >= s.ast.len: return ast.emptyNode result = s.ast.sons[bodyPos] if result == nil: assert s.offset != 0 diff --git a/compiler/semdestruct.nim b/compiler/semdestruct.nim index aaab49a10..af671f6e0 100644 --- a/compiler/semdestruct.nim +++ b/compiler/semdestruct.nim @@ -177,6 +177,15 @@ proc instantiateDestructor(c: PContext, typ: PType): PType = else: return nil +proc createDestructorCall(c: PContext, s: PSym): PNode = + let varTyp = s.typ + if varTyp == nil or sfGlobal in s.flags: return + let destructableT = instantiateDestructor(c, varTyp) + if destructableT != nil: + let call = semStmt(c, newNode(nkCall, s.info, @[ + useSym(destructableT.destructor), useSym(s)])) + result = newNode(nkDefer, s.info, @[call]) + proc insertDestructors(c: PContext, varSection: PNode): tuple[outer, inner: PNode] = # Accepts a var or let section. diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index fba64776d..0e9b9ae5f 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -597,8 +597,8 @@ proc skipObjConv(n: PNode): PNode = of nkObjUpConv, nkObjDownConv: result = n.sons[0] else: result = n -proc isAssignable(c: PContext, n: PNode): TAssignableResult = - result = parampatterns.isAssignable(c.p.owner, n) +proc isAssignable(c: PContext, n: PNode; isUnsafeAddr=false): TAssignableResult = + result = parampatterns.isAssignable(c.p.owner, n, isUnsafeAddr) proc newHiddenAddrTaken(c: PContext, n: PNode): PNode = if n.kind == nkHiddenDeref and not (gCmd == cmdCompileToCpp or @@ -1700,7 +1700,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = case s.magic # magics that need special treatment of mAddr: checkSonsLen(n, 2) - result = semAddr(c, n.sons[1]) + result = semAddr(c, n.sons[1], s.name.s == "unsafeAddr") of mTypeOf: checkSonsLen(n, 2) result = semTypeOf(c, n.sons[1]) @@ -2259,7 +2259,10 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = of nkStaticStmt: result = semStaticStmt(c, n) of nkDefer: - localError(n.info, errGenerated, "'defer' not allowed in this context") + n.sons[0] = semExpr(c, n.sons[0]) + if not n.sons[0].typ.isEmptyType and not implicitlyDiscardable(n.sons[0]): + localError(n.info, errGenerated, "'defer' takes a 'void' expression") + #localError(n.info, errGenerated, "'defer' not allowed in this context") else: localError(n.info, errInvalidExpressionX, renderTree(n, {renderNoComments})) diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 729222220..2ab43a9c9 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -307,12 +307,12 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode = of mToU8: result = newIntNodeT(getInt(a) and 0x000000FF, n) of mToU16: result = newIntNodeT(getInt(a) and 0x0000FFFF, n) of mToU32: result = newIntNodeT(getInt(a) and 0x00000000FFFFFFFF'i64, n) - of mUnaryLt: result = newIntNodeT(getOrdValue(a) - 1, n) - of mSucc: result = newIntNodeT(getOrdValue(a) + getInt(b), n) - of mPred: result = newIntNodeT(getOrdValue(a) - getInt(b), n) - of mAddI: result = newIntNodeT(getInt(a) + getInt(b), n) - of mSubI: result = newIntNodeT(getInt(a) - getInt(b), n) - of mMulI: result = newIntNodeT(getInt(a) * getInt(b), n) + of mUnaryLt: result = newIntNodeT(getOrdValue(a) |-| 1, n) + of mSucc: result = newIntNodeT(getOrdValue(a) |+| getInt(b), n) + of mPred: result = newIntNodeT(getOrdValue(a) |-| getInt(b), n) + of mAddI: result = newIntNodeT(getInt(a) |+| getInt(b), n) + of mSubI: result = newIntNodeT(getInt(a) |-| getInt(b), n) + of mMulI: result = newIntNodeT(getInt(a) |*| getInt(b), n) of mMinI: if getInt(a) > getInt(b): result = newIntNodeT(getInt(b), n) else: result = newIntNodeT(getInt(a), n) @@ -338,11 +338,11 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode = of mDivI: let y = getInt(b) if y != 0: - result = newIntNodeT(getInt(a) div y, n) + result = newIntNodeT(`|div|`(getInt(a), y), n) of mModI: let y = getInt(b) if y != 0: - result = newIntNodeT(getInt(a) mod y, n) + result = newIntNodeT(`|mod|`(getInt(a), y), n) of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n) of mSubF64: result = newFloatNodeT(getFloat(a) - getFloat(b), n) of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n) diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index db910600b..e3b598919 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -39,9 +39,9 @@ type proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags, ctx: var GenericCtx): PNode -proc semGenericStmtScope(c: PContext, n: PNode, +proc semGenericStmtScope(c: PContext, n: PNode, flags: TSemGenericFlags, - ctx: var GenericCtx): PNode = + ctx: var GenericCtx): PNode = openScope(c) result = semGenericStmt(c, n, flags, ctx) closeScope(c) @@ -57,7 +57,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, of skUnknown: # Introduced in this pass! Leave it as an identifier. result = n - of skProc, skMethod, skIterators, skConverter: + of skProc, skMethod, skIterators, skConverter, skModule: result = symChoice(c, n, s, scOpen) of skTemplate: if macroToExpand(s): @@ -73,7 +73,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, result = semGenericStmt(c, result, {}, ctx) else: result = symChoice(c, n, s, scOpen) - of skGenericParam: + of skGenericParam: if s.typ != nil and s.typ.kind == tyStatic: if s.typ.n != nil: result = s.typ.n @@ -85,18 +85,18 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, of skParam: result = n styleCheckUse(n.info, s) - of skType: + of skType: if (s.typ != nil) and (s.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} == {}): result = newSymNodeTypeDesc(s, n.info) - else: + else: result = n styleCheckUse(n.info, s) else: result = newSymNode(s, n.info) styleCheckUse(n.info, s) -proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags, +proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags, ctx: var GenericCtx): PNode = result = n let ident = considerQuotedIdent(n) @@ -118,13 +118,13 @@ proc newDot(n, b: PNode): PNode = result.add(n.sons[0]) result.add(b) -proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags, +proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags, ctx: var GenericCtx; isMacro: var bool): PNode = assert n.kind == nkDotExpr semIdeForTemplateOrGenericCheck(n, ctx.cursorInBody) let luf = if withinMixin notin flags: {checkUndeclared} else: {} - + var s = qualifiedLookUp(c, n, luf) if s != nil: result = semGenericStmtSymbol(c, n, s, ctx) @@ -141,18 +141,20 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags, elif s.name.id in ctx.toMixin: result = newDot(result, symChoice(c, n, s, scForceOpen)) else: - let sym = semGenericStmtSymbol(c, n, s, ctx) - if sym.kind == nkSym: - result = newDot(result, symChoice(c, n, s, scForceOpen)) + let syms = semGenericStmtSymbol(c, n, s, ctx) + if syms.kind == nkSym: + let choice = symChoice(c, n, s, scForceOpen) + choice.kind = nkClosedSymChoice + result = newDot(result, choice) else: - result = newDot(result, sym) + result = newDot(result, syms) proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) = let s = newSymS(skUnknown, getIdentNode(n), c) addPrelimDecl(c, s) styleCheckDef(n.info, s, kind) -proc semGenericStmt(c: PContext, n: PNode, +proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags, ctx: var GenericCtx): PNode = result = n #if gCmd == cmdIdeTools: suggestStmt(c, n) @@ -181,16 +183,16 @@ proc semGenericStmt(c: PContext, n: PNode, result = semGenericStmt(c, n.sons[0], flags+{withinBind}, ctx) of nkMixinStmt: result = semMixinStmt(c, n, ctx.toMixin) - of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkCommand, nkCallStrLit: + of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkCommand, nkCallStrLit: # check if it is an expression macro: checkMinSonsLen(n, 1) let fn = n.sons[0] var s = qualifiedLookUp(c, fn, {}) if s == nil and withinMixin notin flags and - fn.kind in {nkIdent, nkAccQuoted} and + fn.kind in {nkIdent, nkAccQuoted} and considerQuotedIdent(fn).id notin ctx.toMixin: localError(n.info, errUndeclaredIdentifier, fn.renderTree) - + var first = 0 var mixinContext = false if s != nil: @@ -220,19 +222,19 @@ proc semGenericStmt(c: PContext, n: PNode, # we need to put the ``c`` in ``t(c)`` in a mixin context to prevent # the famous "undeclared identifier: it" bug: mixinContext = true - of skUnknown, skParam: + of skUnknown, skParam: # Leave it as an identifier. discard - of skProc, skMethod, skIterators, skConverter: + of skProc, skMethod, skIterators, skConverter, skModule: result.sons[0] = symChoice(c, fn, s, scOption) first = 1 of skGenericParam: result.sons[0] = newSymNodeTypeDesc(s, fn.info) styleCheckUse(fn.info, s) first = 1 - of skType: + of skType: # bad hack for generics: - if (s.typ != nil) and (s.typ.kind != tyGenericParam): + if (s.typ != nil) and (s.typ.kind != tyGenericParam): result.sons[0] = newSymNodeTypeDesc(s, fn.info) styleCheckUse(fn.info, s) first = 1 @@ -244,34 +246,34 @@ proc semGenericStmt(c: PContext, n: PNode, result.sons[0] = fuzzyLookup(c, fn, flags, ctx, mixinContext) first = 1 # Consider 'when declared(globalsSlot): ThreadVarSetValue(globalsSlot, ...)' - # in threads.nim: the subtle preprocessing here binds 'globalsSlot' which + # in threads.nim: the subtle preprocessing here binds 'globalsSlot' which # is not exported and yet the generic 'threadProcWrapper' works correctly. let flags = if mixinContext: flags+{withinMixin} else: flags for i in countup(first, sonsLen(result) - 1): result.sons[i] = semGenericStmt(c, result.sons[i], flags, ctx) - of nkIfStmt: - for i in countup(0, sonsLen(n)-1): + of nkIfStmt: + for i in countup(0, sonsLen(n)-1): n.sons[i] = semGenericStmtScope(c, n.sons[i], flags, ctx) of nkWhenStmt: for i in countup(0, sonsLen(n)-1): n.sons[i] = semGenericStmt(c, n.sons[i], flags+{withinMixin}, ctx) - of nkWhileStmt: + of nkWhileStmt: openScope(c) - for i in countup(0, sonsLen(n)-1): + for i in countup(0, sonsLen(n)-1): n.sons[i] = semGenericStmt(c, n.sons[i], flags, ctx) closeScope(c) - of nkCaseStmt: + of nkCaseStmt: openScope(c) n.sons[0] = semGenericStmt(c, n.sons[0], flags, ctx) - for i in countup(1, sonsLen(n)-1): + for i in countup(1, sonsLen(n)-1): var a = n.sons[i] checkMinSonsLen(a, 1) var L = sonsLen(a) - for j in countup(0, L-2): + for j in countup(0, L-2): a.sons[j] = semGenericStmt(c, a.sons[j], flags, ctx) a.sons[L - 1] = semGenericStmtScope(c, a.sons[L-1], flags, ctx) closeScope(c) - of nkForStmt, nkParForStmt: + of nkForStmt, nkParForStmt: var L = sonsLen(n) openScope(c) n.sons[L - 2] = semGenericStmt(c, n.sons[L-2], flags, ctx) @@ -279,27 +281,27 @@ proc semGenericStmt(c: PContext, n: PNode, addTempDecl(c, n.sons[i], skForVar) n.sons[L - 1] = semGenericStmt(c, n.sons[L-1], flags, ctx) closeScope(c) - of nkBlockStmt, nkBlockExpr, nkBlockType: + of nkBlockStmt, nkBlockExpr, nkBlockType: checkSonsLen(n, 2) openScope(c) - if n.sons[0].kind != nkEmpty: + if n.sons[0].kind != nkEmpty: addTempDecl(c, n.sons[0], skLabel) n.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx) closeScope(c) - of nkTryStmt: + of nkTryStmt: checkMinSonsLen(n, 2) n.sons[0] = semGenericStmtScope(c, n.sons[0], flags, ctx) - for i in countup(1, sonsLen(n)-1): + for i in countup(1, sonsLen(n)-1): var a = n.sons[i] checkMinSonsLen(a, 1) var L = sonsLen(a) - for j in countup(0, L-2): + for j in countup(0, L-2): a.sons[j] = semGenericStmt(c, a.sons[j], flags+{withinTypeDesc}, ctx) a.sons[L-1] = semGenericStmtScope(c, a.sons[L-1], flags, ctx) - of nkVarSection, nkLetSection: - for i in countup(0, sonsLen(n) - 1): + of nkVarSection, nkLetSection: + for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] - if a.kind == nkCommentStmt: continue + if a.kind == nkCommentStmt: continue if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): illFormedAst(a) checkMinSonsLen(a, 3) var L = sonsLen(a) @@ -307,49 +309,49 @@ proc semGenericStmt(c: PContext, n: PNode, a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx) for j in countup(0, L-3): addTempDecl(c, getIdentNode(a.sons[j]), skVar) - of nkGenericParams: - for i in countup(0, sonsLen(n) - 1): + of nkGenericParams: + for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] if (a.kind != nkIdentDefs): illFormedAst(a) checkMinSonsLen(a, 3) var L = sonsLen(a) - a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx) - # do not perform symbol lookup for default expressions - for j in countup(0, L-3): + a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx) + # do not perform symbol lookup for default expressions + for j in countup(0, L-3): addTempDecl(c, getIdentNode(a.sons[j]), skType) - of nkConstSection: - for i in countup(0, sonsLen(n) - 1): + of nkConstSection: + for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] - if a.kind == nkCommentStmt: continue + if a.kind == nkCommentStmt: continue if (a.kind != nkConstDef): illFormedAst(a) checkSonsLen(a, 3) addTempDecl(c, getIdentNode(a.sons[0]), skConst) a.sons[1] = semGenericStmt(c, a.sons[1], flags+{withinTypeDesc}, ctx) a.sons[2] = semGenericStmt(c, a.sons[2], flags, ctx) of nkTypeSection: - for i in countup(0, sonsLen(n) - 1): + for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] - if a.kind == nkCommentStmt: continue + if a.kind == nkCommentStmt: continue if (a.kind != nkTypeDef): illFormedAst(a) checkSonsLen(a, 3) addTempDecl(c, getIdentNode(a.sons[0]), skType) - for i in countup(0, sonsLen(n) - 1): + for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] - if a.kind == nkCommentStmt: continue + if a.kind == nkCommentStmt: continue if (a.kind != nkTypeDef): illFormedAst(a) checkSonsLen(a, 3) - if a.sons[1].kind != nkEmpty: + if a.sons[1].kind != nkEmpty: openScope(c) a.sons[1] = semGenericStmt(c, a.sons[1], flags, ctx) a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc}, ctx) closeScope(c) - else: + else: a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc}, ctx) - of nkEnumTy: + of nkEnumTy: if n.sonsLen > 0: - if n.sons[0].kind != nkEmpty: + if n.sons[0].kind != nkEmpty: n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, ctx) - for i in countup(1, sonsLen(n) - 1): + for i in countup(1, sonsLen(n) - 1): var a: PNode case n.sons[i].kind of nkEnumFieldDef: a = n.sons[i].sons[0] @@ -360,26 +362,26 @@ proc semGenericStmt(c: PContext, n: PNode, discard of nkFormalParams: checkMinSonsLen(n, 1) - if n.sons[0].kind != nkEmpty: + if n.sons[0].kind != nkEmpty: n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, ctx) - for i in countup(1, sonsLen(n) - 1): + for i in countup(1, sonsLen(n) - 1): var a = n.sons[i] if (a.kind != nkIdentDefs): illFormedAst(a) checkMinSonsLen(a, 3) var L = sonsLen(a) a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx) a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx) - for j in countup(0, L-3): + for j in countup(0, L-3): addTempDecl(c, getIdentNode(a.sons[j]), skParam) - of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef, - nkIteratorDef, nkLambdaKinds: + of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef, + nkIteratorDef, nkLambdaKinds: checkSonsLen(n, bodyPos + 1) if n.sons[namePos].kind != nkEmpty: addTempDecl(c, getIdentNode(n.sons[0]), skProc) openScope(c) - n.sons[genericParamsPos] = semGenericStmt(c, n.sons[genericParamsPos], + n.sons[genericParamsPos] = semGenericStmt(c, n.sons[genericParamsPos], flags, ctx) - if n.sons[paramsPos].kind != nkEmpty: + if n.sons[paramsPos].kind != nkEmpty: if n.sons[paramsPos].sons[0].kind != nkEmpty: addPrelimDecl(c, newSym(skUnknown, getIdent("result"), nil, n.info)) n.sons[paramsPos] = semGenericStmt(c, n.sons[paramsPos], flags, ctx) @@ -394,7 +396,7 @@ proc semGenericStmt(c: PContext, n: PNode, checkMinSonsLen(n, 2) result.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx) else: - for i in countup(0, sonsLen(n) - 1): + for i in countup(0, sonsLen(n) - 1): result.sons[i] = semGenericStmt(c, n.sons[i], flags, ctx) proc semGenericStmt(c: PContext, n: PNode): PNode = diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 6ba107916..370990326 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -221,13 +221,14 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, # NOTE: for access of private fields within generics from a different module # we set the friend module: c.friendModules.add(getModule(fn)) - #let oldScope = c.currentScope - #c.currentScope = fn.scope + let oldScope = c.currentScope + while not isTopLevel(c): c.currentScope = c.currentScope.parent result = copySym(fn, false) incl(result.flags, sfFromGeneric) result.owner = fn result.ast = n pushOwner(result) + openScope(c) let gp = n.sons[genericParamsPos] internalAssert gp.kind != nkEmpty @@ -265,7 +266,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, popInfoContext() closeScope(c) # close scope for parameters popOwner() - #c.currentScope = oldScope + c.currentScope = oldScope discard c.friendModules.pop() dec(c.instCounter) if result.kind == skMethod: finishMethod(c, result) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 0a7846f1d..0afbf1f07 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -10,10 +10,10 @@ # This include file implements the semantic checking for magics. # included from sem.nim -proc semAddr(c: PContext; n: PNode): PNode = +proc semAddr(c: PContext; n: PNode; isUnsafeAddr=false): PNode = result = newNodeI(nkAddr, n.info) let x = semExprWithType(c, n) - if isAssignable(c, x) notin {arLValue, arLocalLValue}: + if isAssignable(c, x, isUnsafeAddr) notin {arLValue, arLocalLValue}: localError(n.info, errExprHasNoAddress) result.add x result.typ = makePtrType(c, x.typ) @@ -119,7 +119,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, case n[0].sym.magic of mAddr: checkSonsLen(n, 2) - result = semAddr(c, n.sons[1]) + result = semAddr(c, n.sons[1], n[0].sym.name.s == "unsafeAddr") of mTypeOf: checkSonsLen(n, 2) result = semTypeOf(c, n.sons[1]) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 84a09a7e6..3d9363d77 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -369,6 +369,15 @@ proc addToVarSection(c: PContext; result: var PNode; orig, identDefs: PNode) = else: result.add identDefs +proc addDefer(c: PContext; result: var PNode; s: PSym) = + let deferDestructorCall = createDestructorCall(c, s) + if deferDestructorCall != nil: + if result.kind != nkStmtList: + let oldResult = result + result = newNodeI(nkStmtList, result.info) + result.add oldResult + result.add deferDestructorCall + proc isDiscardUnderscore(v: PSym): bool = if v.name.s == "_": v.flags.incl(sfGenSym) @@ -469,6 +478,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = if def.kind == nkPar: v.ast = def[j] v.typ = tup.sons[j] b.sons[j] = newSymNode(v) + addDefer(c, result, v) checkNilable(v) if sfCompileTime in v.flags: hasCompileTime = true if hasCompileTime: vm.setupCompileTimeVar(c.module, result) @@ -1371,7 +1381,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode = for i in countup(0, length - 1): let k = n.sons[i].kind case k - of nkFinally, nkExceptBranch, nkDefer: + of nkFinally, nkExceptBranch: # stand-alone finally and except blocks are # transformed into regular try blocks: # @@ -1424,21 +1434,13 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode = n.typ = n.sons[i].typ if not isEmptyType(n.typ): n.kind = nkStmtListExpr case n.sons[i].kind - of nkVarSection, nkLetSection: - let (outer, inner) = insertDestructors(c, n.sons[i]) - if outer != nil: - n.sons[i] = outer - var rest = newNode(nkStmtList, n.info, n.sons[i+1 .. length-1]) - inner.addSon(semStmtList(c, rest, flags)) - n.sons.setLen(i+1) - return of LastBlockStmts: for j in countup(i + 1, length - 1): case n.sons[j].kind of nkPragma, nkCommentStmt, nkNilLit, nkEmpty: discard else: localError(n.sons[j].info, errStmtInvalidAfterReturn) else: discard - if result.len == 1: + if result.len == 1 and result.sons[0].kind != nkDefer: result = result.sons[0] when defined(nimfix): if result.kind == nkCommentStmt and not result.comment.isNil and diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index a138981b7..4d1eae48f 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -184,10 +184,25 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) = else: let ident = getIdentNode(c, n) if not isTemplParam(c, ident): - let local = newGenSym(k, ident, c) - addPrelimDecl(c.c, local) - styleCheckDef(n.info, local) - replaceIdentBySym(n, newSymNode(local, n.info)) + # fix #2670, consider: + # + # when b: + # var a = "hi" + # else: + # var a = 5 + # echo a + # + # We need to ensure that both 'a' produce the same gensym'ed symbol. + # So we need only check the *current* scope. + let s = localSearchInScope(c.c, considerQuotedIdent ident) + if s != nil and s.owner == c.owner and sfGenSym in s.flags: + styleCheckUse(n.info, s) + replaceIdentBySym(n, newSymNode(s, n.info)) + else: + let local = newGenSym(k, ident, c) + addPrelimDecl(c.c, local) + styleCheckDef(n.info, local) + replaceIdentBySym(n, newSymNode(local, n.info)) else: replaceIdentBySym(n, ident) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 3bb1284fc..5ae3d16c0 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -508,8 +508,9 @@ proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int, var typ = skipTypes(a.sons[0].typ, abstractVar-{tyTypeDesc}) if not isOrdinalType(typ): localError(n.info, errSelectorMustBeOrdinal) - elif firstOrd(typ) < 0: - localError(n.info, errOrdXMustNotBeNegative, a.sons[0].sym.name.s) + elif firstOrd(typ) != 0: + localError(n.info, errGenerated, "low(" & $a.sons[0].sym.name.s & + ") must be 0 for discriminant") elif lengthOrd(typ) > 0x00007FFF: localError(n.info, errLenXinvalid, a.sons[0].sym.name.s) var chckCovered = true diff --git a/compiler/transf.nim b/compiler/transf.nim index dddbd51c4..5c7472a39 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -16,6 +16,7 @@ # * converts "continue" to "break"; disambiguates "break" # * introduces method dispatchers # * performs lambda lifting for closure support +# * transforms 'defer' into a 'try finally' statement import intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os, @@ -44,6 +45,7 @@ type inlining: int # > 0 if we are in inlining context (copy vars) nestedProcs: int # > 0 if we are in a nested proc contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break' + deferDetected: bool PTransf = ref TTransfContext proc newTransNode(a: PNode): PTransNode {.inline.} = @@ -680,6 +682,14 @@ proc commonOptimizations*(c: PSym, n: PNode): PNode = result = n proc transform(c: PTransf, n: PNode): PTransNode = + when false: + var oldDeferAnchor: PNode + if n.kind in {nkElifBranch, nkOfBranch, nkExceptBranch, nkElifExpr, + nkElseExpr, nkElse, nkForStmt, nkWhileStmt, nkFinally, + nkBlockStmt, nkBlockExpr}: + oldDeferAnchor = c.deferAnchor + c.deferAnchor = n + case n.kind of nkSym: result = transformSym(c, n) @@ -712,13 +722,36 @@ proc transform(c: PTransf, n: PNode): PTransNode = result = transformFor(c, n) of nkParForStmt: result = transformSons(c, n) - of nkCaseStmt: result = transformCase(c, n) + of nkCaseStmt: + result = transformCase(c, n) + of nkWhileStmt: result = transformWhile(c, n) + of nkBlockStmt, nkBlockExpr: + result = transformBlock(c, n) + of nkDefer: + c.deferDetected = true + result = transformSons(c, n) + when false: + let deferPart = newNodeI(nkFinally, n.info) + deferPart.add n.sons[0] + let tryStmt = newNodeI(nkTryStmt, n.info) + if c.deferAnchor.isNil: + tryStmt.add c.root + c.root = tryStmt + result = PTransNode(tryStmt) + else: + # modify the corresponding *action*, don't rely on nkStmtList: + let L = c.deferAnchor.len-1 + tryStmt.add c.deferAnchor.sons[L] + c.deferAnchor.sons[L] = tryStmt + result = newTransNode(nkCommentStmt, n.info, 0) + tryStmt.addSon(deferPart) + # disable the original 'defer' statement: + n.kind = nkCommentStmt of nkContinueStmt: result = PTransNode(newNodeI(nkBreakStmt, n.info)) var labl = c.contSyms[c.contSyms.high] add(result, PTransNode(newSymNode(labl))) of nkBreakStmt: result = transformBreak(c, n) - of nkWhileStmt: result = transformWhile(c, n) of nkCallKinds: result = transformCall(c, n) of nkAddr, nkHiddenAddr: @@ -754,8 +787,6 @@ proc transform(c: PTransf, n: PNode): PTransNode = result = transformYield(c, n) else: result = transformSons(c, n) - of nkBlockStmt, nkBlockExpr: - result = transformBlock(c, n) of nkIdentDefs, nkConstDef: result = transformSons(c, n) # XXX comment handling really sucks: @@ -764,6 +795,8 @@ proc transform(c: PTransf, n: PNode): PTransNode = of nkClosure: return PTransNode(n) else: result = transformSons(c, n) + when false: + if oldDeferAnchor != nil: c.deferAnchor = oldDeferAnchor var cnst = getConstExpr(c.module, PNode(result)) # we inline constants if they are not complex constants: if cnst != nil and not dontInlineConstant(n, cnst): @@ -785,12 +818,52 @@ proc openTransf(module: PSym, filename: string): PTransf = result.breakSyms = @[] result.module = module +proc flattenStmts(n: PNode) = + var goOn = true + while goOn: + goOn = false + for i in 0..<n.len: + let it = n[i] + if it.kind in {nkStmtList, nkStmtListExpr}: + n.sons[i..i] = it.sons[0..<it.len] + goOn = true + +proc liftDeferAux(n: PNode) = + if n.kind in {nkStmtList, nkStmtListExpr}: + flattenStmts(n) + var goOn = true + while goOn: + goOn = false + let last = n.len-1 + for i in 0..last: + if n.sons[i].kind == nkDefer: + let deferPart = newNodeI(nkFinally, n.sons[i].info) + deferPart.add n.sons[i].sons[0] + var tryStmt = newNodeI(nkTryStmt, n.sons[i].info) + var body = newNodeI(n.kind, n.sons[i].info) + if i < last: + body.sons = n.sons[(i+1)..last] + tryStmt.addSon(body) + tryStmt.addSon(deferPart) + n.sons[i] = tryStmt + n.sons.setLen(i+1) + n.typ = n.sons[i].typ + goOn = true + break + for i in 0..n.safeLen-1: + liftDeferAux(n.sons[i]) + +template liftDefer(c, root) = + if c.deferDetected: + liftDeferAux(root) + proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode = if nfTransf in n.flags or prc.kind in {skTemplate}: result = n else: var c = openTransf(module, "") result = processTransf(c, n, prc) + liftDefer(c, result) result = liftLambdas(prc, result) #if prc.kind == skClosureIterator: # result = lambdalifting.liftIterator(prc, result) @@ -805,6 +878,7 @@ proc transformStmt*(module: PSym, n: PNode): PNode = else: var c = openTransf(module, "") result = processTransf(c, n, module) + liftDefer(c, result) result = liftLambdasForTopLevel(module, result) incl(result.flags, nfTransf) when useEffectSystem: trackTopLevelStmt(module, result) @@ -815,4 +889,5 @@ proc transformExpr*(module: PSym, n: PNode): PNode = else: var c = openTransf(module, "") result = processTransf(c, n, module) + liftDefer(c, result) incl(result.flags, nfTransf) diff --git a/compiler/vm.nim b/compiler/vm.nim index a51087aa6..b1d71d73b 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -432,7 +432,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = assert regs[rb].kind == rkNode let nb = regs[rb].node case nb.kind - of nkCharLit..nkInt64Lit: + of nkCharLit..nkUInt64Lit: ensureKind(rkInt) regs[ra].intVal = nb.intVal of nkFloatLit..nkFloat64Lit: diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index c75027e16..858ec203e 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1106,6 +1106,8 @@ proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode; # nkAddr we must not use 'unneededIndirection', but for deref we use it. if not isAddr and unneededIndirection(n.sons[0]): gen(c, n.sons[0], dest, newflags) + if gfAddrOf notin flags and fitsRegister(n.typ): + c.gABC(n, opcNodeToReg, dest, dest) elif isAddr and isGlobal(n.sons[0]): gen(c, n.sons[0], dest, flags+{gfAddrOf}) else: @@ -1183,6 +1185,9 @@ proc checkCanEval(c: PCtx; n: PNode) = if s.kind in {skVar, skTemp, skLet, skParam, skResult} and not s.isOwnedBy(c.prc.sym) and s.owner != c.module: cannotEval(n) + elif s.kind in {skProc, skConverter, skMethod, + skIterator, skClosureIterator} and sfForward in s.flags: + cannotEval(n) proc isTemp(c: PCtx; dest: TDest): bool = result = dest >= 0 and c.prc.slots[dest].kind >= slotTempUnknown |