completed expr/stmt unification

This commit is contained in:
Araq 2013-05-03 23:51:43 +02:00
commit fa0a327dd6
10 changed files with 642 additions and 673 deletions

View file

@ -19,24 +19,6 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode =
proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
proc performProcvarCheck(c: PContext, n: PNode, s: PSym) =
var smoduleId = getModule(s).id
if sfProcVar notin s.flags and s.typ.callConv == ccDefault and
smoduleId != c.module.id and smoduleId != c.friendModule.id:
LocalError(n.info, errXCannotBePassedToProcVar, s.name.s)
proc semProcvarCheck(c: PContext, n: PNode) =
let n = n.skipConv
if n.kind == nkSym and n.sym.kind in {skProc, skMethod, skIterator,
skConverter}:
performProcvarCheck(c, n, n.sym)
proc semDestructorCheck(c: PContext, n: PNode, flags: TExprFlags) {.inline.} =
if efAllowDestructor notin flags and n.kind in nkCallKinds+{nkObjConstr}:
if instantiateDestructor(c, n.typ):
LocalError(n.info, errGenerated,
"usage of a type with a destructor in a non destructible context")
proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
# same as 'semExprWithType' but doesn't check for proc vars
result = semExpr(c, n, flags)
@ -781,16 +763,6 @@ proc buildEchoStmt(c: PContext, n: PNode): PNode =
# and check 'arg' for semantics again:
addSon(result, semExpr(c, arg))
proc discardCheck(result: PNode) =
if result.typ != nil and result.typ.kind notin {tyStmt, tyEmpty}:
if result.kind == nkNilLit:
# XXX too much work and fixing would break bootstrapping:
#Message(n.info, warnNilStatement)
result.typ = nil
elif not ImplicitlyDiscardable(result) and result.typ.kind != tyError and
gCmd != cmdInteractive:
localError(result.info, errDiscardValue)
proc semExprNoType(c: PContext, n: PNode): PNode =
result = semExpr(c, n, {efWantStmt})
discardCheck(result)
@ -1125,14 +1097,16 @@ proc semAsgn(c: PContext, n: PNode): PNode =
var
rhs = semExprWithType(c, n.sons[1],
if lhsIsResult: {efAllowDestructor} else: {})
if lhsIsResult and lhs.sym.typ.kind == tyGenericParam:
if matchTypeClass(lhs.typ, rhs.typ):
InternalAssert c.p.resultSym != nil
lhs.typ = rhs.typ
c.p.resultSym.typ = rhs.typ
c.p.owner.typ.sons[0] = rhs.typ
else:
typeMismatch(n, lhs.typ, rhs.typ)
if lhsIsResult:
n.typ = EnforceVoidContext
if lhs.sym.typ.kind == tyGenericParam:
if matchTypeClass(lhs.typ, rhs.typ):
InternalAssert c.p.resultSym != nil
lhs.typ = rhs.typ
c.p.resultSym.typ = rhs.typ
c.p.owner.typ.sons[0] = rhs.typ
else:
typeMismatch(n, lhs.typ, rhs.typ)
n.sons[1] = fitNode(c, le, rhs)
fixAbstractType(c, n)
@ -1481,52 +1455,13 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
if result == nil:
setResult(it.sons[0])
else: illFormedAst(n)
if result == nil:
result = newNodeI(nkNilLit, n.info)
if result == nil:
result = newNodeI(nkEmpty, n.info)
# The ``when`` statement implements the mechanism for platform dependent
# code. Thus we try to ensure here consistent ID allocation after the
# ``when`` statement.
IDsynchronizationPoint(200)
proc semExprBranch(c: PContext, n: PNode): PNode =
result = semExpr(c, n)
if result.typ != nil:
# XXX tyGenericInst here?
semProcvarCheck(c, result)
if result.typ.kind == tyVar: result = newDeref(result)
semDestructorCheck(c, result, {})
proc semIf(c: PContext, n: PNode): PNode =
result = n
var typ = CommonTypeBegin
var hasElse = false
for i in countup(0, sonsLen(n) - 1):
var it = n.sons[i]
if it.len == 2:
when newScopeForIf: openScope(c.tab)
it.sons[0] = forceBool(c, semExprWithType(c, it.sons[0]))
when not newScopeForIf: openScope(c.tab)
it.sons[1] = semExprBranch(c, it.sons[1])
typ = commonType(typ, it.sons[1].typ)
closeScope(c.tab)
elif it.len == 1:
hasElse = true
openScope(c.tab)
it.sons[0] = semExprBranch(c, it.sons[0])
typ = commonType(typ, it.sons[0].typ)
closeScope(c.tab)
else: illFormedAst(it)
if isEmptyType(typ) or not hasElse:
for it in n: discardCheck(it.lastSon)
result.kind = nkIfStmt
else:
for it in n:
let j = it.len-1
it.sons[j] = fitNode(c, typ, it.sons[j])
result.kind = nkIfExpr
result.typ = typ
proc semSetConstr(c: PContext, n: PNode): PNode =
result = newNodeI(nkCurly, n.info)
result.typ = newTypeS(tySet, c)
@ -1692,26 +1627,21 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
it.sons[1] = e
# XXX object field name check for 'case objects' if the kind is static?
proc semStmtListExpr(c: PContext, n: PNode): PNode =
result = n
checkMinSonsLen(n, 1)
var length = sonsLen(n)
for i in countup(0, length - 2):
n.sons[i] = semStmt(c, n.sons[i])
if length > 0:
n.sons[length - 1] = semExprWithType(c, n.sons[length - 1])
n.typ = n.sons[length - 1].typ
proc semBlockExpr(c: PContext, n: PNode): PNode =
proc semBlock(c: PContext, n: PNode): PNode =
result = n
Inc(c.p.nestedBlockCounter)
checkSonsLen(n, 2)
openScope(c.tab) # BUGFIX: label is in the scope of block!
if n.sons[0].kind notin {nkEmpty, nkSym}:
# nkSym for gensym'ed labels:
addDecl(c, newSymS(skLabel, n.sons[0], c))
n.sons[1] = semStmtListExpr(c, n.sons[1])
if n.sons[0].kind != nkEmpty:
var labl = newSymG(skLabel, n.sons[0], c)
if sfGenSym notin labl.flags:
addDecl(c, labl)
n.sons[0] = newSymNode(labl, n.sons[0].info)
suggestSym(n.sons[0], labl)
n.sons[1] = semExpr(c, n.sons[1])
n.typ = n.sons[1].typ
if isEmptyType(n.typ): n.kind = nkBlockStmt
else: n.kind = nkBlockExpr
closeScope(c.tab)
Dec(c.p.nestedBlockCounter)
@ -1731,57 +1661,6 @@ proc buildCall(n: PNode): PNode =
else:
result = n
proc semCaseExpr(c: PContext, caseStmt: PNode): PNode =
# The case expression is simply rewritten to a StmtListExpr:
# var res {.noInit, genSym.}: type(values)
#
# case E
# of X: res = value1
# of Y: res = value2
#
# res
var
info = caseStmt.info
resVar = newSym(skVar, idAnon, getCurrOwner(), info)
resNode = newSymNode(resVar, info)
resType: PType
resVar.flags = { sfGenSym, sfNoInit }
for i in countup(1, caseStmt.len - 1):
var cs = caseStmt[i]
case cs.kind
of nkOfBranch, nkElifBranch, nkElse:
# the value is always the last son regardless of the branch kind
cs.checkMinSonsLen 1
var value = cs{-1}
if value.kind == nkStmtList: value.kind = nkStmtListExpr
value = semExprWithType(c, value)
if resType == nil:
resType = value.typ
elif not sameType(resType, value.typ):
# XXX: semeType is a bit too harsh.
# work on finding a common base type.
# this will be useful for arrays/seq too:
# [ref DerivedA, ref DerivedB, ref Base]
typeMismatch(cs, resType, value.typ)
cs{-1} = newNode(nkAsgn, cs.info, @[resNode, value])
else:
IllFormedAst(caseStmt)
result = newNode(nkStmtListExpr, info, @[
newNode(nkVarSection, info, @[
newNode(nkIdentDefs, info, @[
resNode,
symNodeFromType(c, resType, info),
emptyNode])]),
caseStmt,
resNode])
result = semStmtListExpr(c, result)
proc fixImmediateParams(n: PNode): PNode =
# XXX: Temporary work-around until we carry out
# the planned overload resolution reforms
@ -1946,7 +1825,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
of nkObjConstr: result = semObjConstr(c, n, flags)
of nkLambdaKinds: result = semLambda(c, n, flags)
of nkDerefExpr: result = semDeref(c, n)
of nkAddr:
of nkAddr:
result = n
checkSonsLen(n, 1)
n.sons[0] = semExprWithType(c, n.sons[0])
@ -1958,8 +1837,6 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
n.sons[0] = semExpr(c, n.sons[0], flags)
of nkCast: result = semCast(c, n)
of nkIfExpr, nkIfStmt: result = semIf(c, n)
of nkStmtListExpr: result = semStmtListExpr(c, n)
of nkBlockExpr: result = semBlockExpr(c, n)
of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkHiddenCallConv:
checkSonsLen(n, 2)
of nkStringToCString, nkCStringToString, nkObjDownConv, nkObjUpConv:
@ -1976,8 +1853,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
of nkStaticExpr:
result = semStaticExpr(c, n)
of nkAsgn: result = semAsgn(c, n)
of nkBlockStmt: result = semBlock(c, n)
of nkStmtList: result = semStmtList(c, n)
of nkBlockStmt, nkBlockExpr: result = semBlock(c, n)
of nkStmtList, nkStmtListExpr: result = semStmtList(c, n)
of nkRaiseStmt: result = semRaise(c, n)
of nkVarSection: result = semVarOrLet(c, n, skVar)
of nkLetSection: result = semVarOrLet(c, n, skLet)
@ -1988,9 +1865,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
of nkTryStmt: result = semTry(c, n)
of nkBreakStmt, nkContinueStmt: result = semBreakOrContinue(c, n)
of nkForStmt, nkParForStmt: result = semFor(c, n)
of nkCaseStmt:
if efWantStmt in flags: result = semCase(c, n)
else: result = semCaseExpr(c, n)
of nkCaseStmt: result = semCase(c, n)
of nkReturnStmt: result = semReturn(c, n)
of nkAsmStmt: result = semAsm(c, n)
of nkYieldStmt: result = semYield(c, n)