distinguish properly between nkOpen and nkClosedSymChoice

This commit is contained in:
Araq 2012-08-26 02:47:17 +02:00
commit b5b5e6e76d
15 changed files with 107 additions and 50 deletions

View file

@ -104,7 +104,8 @@ type
nkTableConstr, # a table constructor {expr: expr}
nkBind, # ``bind expr`` node
nkSymChoice, # symbol choice node
nkClosedSymChoice, # symbol choice node; a list of nkSyms (closed)
nkOpenSymChoice, # symbol choice node; a list of nkSyms (open)
nkHiddenStdConv, # an implicit standard type conversion
nkHiddenSubConv, # an implicit type conversion from a subtype
# to a supertype
@ -473,6 +474,11 @@ const
mInRange, mInSet, mRepr,
mRand,
mCopyStr, mCopyStrLast}
# magics that require special semantic checking and
# thus cannot be overloaded (also documented in the spec!):
SpecialSemMagics* = {
mDefined, mDefinedInScope, mCompiles, mLow, mHigh, mSizeOf, mIs, mOf,
mEcho, mShallowCopy, mExpandToAst}
type
PNode* = ref TNode

View file

@ -230,7 +230,7 @@ proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
LocalError(n.sons[1].info, errIdentifierExpected,
renderTree(n.sons[1]))
result = errorSym(c, n.sons[1])
of nkSymChoice:
of nkClosedSymChoice, nkOpenSymChoice:
o.mode = oimSymChoice
result = n.sons[0].sym
o.stackPtr = 1
@ -269,7 +269,7 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
result = n.sons[o.stackPtr].sym
Incl(o.inSymChoice, result.id)
inc(o.stackPtr)
else:
elif n.kind == nkOpenSymChoice:
# try 'local' symbols too for Koenig's lookup:
o.mode = oimSymChoiceLocalLookup
o.stackPtr = c.tab.tos-1

View file

@ -379,7 +379,8 @@ proc lsub(n: PNode): int =
of nkPar, nkCurly, nkBracket, nkClosure: result = lcomma(n) + 2
of nkTableConstr:
result = if n.len > 0: lcomma(n) + 2 else: len("{:}")
of nkSymChoice: result = lsons(n) + len("()") + sonsLen(n) - 1
of nkClosedSymChoice, nkOpenSymChoice:
result = lsons(n) + len("()") + sonsLen(n) - 1
of nkTupleTy: result = lcomma(n) + len("tuple[]")
of nkDotExpr: result = lsons(n) + 1
of nkBind: result = lsons(n) + len("bind_")
@ -833,7 +834,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
put(g, tkParLe, "(")
gcomma(g, n, 1)
put(g, tkParRi, ")")
of nkSymChoice:
of nkClosedSymChoice, nkOpenSymChoice:
put(g, tkParLe, "(")
for i in countup(0, sonsLen(n) - 1):
if i > 0: put(g, tkOpr, "|")

View file

@ -10,7 +10,7 @@
## This module implements semantic checking for calls.
# included from sem.nim
proc sameMethodDispatcher(a, b: PSym): bool =
proc sameMethodDispatcher(a, b: PSym): bool =
result = false
if a.kind == skMethod and b.kind == skMethod:
var aa = lastSon(a.ast)
@ -132,11 +132,11 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
if safeLen(s.ast.sons[genericParamsPos]) != n.len-1:
return explicitGenericInstError(n)
result = explicitGenericSym(c, n, s)
elif a.kind == nkSymChoice:
elif a.kind in {nkClosedSymChoice, nkOpenSymChoice}:
# choose the generic proc with the proper number of type parameters.
# XXX I think this could be improved by reusing sigmatch.ParamTypesMatch.
# It's good enough for now.
result = newNodeI(nkSymChoice, n.info)
result = newNodeI(a.kind, n.info)
for i in countup(0, len(a)-1):
var candidate = a.sons[i].sym
if candidate.kind in {skProc, skMethod, skConverter, skIterator}:
@ -144,8 +144,9 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
# type parameters:
if safeLen(candidate.ast.sons[genericParamsPos]) == n.len-1:
result.add(explicitGenericSym(c, n, candidate))
# get rid of nkSymChoice if not ambiguous:
if result.len == 1: result = result[0]
# get rid of nkClosedSymChoice if not ambiguous:
if result.len == 1 and a.kind == nkClosedSymChoice:
result = result[0]
# candidateCount != 1: return explicitGenericInstError(n)
else:
result = explicitGenericInstError(n)

