diff options
Diffstat (limited to 'compiler/semstmts.nim')
-rw-r--r-- | compiler/semstmts.nim | 209 |
1 files changed, 46 insertions, 163 deletions
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index c6906d98e..1396ef374 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -263,7 +263,8 @@ proc semTry(c: PContext, n: PNode): PNode = n.sons[0] = semExprBranchScope(c, n.sons[0]) typ = commonType(typ, n.sons[0].typ) var check = initIntSet() - for i in countup(1, sonsLen(n) - 1): + var last = sonsLen(n) - 1 + for i in countup(1, last): var a = n.sons[i] checkMinSonsLen(a, 1) var length = sonsLen(a) @@ -282,11 +283,12 @@ proc semTry(c: PContext, n: PNode): PNode = a.sons[j].typ = typ if containsOrIncl(check, typ.id): localError(a.sons[j].info, errExceptionAlreadyHandled) - elif a.kind != nkFinally: + elif a.kind != nkFinally: illFormedAst(n) # last child of an nkExcept/nkFinally branch is a statement: a.sons[length-1] = semExprBranchScope(c, a.sons[length-1]) - typ = commonType(typ, a.sons[length-1].typ) + if a.kind != nkFinally: typ = commonType(typ, a.sons[length-1].typ) + else: dec last dec c.p.inTryStmt if isEmptyType(typ) or typ.kind == tyNil: discardCheck(c, n.sons[0]) @@ -294,13 +296,14 @@ proc semTry(c: PContext, n: PNode): PNode = if typ == enforceVoidContext: result.typ = enforceVoidContext else: + if n.lastSon.kind == nkFinally: discardCheck(c, n.lastSon.lastSon) n.sons[0] = fitNode(c, typ, n.sons[0]) - for i in 1..n.len-1: + for i in 1..last: var it = n.sons[i] let j = it.len-1 it.sons[j] = fitNode(c, typ, it.sons[j]) result.typ = typ - + proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode = result = fitNode(c, typ, n) if result.kind in {nkHiddenStdConv, nkHiddenSubConv}: @@ -364,6 +367,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = # BUGFIX: ``fitNode`` is needed here! # check type compability between def.typ and typ def = fitNode(c, typ, def) + #changeType(def.skipConv, typ, check=true) else: typ = skipIntLit(def.typ) if typ.kind in {tySequence, tyArray, tySet} and @@ -465,153 +469,7 @@ proc semConst(c: PContext, n: PNode): PNode = addSon(b, copyTree(def)) addSon(result, b) -type - TFieldInstCtx = object # either 'tup[i]' or 'field' is valid - tupleType: PType # if != nil we're traversing a tuple - tupleIndex: int - field: PSym - replaceByFieldName: bool - -proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode = - case n.kind - of nkEmpty..pred(nkIdent), succ(nkIdent)..nkNilLit: result = n - of nkIdent: - result = n - var L = sonsLen(forLoop) - if c.replaceByFieldName: - if n.ident.id == forLoop[0].ident.id: - let fieldName = if c.tupleType.isNil: c.field.name.s - elif c.tupleType.n.isNil: "Field" & $c.tupleIndex - else: c.tupleType.n.sons[c.tupleIndex].sym.name.s - result = newStrNode(nkStrLit, fieldName) - return - # other fields: - for i in ord(c.replaceByFieldName)..L-3: - if n.ident.id == forLoop[i].ident.id: - var call = forLoop.sons[L-2] - var tupl = call.sons[i+1-ord(c.replaceByFieldName)] - if c.field.isNil: - result = newNodeI(nkBracketExpr, n.info) - result.add(tupl) - result.add(newIntNode(nkIntLit, c.tupleIndex)) - else: - result = newNodeI(nkDotExpr, n.info) - result.add(tupl) - result.add(newSymNode(c.field, n.info)) - break - else: - if n.kind == nkContinueStmt: - localError(n.info, errGenerated, - "'continue' not supported in a 'fields' loop") - result = copyNode(n) - newSons(result, sonsLen(n)) - for i in countup(0, sonsLen(n)-1): - result.sons[i] = instFieldLoopBody(c, n.sons[i], forLoop) - -type - TFieldsCtx = object - c: PContext - m: TMagic - -proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) = - case typ.kind - of nkSym: - var fc: TFieldInstCtx # either 'tup[i]' or 'field' is valid - fc.field = typ.sym - fc.replaceByFieldName = c.m == mFieldPairs - openScope(c.c) - inc c.c.inUnrolledContext - let body = instFieldLoopBody(fc, lastSon(forLoop), forLoop) - father.add(semStmt(c.c, body)) - dec c.c.inUnrolledContext - closeScope(c.c) - of nkNilLit: discard - of nkRecCase: - let L = forLoop.len - let call = forLoop.sons[L-2] - if call.len > 2: - localError(forLoop.info, errGenerated, - "parallel 'fields' iterator does not work for 'case' objects") - return - # iterate over the selector: - semForObjectFields(c, typ[0], forLoop, father) - # we need to generate a case statement: - var caseStmt = newNodeI(nkCaseStmt, forLoop.info) - # generate selector: - var access = newNodeI(nkDotExpr, forLoop.info, 2) - access.sons[0] = call.sons[1] - access.sons[1] = newSymNode(typ.sons[0].sym, forLoop.info) - caseStmt.add(semExprWithType(c.c, access)) - # copy the branches over, but replace the fields with the for loop body: - for i in 1 .. <typ.len: - var branch = copyTree(typ[i]) - let L = branch.len - branch.sons[L-1] = newNodeI(nkStmtList, forLoop.info) - semForObjectFields(c, typ[i].lastSon, forLoop, branch[L-1]) - caseStmt.add(branch) - father.add(caseStmt) - of nkRecList: - for t in items(typ): semForObjectFields(c, t, forLoop, father) - else: - illFormedAst(typ) - -proc semForFields(c: PContext, n: PNode, m: TMagic): PNode = - # so that 'break' etc. work as expected, we produce - # a 'while true: stmt; break' loop ... - result = newNodeI(nkWhileStmt, n.info, 2) - var trueSymbol = strTableGet(magicsys.systemModule.tab, getIdent"true") - if trueSymbol == nil: - localError(n.info, errSystemNeeds, "true") - trueSymbol = newSym(skUnknown, getIdent"true", getCurrOwner(), n.info) - trueSymbol.typ = getSysType(tyBool) - - result.sons[0] = newSymNode(trueSymbol, n.info) - var stmts = newNodeI(nkStmtList, n.info) - result.sons[1] = stmts - - var length = sonsLen(n) - var call = n.sons[length-2] - if length-2 != sonsLen(call)-1 + ord(m==mFieldPairs): - localError(n.info, errWrongNumberOfVariables) - return result - - var tupleTypeA = skipTypes(call.sons[1].typ, abstractVar-{tyTypeDesc}) - if tupleTypeA.kind notin {tyTuple, tyObject}: - localError(n.info, errGenerated, "no object or tuple type") - return result - for i in 1..call.len-1: - var tupleTypeB = skipTypes(call.sons[i].typ, abstractVar-{tyTypeDesc}) - if not sameType(tupleTypeA, tupleTypeB): - typeMismatch(call.sons[i], tupleTypeA, tupleTypeB) - - inc(c.p.nestedLoopCounter) - if tupleTypeA.kind == tyTuple: - var loopBody = n.sons[length-1] - for i in 0..sonsLen(tupleTypeA)-1: - openScope(c) - var fc: TFieldInstCtx - fc.tupleType = tupleTypeA - fc.tupleIndex = i - fc.replaceByFieldName = m == mFieldPairs - var body = instFieldLoopBody(fc, loopBody, n) - inc c.inUnrolledContext - stmts.add(semStmt(c, body)) - dec c.inUnrolledContext - closeScope(c) - else: - var fc: TFieldsCtx - fc.m = m - fc.c = c - semForObjectFields(fc, tupleTypeA.n, n, stmts) - dec(c.p.nestedLoopCounter) - # for TR macros this 'while true: ...; break' loop is pretty bad, so - # we avoid it now if we can: - if hasSonWith(stmts, nkBreakStmt): - var b = newNodeI(nkBreakStmt, n.info) - b.add(ast.emptyNode) - stmts.add(b) - else: - result = stmts +include semfields proc addForVarDecl(c: PContext, v: PSym) = if warnShadowIdent in gNotes: @@ -795,7 +653,8 @@ proc checkForMetaFields(n: PNode) = template checkMeta(t) = if t != nil and t.isMetaType and tfGenericTypeParam notin t.flags: localError(n.info, errTIsNotAConcreteType, t.typeToString) - + + if n.isNil: return case n.kind of nkRecList, nkRecCase: for s in n: checkForMetaFields(s) @@ -918,7 +777,7 @@ proc semProcAnnotation(c: PContext, prc: PNode): PNode = if it.kind == nkExprColonExpr: # pass pragma argument to the macro too: x.add(it.sons[1]) - x.add(newProcNode(nkDo, prc.info, prc)) + x.add(prc) # recursion assures that this works for multiple macro annotations too: return semStmt(c, x) @@ -946,6 +805,9 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode = gp = newNodeI(nkGenericParams, n.info) if n.sons[paramsPos].kind != nkEmpty: + #if n.kind == nkDo and not experimentalMode(c): + # localError(n.sons[paramsPos].info, + # "use the {.experimental.} pragma to enable 'do' with parameters") semParamList(c, n.sons[paramsPos], gp, s) # paramsTypeCheck(c, s.typ) if sonsLen(gp) > 0 and n.sons[genericParamsPos].kind == nkEmpty: @@ -1026,7 +888,10 @@ proc maybeAddResult(c: PContext, s: PSym, n: PNode) = proc semOverride(c: PContext, s: PSym, n: PNode) = case s.name.s.normalize - of "destroy": doDestructorStuff(c, s, n) + of "destroy": + doDestructorStuff(c, s, n) + if not experimentalMode(c): + localError n.info, "use the {.experimental.} pragma to enable destructors" of "deepcopy": if s.typ.len == 2 and s.typ.sons[1].skipTypes(abstractInst).kind in {tyRef, tyPtr} and @@ -1362,8 +1227,9 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode = # nkNilLit, nkEmpty}: # dec last for i in countup(0, length - 1): - case n.sons[i].kind - of nkFinally, nkExceptBranch: + let k = n.sons[i].kind + case k + of nkFinally, nkExceptBranch, nkDefer: # stand-alone finally and except blocks are # transformed into regular try blocks: # @@ -1372,21 +1238,38 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode = # ... | ... # | finally: # | fclose(f) + var deferPart: PNode + if k == nkDefer: + deferPart = newNodeI(nkFinally, n.sons[i].info) + deferPart.add n.sons[i].sons[0] + elif k == nkFinally: + message(n.info, warnDeprecated, + "use 'defer'; standalone 'finally'") + deferPart = n.sons[i] + else: + message(n.info, warnDeprecated, + "use an explicit 'try'; standalone 'except'") + deferPart = n.sons[i] var tryStmt = newNodeI(nkTryStmt, n.sons[i].info) var body = newNodeI(nkStmtList, n.sons[i].info) if i < n.sonsLen - 1: body.sons = n.sons[(i+1)..(-1)] tryStmt.addSon(body) - tryStmt.addSon(n.sons[i]) + tryStmt.addSon(deferPart) n.sons[i] = semTry(c, tryStmt) n.sons.setLen(i+1) + n.typ = n.sons[i].typ return else: n.sons[i] = semExpr(c, n.sons[i]) - if c.inTypeClass > 0 and n[i].typ != nil and n[i].typ.kind == tyBool: - let verdict = semConstExpr(c, n[i]) - if verdict.intVal == 0: - localError(result.info, "type class predicate failed") + if c.inTypeClass > 0 and n[i].typ != nil: + case n[i].typ.kind + of tyBool: + let verdict = semConstExpr(c, n[i]) + if verdict.intVal == 0: + localError(result.info, "type class predicate failed") + of tyUnknown: continue + else: discard if n.sons[i].typ == enforceVoidContext or usesResult(n.sons[i]): voidContext = true n.typ = enforceVoidContext @@ -1424,7 +1307,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode = # a statement list (s; e) has the type 'e': if result.kind == nkStmtList and result.len > 0: var lastStmt = lastSon(result) - if lastStmt.kind != nkNilLit and not ImplicitlyDiscardable(lastStmt): + if lastStmt.kind != nkNilLit and not implicitlyDiscardable(lastStmt): result.typ = lastStmt.typ #localError(lastStmt.info, errGenerated, # "Last expression must be explicitly returned if it " & |