View file

@ -58,7 +58,7 @@ proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result.typ = errorType(c)
proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
result = symChoice(c, n, s)
result = symChoice(c, n, s, scClosed)
proc inlineConst(n: PNode, s: PSym): PNode {.inline.} =
result = copyTree(s.ast)
@ -72,7 +72,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
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)
result = symChoice(c, n, s)
result = symChoice(c, n, s, scClosed)
if result.kind == nkSym:
markIndirect(c, result.sym)
if isGenericRoutine(result.sym):
@ -182,6 +182,9 @@ proc isCastable(dst, src: PType): bool =
(skipTypes(dst, abstractInst).kind in IntegralTypes) or
(skipTypes(src, abstractInst).kind in IntegralTypes)
proc isSymChoice(n: PNode): bool {.inline.} =
result = n.kind in {nkClosedSymChoice, nkOpenSymChoice}
proc semConv(c: PContext, n: PNode, s: PSym): PNode =
if sonsLen(n) != 2:
LocalError(n.info, errConvNeedsOneArg)
@ -191,7 +194,7 @@ proc semConv(c: PContext, n: PNode, s: PSym): PNode =
addSon(result, copyTree(n.sons[0]))
addSon(result, semExprWithType(c, n.sons[1]))
var op = result.sons[1]
if op.kind != nkSymChoice:
if not isSymChoice(op):
checkConvertible(result.info, result.typ, op.typ)
else:
for i in countup(0, sonsLen(op) - 1):
@ -830,7 +833,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
## returns nil if it's not a built-in field access
checkSonsLen(n, 2)
# early exit for this; see tests/compile/tbindoverload.nim:
if n.sons[1].kind == nkSymChoice: return
if isSymChoice(n.sons[1]): return
var s = qualifiedLookup(c, n, {checkAmbiguity, checkUndeclared})
if s != nil:
@ -910,7 +913,7 @@ proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
# in Nimrod. We first allow types in the semantic checking.
result = builtinFieldAccess(c, n, flags)
if result == nil:
if n.sons[1].kind == nkSymChoice:
if isSymChoice(n.sons[1]):
result = newNodeI(nkDotCall, n.info)
addSon(result, n.sons[1])
addSon(result, copyTree(n[0]))
@ -1222,6 +1225,7 @@ proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
# this is a hotspot in the compiler!
# DON'T forget to update ast.SpecialSemMagics if you add a magic here!
result = n
case s.magic # magics that need special treatment
of mDefined: result = semDefined(c, setMs(n, s), false)
@ -1518,8 +1522,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
else:
#liMessage(n.info, warnUser, renderTree(n));
result = semIndirectOp(c, n, flags)
elif n.sons[0].kind == nkSymChoice or n[0].kind == nkBracketExpr and
n[0][0].kind == nkSymChoice:
elif isSymChoice(n.sons[0]) or n[0].kind == nkBracketExpr and
isSymChoice(n[0][0]):
result = semDirectOp(c, n, flags)
else:
result = semIndirectOp(c, n, flags)
@ -1576,7 +1580,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
checkMinSonsLen(n, 2)
of nkTableConstr:
result = semTableConstr(c, n)
of nkSymChoice:
of nkClosedSymChoice, nkOpenSymChoice:
LocalError(n.info, errExprXAmbiguous, renderTree(n, {renderNoComments}))
# error correction: Pick first element:
result = n.sons[0]

View file

@ -13,7 +13,7 @@
# A problem is that it cannot be detected if the symbol is introduced
# as in ``var x = ...`` or used because macros/templates can hide this!
# So we have to eval templates/macros right here so that symbol
# lookup can be accurate.
# lookup can be accurate. XXX But this can only be done for immediate macros!
# included from sem.nim
@ -47,8 +47,8 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode =
# Introduced in this pass! Leave it as an identifier.
result = n
of skProc, skMethod, skIterator, skConverter:
result = symChoice(c, n, s)
of skTemplate:
result = symChoice(c, n, s, scOpen)
of skTemplate:
result = semTemplateExpr(c, n, s, false)
of skMacro:
result = semMacroExpr(c, n, s, false)
@ -75,7 +75,8 @@ proc semGenericStmt(c: PContext, n: PNode,
if withinBind in flags:
localError(n.info, errUndeclaredIdentifier, n.ident.s)
else:
if withinBind in flags or s.id in toBind: result = symChoice(c, n, s)
if withinBind in flags or s.id in toBind:
result = symChoice(c, n, s, scClosed)
else: result = semGenericStmtSymbol(c, n, s)
of nkDotExpr:
var s = QualifiedLookUp(c, n, {})
@ -104,7 +105,7 @@ proc semGenericStmt(c: PContext, n: PNode,
of skUnknown, skParam:
# Leave it as an identifier.
of skProc, skMethod, skIterator, skConverter:
result.sons[0] = symChoice(c, n.sons[0], s)
result.sons[0] = symChoice(c, n.sons[0], s, scOpen)
first = 1
of skGenericParam:
result.sons[0] = newSymNode(s, n.sons[0].info)
@ -114,7 +115,7 @@ proc semGenericStmt(c: PContext, n: PNode,
if (s.typ != nil) and (s.typ.kind != tyGenericParam):
result.sons[0] = newSymNode(s, n.sons[0].info)
first = 1
else:
else:
result.sons[0] = newSymNode(s, n.sons[0].info)
first = 1
for i in countup(first, sonsLen(result) - 1):

View file

@ -49,16 +49,22 @@ proc semBindSym(c: PContext, n: PNode): PNode =
result = copyNode(n)
result.add(n.sons[0])
let sl = c.semConstExpr(c, n.sons[1])
let sl = semConstExpr(c, n.sons[1])
if sl.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit}:
LocalError(n.info, errStringLiteralExpected)
LocalError(n.sons[1].info, errStringLiteralExpected)
return errorNode(c, n)
let isMixin = semConstExpr(c, n.sons[2])
if isMixin.kind != nkIntLit or isMixin.intVal < 0 or
isMixin.intVal > high(TSymChoiceRule).int:
LocalError(n.sons[2].info, errConstExprExpected)
return errorNode(c, n)
let id = newIdentNode(getIdent(sl.strVal), n.info)
let s = QualifiedLookUp(c, id)
if s != nil:
# we need to mark all symbols:
let sc = symChoice(c, id, s)
var sc = symChoice(c, id, s, TSymChoiceRule(isMixin.intVal))
result.add(sc)
else:
LocalError(n.sons[1].info, errUndeclaredIdentifier, sl.strVal)

View file

@ -40,8 +40,12 @@ proc symBinding(n: PNode): TSymBinding =
of wInject: return spInject
else: nil
proc symChoice(c: PContext, n: PNode, s: PSym): PNode =
var
type
TSymChoiceRule = enum
scClosed, scOpen, scForceOpen
proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
var
a: PSym
o: TOverloadIter
var i = 0
@ -50,17 +54,17 @@ proc symChoice(c: PContext, n: PNode, s: PSym): PNode =
a = nextOverloadIter(o, c, n)
inc(i)
if i > 1: break
if i <= 1:
if i <= 1 and r != scForceOpen:
# XXX this makes more sense but breaks bootstrapping for now:
# (s.kind notin routineKinds or s.magic != mNone):
# for some reason 'nextTry' is copied and considered as a candidate in
# tables.nim
# for instance 'nextTry' is both in tables.nim and astalgo.nim ...
result = newSymNode(s, n.info)
markUsed(n, s)
else:
# semantic checking requires a type; ``fitNode`` deals with it
# appropriately
result = newNodeIT(nkSymChoice, n.info, newTypeS(tyNone, c))
let kind = if r == scClosed: nkClosedSymChoice else: nkOpenSymChoice
result = newNodeIT(kind, n.info, newTypeS(tyNone, c))
a = initOverloadIter(o, c, n)
while a != nil:
incl(a.flags, sfUsed)
@ -78,7 +82,7 @@ proc semBindStmt(c: PContext, n: PNode, toBind: var TIntSet): PNode =
let s = QualifiedLookUp(c, a)
if s != nil:
# we need to mark all symbols:
let sc = symChoice(c, n, s)
let sc = symChoice(c, n, s, scClosed)
if sc.kind == nkSym:
toBind.incl(sc.sym.id)
else:
@ -178,7 +182,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
incl(s.flags, sfUsed)
result = newSymNode(s, n.info)
elif Contains(c.toBind, s.id):
result = symChoice(c.c, n, s)
result = symChoice(c.c, n, s, scClosed)
elif s.owner == c.owner:
InternalAssert sfGenSym in s.flags
incl(s.flags, sfUsed)
@ -294,7 +298,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
if n.kind == nkDotExpr or n.kind == nkAccQuoted:
let s = QualifiedLookUp(c.c, n, {})
if s != nil and Contains(c.toBind, s.id):
return symChoice(c.c, n, s)
return symChoice(c.c, n, s, scClosed)
result = n
for i in countup(0, sonsLen(n) - 1):
result.sons[i] = semTemplBody(c, n.sons[i])
@ -308,7 +312,7 @@ proc semTemplBodyDirty(c: var TemplCtx, n: PNode): PNode =
if s.owner == c.owner and s.kind == skParam:
result = newSymNode(s, n.info)
elif Contains(c.toBind, s.id):
result = symChoice(c.c, n, s)
result = symChoice(c.c, n, s, scClosed)
of nkBind:
result = semTemplBodyDirty(c, n.sons[0])
of nkBindStmt:
@ -321,7 +325,7 @@ proc semTemplBodyDirty(c: var TemplCtx, n: PNode): PNode =
if n.kind == nkDotExpr or n.kind == nkAccQuoted:
let s = QualifiedLookUp(c.c, n, {})
if s != nil and Contains(c.toBind, s.id):
return symChoice(c.c, n, s)
return symChoice(c.c, n, s, scClosed)
result = n
for i in countup(0, sonsLen(n) - 1):
result.sons[i] = semTemplBodyDirty(c, n.sons[i])

View file

@ -703,7 +703,7 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
proc ParamTypesMatch(c: PContext, m: var TCandidate, f, a: PType,
arg, argOrig: PNode): PNode =
if arg == nil or arg.kind != nkSymChoice:
if arg == nil or arg.kind != nkClosedSymChoice:
result = ParamTypesMatchAux(c, m, f, a, arg, argOrig)
else:
# CAUTION: The order depends on the used hashing scheme. Thus it is

View file

@ -85,7 +85,7 @@ proc suggestObject(c: PContext, n: PNode, outputs: var int) =
proc nameFits(c: PContext, s: PSym, n: PNode): bool =
var op = n.sons[0]
if op.kind == nkSymChoice: op = op.sons[0]
if op.kind in {nkOpenSymChoice, nkClosedSymChoice}: op = op.sons[0]
var opr: PIdent
case op.kind
of nkSym: opr = op.sym.name

View file

@ -143,7 +143,8 @@ proc SwapOperands*(op: PNode) =
proc IsRange*(n: PNode): bool {.inline.} =
if n.kind == nkInfix:
if n[0].kind == nkIdent and n[0].ident.id == ord(wDotDot) or
n[0].kind == nkSymChoice and n[0][1].sym.name.id == ord(wDotDot):
n[0].kind in {nkClosedSymChoice, nkOpenSymChoice} and
n[0][1].sym.name.id == ord(wDotDot):
result = true
proc whichPragma*(n: PNode): TSpecialWord =

View file

@ -117,7 +117,7 @@ proc isCompatibleToCString(a: PType): bool =
result = true
proc getProcHeader(sym: PSym): string =
result = sym.name.s & '('
result = sym.owner.name.s & '.' & sym.name.s & '('
var n = sym.typ.n
for i in countup(1, sonsLen(n) - 1):
var p = n.sons[i]