added experimental .this pragma
This commit is contained in:
parent
6d2fd0c9f1
commit
1afdefcbe9
9 changed files with 192 additions and 117 deletions
|
|
@ -298,6 +298,7 @@ const
|
||||||
sfWrittenTo* = sfBorrow # param is assigned to
|
sfWrittenTo* = sfBorrow # param is assigned to
|
||||||
sfEscapes* = sfProcvar # param escapes
|
sfEscapes* = sfProcvar # param escapes
|
||||||
sfBase* = sfDiscriminant
|
sfBase* = sfDiscriminant
|
||||||
|
sfIsSelf* = sfOverriden # param is 'self'
|
||||||
|
|
||||||
const
|
const
|
||||||
# getting ready for the future expr/stmt merge
|
# getting ready for the future expr/stmt merge
|
||||||
|
|
|
||||||
|
|
@ -635,7 +635,7 @@ proc reallySameIdent(a, b: string): bool {.inline.} =
|
||||||
else:
|
else:
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
proc strTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} =
|
proc strTableIncl*(t: var TStrTable, n: PSym; onConflictKeepOld=false): bool {.discardable.} =
|
||||||
# returns true if n is already in the string table:
|
# returns true if n is already in the string table:
|
||||||
# It is essential that `n` is written nevertheless!
|
# It is essential that `n` is written nevertheless!
|
||||||
# This way the newest redefinition is picked by the semantic analyses!
|
# This way the newest redefinition is picked by the semantic analyses!
|
||||||
|
|
@ -654,7 +654,8 @@ proc strTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} =
|
||||||
replaceSlot = h
|
replaceSlot = h
|
||||||
h = nextTry(h, high(t.data))
|
h = nextTry(h, high(t.data))
|
||||||
if replaceSlot >= 0:
|
if replaceSlot >= 0:
|
||||||
t.data[replaceSlot] = n # overwrite it with newer definition!
|
if not onConflictKeepOld:
|
||||||
|
t.data[replaceSlot] = n # overwrite it with newer definition!
|
||||||
return true # found it
|
return true # found it
|
||||||
elif mustRehash(len(t.data), t.counter):
|
elif mustRehash(len(t.data), t.counter):
|
||||||
strTableEnlarge(t)
|
strTableEnlarge(t)
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ const
|
||||||
wBreakpoint, wWatchPoint, wPassl, wPassc, wDeadCodeElim, wDeprecated,
|
wBreakpoint, wWatchPoint, wPassl, wPassc, wDeadCodeElim, wDeprecated,
|
||||||
wFloatchecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
|
wFloatchecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
|
||||||
wLinearScanEnd, wPatterns, wEffects, wNoForward, wComputedGoto,
|
wLinearScanEnd, wPatterns, wEffects, wNoForward, wComputedGoto,
|
||||||
wInjectStmt, wDeprecated, wExperimental}
|
wInjectStmt, wDeprecated, wExperimental, wThis}
|
||||||
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
|
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
|
||||||
wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
|
wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
|
||||||
wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame,
|
wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame,
|
||||||
|
|
@ -875,6 +875,11 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||||
c.module.flags.incl sfExperimental
|
c.module.flags.incl sfExperimental
|
||||||
else:
|
else:
|
||||||
localError(it.info, "'experimental' pragma only valid as toplevel statement")
|
localError(it.info, "'experimental' pragma only valid as toplevel statement")
|
||||||
|
of wThis:
|
||||||
|
if it.kind == nkExprColonExpr:
|
||||||
|
c.selfName = considerQuotedIdent(it[1])
|
||||||
|
else:
|
||||||
|
c.selfName = getIdent("self")
|
||||||
of wNoRewrite:
|
of wNoRewrite:
|
||||||
noVal(it)
|
noVal(it)
|
||||||
of wBase:
|
of wBase:
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,8 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||||
initialBinding: PNode,
|
initialBinding: PNode,
|
||||||
filter: TSymKinds,
|
filter: TSymKinds,
|
||||||
best, alt: var TCandidate,
|
best, alt: var TCandidate,
|
||||||
errors: var CandidateErrors) =
|
errors: var CandidateErrors;
|
||||||
|
fromUsingStmt: bool) =
|
||||||
var o: TOverloadIter
|
var o: TOverloadIter
|
||||||
# thanks to the lazy semchecking for operands, we need to iterate over the
|
# thanks to the lazy semchecking for operands, we need to iterate over the
|
||||||
# symbol table *before* any call to 'initCandidate' which might invoke
|
# symbol table *before* any call to 'initCandidate' which might invoke
|
||||||
|
|
@ -50,7 +51,12 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||||
|
|
||||||
var syms: seq[tuple[a: PSym, b: int]] = @[]
|
var syms: seq[tuple[a: PSym, b: int]] = @[]
|
||||||
while symx != nil:
|
while symx != nil:
|
||||||
if symx.kind in filter: syms.add((symx, o.lastOverloadScope))
|
if symx.kind in filter:
|
||||||
|
if fromUsingStmt and (symx.typ.n.len <= 1 or
|
||||||
|
sfIsSelf notin symx.typ.n[1].sym.flags):
|
||||||
|
discard "only consider procs that have a 'self' too"
|
||||||
|
else:
|
||||||
|
syms.add((symx, o.lastOverloadScope))
|
||||||
symx = nextOverloadIter(o, c, headSymbol)
|
symx = nextOverloadIter(o, c, headSymbol)
|
||||||
if syms.len == 0: return
|
if syms.len == 0: return
|
||||||
|
|
||||||
|
|
@ -63,7 +69,6 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||||
let sym = syms[i][0]
|
let sym = syms[i][0]
|
||||||
determineType(c, sym)
|
determineType(c, sym)
|
||||||
initCandidate(c, z, sym, initialBinding, syms[i][1])
|
initCandidate(c, z, sym, initialBinding, syms[i][1])
|
||||||
z.calleeSym = sym
|
|
||||||
|
|
||||||
#if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140:
|
#if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140:
|
||||||
# gDebug = true
|
# gDebug = true
|
||||||
|
|
@ -156,28 +161,27 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||||
else:
|
else:
|
||||||
initialBinding = nil
|
initialBinding = nil
|
||||||
|
|
||||||
var usedSyms: seq[PNode]
|
template pickBest(headSymbol, fromUsingStmt) =
|
||||||
|
|
||||||
template pickBest(headSymbol: expr) =
|
|
||||||
pickBestCandidate(c, headSymbol, n, orig, initialBinding,
|
pickBestCandidate(c, headSymbol, n, orig, initialBinding,
|
||||||
filter, result, alt, errors)
|
filter, result, alt, errors, fromUsingStmt)
|
||||||
|
|
||||||
gatherUsedSyms(c, usedSyms)
|
|
||||||
if usedSyms != nil:
|
|
||||||
var hiddenArg = if usedSyms.len > 1: newNode(nkClosedSymChoice, n.info, usedSyms)
|
|
||||||
else: usedSyms[0]
|
|
||||||
|
|
||||||
|
#gatherUsedSyms(c, usedSyms)
|
||||||
|
if c.p != nil and c.p.selfSym != nil:
|
||||||
|
# we need to enforce semchecking of selfSym again because it
|
||||||
|
# might need auto-deref:
|
||||||
|
var hiddenArg = newSymNode(c.p.selfSym)
|
||||||
|
hiddenArg.typ = nil
|
||||||
n.sons.insert(hiddenArg, 1)
|
n.sons.insert(hiddenArg, 1)
|
||||||
orig.sons.insert(hiddenArg, 1)
|
orig.sons.insert(hiddenArg, 1)
|
||||||
|
|
||||||
pickBest(f)
|
pickBest(f, true)
|
||||||
|
|
||||||
if result.state != csMatch:
|
if result.state != csMatch:
|
||||||
n.sons.delete(1)
|
n.sons.delete(1)
|
||||||
orig.sons.delete(1)
|
orig.sons.delete(1)
|
||||||
else: return
|
else: return
|
||||||
|
|
||||||
pickBest(f)
|
pickBest(f, false)
|
||||||
|
|
||||||
let overloadsState = result.state
|
let overloadsState = result.state
|
||||||
if overloadsState != csMatch:
|
if overloadsState != csMatch:
|
||||||
|
|
@ -194,7 +198,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||||
let op = newIdentNode(getIdent(x), n.info)
|
let op = newIdentNode(getIdent(x), n.info)
|
||||||
n.sons[0] = op
|
n.sons[0] = op
|
||||||
orig.sons[0] = op
|
orig.sons[0] = op
|
||||||
pickBest(op)
|
pickBest(op, false)
|
||||||
|
|
||||||
if nfExplicitCall in n.flags:
|
if nfExplicitCall in n.flags:
|
||||||
tryOp ".()"
|
tryOp ".()"
|
||||||
|
|
@ -209,7 +213,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||||
let callOp = newIdentNode(getIdent".=", n.info)
|
let callOp = newIdentNode(getIdent".=", n.info)
|
||||||
n.sons[0..1] = [callOp, n[1], calleeName]
|
n.sons[0..1] = [callOp, n[1], calleeName]
|
||||||
orig.sons[0..1] = [callOp, orig[1], calleeName]
|
orig.sons[0..1] = [callOp, orig[1], calleeName]
|
||||||
pickBest(callOp)
|
pickBest(callOp, false)
|
||||||
|
|
||||||
if overloadsState == csEmpty and result.state == csEmpty:
|
if overloadsState == csEmpty and result.state == csEmpty:
|
||||||
if nfDotField in n.flags and nfExplicitCall notin n.flags:
|
if nfDotField in n.flags and nfExplicitCall notin n.flags:
|
||||||
|
|
@ -228,7 +232,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||||
n.sons[0] = f
|
n.sons[0] = f
|
||||||
|
|
||||||
errors = @[]
|
errors = @[]
|
||||||
pickBest(f)
|
pickBest(f, false)
|
||||||
#notFoundError(c, n, errors)
|
#notFoundError(c, n, errors)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ type
|
||||||
# statements
|
# statements
|
||||||
owner*: PSym # the symbol this context belongs to
|
owner*: PSym # the symbol this context belongs to
|
||||||
resultSym*: PSym # the result symbol (if we are in a proc)
|
resultSym*: PSym # the result symbol (if we are in a proc)
|
||||||
|
selfSym*: PSym # the 'self' symbol (if available)
|
||||||
nestedLoopCounter*: int # whether we are in a loop or not
|
nestedLoopCounter*: int # whether we are in a loop or not
|
||||||
nestedBlockCounter*: int # whether we are in a block or not
|
nestedBlockCounter*: int # whether we are in a block or not
|
||||||
inTryStmt*: int # whether we are in a try statement; works also
|
inTryStmt*: int # whether we are in a try statement; works also
|
||||||
|
|
@ -103,7 +104,7 @@ type
|
||||||
inParallelStmt*: int
|
inParallelStmt*: int
|
||||||
instTypeBoundOp*: proc (c: PContext; dc: PSym; t: PType; info: TLineInfo;
|
instTypeBoundOp*: proc (c: PContext; dc: PSym; t: PType; info: TLineInfo;
|
||||||
op: TTypeAttachedOp): PSym {.nimcall.}
|
op: TTypeAttachedOp): PSym {.nimcall.}
|
||||||
|
selfName*: PIdent
|
||||||
|
|
||||||
proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
|
proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
|
||||||
result.genericSym = s
|
result.genericSym = s
|
||||||
|
|
@ -154,16 +155,6 @@ proc popOwner() =
|
||||||
proc lastOptionEntry(c: PContext): POptionEntry =
|
proc lastOptionEntry(c: PContext): POptionEntry =
|
||||||
result = POptionEntry(c.optionStack.tail)
|
result = POptionEntry(c.optionStack.tail)
|
||||||
|
|
||||||
proc pushProcCon*(c: PContext, owner: PSym) {.inline.} =
|
|
||||||
if owner == nil:
|
|
||||||
internalError("owner is nil")
|
|
||||||
return
|
|
||||||
var x: PProcCon
|
|
||||||
new(x)
|
|
||||||
x.owner = owner
|
|
||||||
x.next = c.p
|
|
||||||
c.p = x
|
|
||||||
|
|
||||||
proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next
|
proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next
|
||||||
|
|
||||||
proc newOptionEntry(): POptionEntry =
|
proc newOptionEntry(): POptionEntry =
|
||||||
|
|
|
||||||
|
|
@ -77,88 +77,6 @@ proc inlineConst(n: PNode, s: PSym): PNode {.inline.} =
|
||||||
result.typ = s.typ
|
result.typ = s.typ
|
||||||
result.info = n.info
|
result.info = n.info
|
||||||
|
|
||||||
proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
|
||||||
case s.kind
|
|
||||||
of skConst:
|
|
||||||
markUsed(n.info, s)
|
|
||||||
styleCheckUse(n.info, s)
|
|
||||||
case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind
|
|
||||||
of tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
|
|
||||||
tyTuple, tySet, tyUInt..tyUInt64:
|
|
||||||
if s.magic == mNone: result = inlineConst(n, s)
|
|
||||||
else: result = newSymNode(s, n.info)
|
|
||||||
of tyArrayConstr, tySequence:
|
|
||||||
# Consider::
|
|
||||||
# const x = []
|
|
||||||
# proc p(a: openarray[int])
|
|
||||||
# proc q(a: openarray[char])
|
|
||||||
# p(x)
|
|
||||||
# q(x)
|
|
||||||
#
|
|
||||||
# It is clear that ``[]`` means two totally different things. Thus, we
|
|
||||||
# copy `x`'s AST into each context, so that the type fixup phase can
|
|
||||||
# deal with two different ``[]``.
|
|
||||||
if s.ast.len == 0: result = inlineConst(n, s)
|
|
||||||
else: result = newSymNode(s, n.info)
|
|
||||||
else:
|
|
||||||
result = newSymNode(s, n.info)
|
|
||||||
of skMacro: result = semMacroExpr(c, n, n, s, flags)
|
|
||||||
of skTemplate: result = semTemplateExpr(c, n, s, flags)
|
|
||||||
of skParam:
|
|
||||||
markUsed(n.info, s)
|
|
||||||
styleCheckUse(n.info, s)
|
|
||||||
if s.typ.kind == tyStatic and s.typ.n != nil:
|
|
||||||
# XXX see the hack in sigmatch.nim ...
|
|
||||||
return s.typ.n
|
|
||||||
elif sfGenSym in s.flags:
|
|
||||||
if c.p.wasForwarded:
|
|
||||||
# gensym'ed parameters that nevertheless have been forward declared
|
|
||||||
# need a special fixup:
|
|
||||||
let realParam = c.p.owner.typ.n[s.position+1]
|
|
||||||
internalAssert realParam.kind == nkSym and realParam.sym.kind == skParam
|
|
||||||
return newSymNode(c.p.owner.typ.n[s.position+1].sym, n.info)
|
|
||||||
elif c.p.owner.kind == skMacro:
|
|
||||||
# gensym'ed macro parameters need a similar hack (see bug #1944):
|
|
||||||
var u = searchInScopes(c, s.name)
|
|
||||||
internalAssert u != nil and u.kind == skParam and u.owner == s.owner
|
|
||||||
return newSymNode(u, n.info)
|
|
||||||
result = newSymNode(s, n.info)
|
|
||||||
of skVar, skLet, skResult, skForVar:
|
|
||||||
if s.magic == mNimvm:
|
|
||||||
localError(n.info, "illegal context for 'nimvm' magic")
|
|
||||||
|
|
||||||
markUsed(n.info, s)
|
|
||||||
styleCheckUse(n.info, s)
|
|
||||||
# if a proc accesses a global variable, it is not side effect free:
|
|
||||||
if sfGlobal in s.flags:
|
|
||||||
incl(c.p.owner.flags, sfSideEffect)
|
|
||||||
result = newSymNode(s, n.info)
|
|
||||||
# We cannot check for access to outer vars for example because it's still
|
|
||||||
# not sure the symbol really ends up being used:
|
|
||||||
# var len = 0 # but won't be called
|
|
||||||
# genericThatUsesLen(x) # marked as taking a closure?
|
|
||||||
of skGenericParam:
|
|
||||||
styleCheckUse(n.info, s)
|
|
||||||
if s.typ.kind == tyStatic:
|
|
||||||
result = newSymNode(s, n.info)
|
|
||||||
result.typ = s.typ
|
|
||||||
elif s.ast != nil:
|
|
||||||
result = semExpr(c, s.ast)
|
|
||||||
else:
|
|
||||||
n.typ = s.typ
|
|
||||||
return n
|
|
||||||
of skType:
|
|
||||||
markUsed(n.info, s)
|
|
||||||
styleCheckUse(n.info, s)
|
|
||||||
if s.typ.kind == tyStatic and s.typ.n != nil:
|
|
||||||
return s.typ.n
|
|
||||||
result = newSymNode(s, n.info)
|
|
||||||
result.typ = makeTypeDesc(c, s.typ)
|
|
||||||
else:
|
|
||||||
markUsed(n.info, s)
|
|
||||||
styleCheckUse(n.info, s)
|
|
||||||
result = newSymNode(s, n.info)
|
|
||||||
|
|
||||||
type
|
type
|
||||||
TConvStatus = enum
|
TConvStatus = enum
|
||||||
convOK,
|
convOK,
|
||||||
|
|
@ -1015,6 +933,116 @@ proc readTypeParameter(c: PContext, typ: PType,
|
||||||
return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info)
|
return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info)
|
||||||
#echo "came here: returned nil"
|
#echo "came here: returned nil"
|
||||||
|
|
||||||
|
proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||||
|
case s.kind
|
||||||
|
of skConst:
|
||||||
|
markUsed(n.info, s)
|
||||||
|
styleCheckUse(n.info, s)
|
||||||
|
case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind
|
||||||
|
of tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
|
||||||
|
tyTuple, tySet, tyUInt..tyUInt64:
|
||||||
|
if s.magic == mNone: result = inlineConst(n, s)
|
||||||
|
else: result = newSymNode(s, n.info)
|
||||||
|
of tyArrayConstr, tySequence:
|
||||||
|
# Consider::
|
||||||
|
# const x = []
|
||||||
|
# proc p(a: openarray[int])
|
||||||
|
# proc q(a: openarray[char])
|
||||||
|
# p(x)
|
||||||
|
# q(x)
|
||||||
|
#
|
||||||
|
# It is clear that ``[]`` means two totally different things. Thus, we
|
||||||
|
# copy `x`'s AST into each context, so that the type fixup phase can
|
||||||
|
# deal with two different ``[]``.
|
||||||
|
if s.ast.len == 0: result = inlineConst(n, s)
|
||||||
|
else: result = newSymNode(s, n.info)
|
||||||
|
else:
|
||||||
|
result = newSymNode(s, n.info)
|
||||||
|
of skMacro: result = semMacroExpr(c, n, n, s, flags)
|
||||||
|
of skTemplate: result = semTemplateExpr(c, n, s, flags)
|
||||||
|
of skParam:
|
||||||
|
markUsed(n.info, s)
|
||||||
|
styleCheckUse(n.info, s)
|
||||||
|
if s.typ.kind == tyStatic and s.typ.n != nil:
|
||||||
|
# XXX see the hack in sigmatch.nim ...
|
||||||
|
return s.typ.n
|
||||||
|
elif sfGenSym in s.flags:
|
||||||
|
if c.p.wasForwarded:
|
||||||
|
# gensym'ed parameters that nevertheless have been forward declared
|
||||||
|
# need a special fixup:
|
||||||
|
let realParam = c.p.owner.typ.n[s.position+1]
|
||||||
|
internalAssert realParam.kind == nkSym and realParam.sym.kind == skParam
|
||||||
|
return newSymNode(c.p.owner.typ.n[s.position+1].sym, n.info)
|
||||||
|
elif c.p.owner.kind == skMacro:
|
||||||
|
# gensym'ed macro parameters need a similar hack (see bug #1944):
|
||||||
|
var u = searchInScopes(c, s.name)
|
||||||
|
internalAssert u != nil and u.kind == skParam and u.owner == s.owner
|
||||||
|
return newSymNode(u, n.info)
|
||||||
|
result = newSymNode(s, n.info)
|
||||||
|
of skVar, skLet, skResult, skForVar:
|
||||||
|
if s.magic == mNimvm:
|
||||||
|
localError(n.info, "illegal context for 'nimvm' magic")
|
||||||
|
|
||||||
|
markUsed(n.info, s)
|
||||||
|
styleCheckUse(n.info, s)
|
||||||
|
# if a proc accesses a global variable, it is not side effect free:
|
||||||
|
if sfGlobal in s.flags:
|
||||||
|
incl(c.p.owner.flags, sfSideEffect)
|
||||||
|
result = newSymNode(s, n.info)
|
||||||
|
# We cannot check for access to outer vars for example because it's still
|
||||||
|
# not sure the symbol really ends up being used:
|
||||||
|
# var len = 0 # but won't be called
|
||||||
|
# genericThatUsesLen(x) # marked as taking a closure?
|
||||||
|
of skGenericParam:
|
||||||
|
styleCheckUse(n.info, s)
|
||||||
|
if s.typ.kind == tyStatic:
|
||||||
|
result = newSymNode(s, n.info)
|
||||||
|
result.typ = s.typ
|
||||||
|
elif s.ast != nil:
|
||||||
|
result = semExpr(c, s.ast)
|
||||||
|
else:
|
||||||
|
n.typ = s.typ
|
||||||
|
return n
|
||||||
|
of skType:
|
||||||
|
markUsed(n.info, s)
|
||||||
|
styleCheckUse(n.info, s)
|
||||||
|
if s.typ.kind == tyStatic and s.typ.n != nil:
|
||||||
|
return s.typ.n
|
||||||
|
result = newSymNode(s, n.info)
|
||||||
|
result.typ = makeTypeDesc(c, s.typ)
|
||||||
|
of skField:
|
||||||
|
if c.p != nil and c.p.selfSym != nil:
|
||||||
|
var ty = skipTypes(c.p.selfSym.typ, {tyGenericInst, tyVar, tyPtr, tyRef})
|
||||||
|
while tfBorrowDot in ty.flags: ty = ty.skipTypes({tyDistinct})
|
||||||
|
var check: PNode = nil
|
||||||
|
if ty.kind == tyObject:
|
||||||
|
while true:
|
||||||
|
check = nil
|
||||||
|
let f = lookupInRecordAndBuildCheck(c, n, ty.n, s.name, check)
|
||||||
|
if f != nil and fieldVisible(c, f):
|
||||||
|
# is the access to a public field or in the same module or in a friend?
|
||||||
|
doAssert f == s
|
||||||
|
markUsed(n.info, f)
|
||||||
|
styleCheckUse(n.info, f)
|
||||||
|
result = newNodeIT(nkDotExpr, n.info, f.typ)
|
||||||
|
result.add makeDeref(newSymNode(c.p.selfSym))
|
||||||
|
result.add newSymNode(f) # we now have the correct field
|
||||||
|
if check != nil:
|
||||||
|
check.sons[0] = result
|
||||||
|
check.typ = result.typ
|
||||||
|
result = check
|
||||||
|
return result
|
||||||
|
if ty.sons[0] == nil: break
|
||||||
|
ty = skipTypes(ty.sons[0], {tyGenericInst})
|
||||||
|
# old code, not sure if it's live code:
|
||||||
|
markUsed(n.info, s)
|
||||||
|
styleCheckUse(n.info, s)
|
||||||
|
result = newSymNode(s, n.info)
|
||||||
|
else:
|
||||||
|
markUsed(n.info, s)
|
||||||
|
styleCheckUse(n.info, s)
|
||||||
|
result = newSymNode(s, n.info)
|
||||||
|
|
||||||
proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
## returns nil if it's not a built-in field access
|
## returns nil if it's not a built-in field access
|
||||||
checkSonsLen(n, 2)
|
checkSonsLen(n, 2)
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,47 @@
|
||||||
# This module implements the instantiation of generic procs.
|
# This module implements the instantiation of generic procs.
|
||||||
# included from sem.nim
|
# included from sem.nim
|
||||||
|
|
||||||
|
proc addObjFieldsToLocalScope(c: PContext; n: PNode) =
|
||||||
|
template rec(n) = addObjFieldsToLocalScope(c, n)
|
||||||
|
case n.kind
|
||||||
|
of nkRecList:
|
||||||
|
for i in countup(0, len(n)-1):
|
||||||
|
rec n[i]
|
||||||
|
of nkRecCase:
|
||||||
|
if n.len > 0: rec n.sons[0]
|
||||||
|
for i in countup(1, len(n)-1):
|
||||||
|
if n[i].kind in {nkOfBranch, nkElse}: rec lastSon(n[i])
|
||||||
|
of nkSym:
|
||||||
|
let f = n.sym
|
||||||
|
if f.kind == skField and fieldVisible(c, f):
|
||||||
|
c.currentScope.symbols.strTableIncl(f, onConflictKeepOld=true)
|
||||||
|
incl(f.flags, sfUsed)
|
||||||
|
# it is not an error to shadow fields via parameters
|
||||||
|
else: discard
|
||||||
|
|
||||||
|
proc rawPushProcCon(c: PContext, owner: PSym) =
|
||||||
|
var x: PProcCon
|
||||||
|
new(x)
|
||||||
|
x.owner = owner
|
||||||
|
x.next = c.p
|
||||||
|
c.p = x
|
||||||
|
|
||||||
|
proc rawHandleSelf(c: PContext; owner: PSym) =
|
||||||
|
if c.selfName != nil and owner.kind in {skProc, skMethod, skConverter, skIterator, skMacro} and owner.typ != nil:
|
||||||
|
let params = owner.typ.n
|
||||||
|
if params.len > 1:
|
||||||
|
let arg = params[1].sym
|
||||||
|
if arg.name.id == c.selfName.id:
|
||||||
|
c.p.selfSym = arg
|
||||||
|
arg.flags.incl sfIsSelf
|
||||||
|
let t = c.p.selfSym.typ.skipTypes(abstractPtrs)
|
||||||
|
if t.kind == tyObject:
|
||||||
|
addObjFieldsToLocalScope(c, t.n)
|
||||||
|
|
||||||
|
proc pushProcCon*(c: PContext; owner: PSym) =
|
||||||
|
rawPushProcCon(c, owner)
|
||||||
|
rawHandleSelf(c, owner)
|
||||||
|
|
||||||
iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable): PSym =
|
iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable): PSym =
|
||||||
internalAssert n.kind == nkGenericParams
|
internalAssert n.kind == nkGenericParams
|
||||||
for i, a in n.pairs:
|
for i, a in n.pairs:
|
||||||
|
|
@ -248,7 +289,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||||
addDecl(c, s)
|
addDecl(c, s)
|
||||||
entry.concreteTypes[i] = s.typ
|
entry.concreteTypes[i] = s.typ
|
||||||
inc i
|
inc i
|
||||||
pushProcCon(c, result)
|
rawPushProcCon(c, result)
|
||||||
instantiateProcType(c, pt, result, info)
|
instantiateProcType(c, pt, result, info)
|
||||||
for j in 1 .. result.typ.len-1:
|
for j in 1 .. result.typ.len-1:
|
||||||
entry.concreteTypes[i] = result.typ.sons[j]
|
entry.concreteTypes[i] = result.typ.sons[j]
|
||||||
|
|
@ -263,6 +304,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||||
# a ``compiles`` context but this is the lesser evil. See
|
# a ``compiles`` context but this is the lesser evil. See
|
||||||
# bug #1055 (tevilcompiles).
|
# bug #1055 (tevilcompiles).
|
||||||
#if c.compilesContextId == 0:
|
#if c.compilesContextId == 0:
|
||||||
|
rawHandleSelf(c, result)
|
||||||
entry.compilesId = c.compilesContextId
|
entry.compilesId = c.compilesContextId
|
||||||
fn.procInstCache.safeAdd(entry)
|
fn.procInstCache.safeAdd(entry)
|
||||||
c.generics.add(makeInstPair(fn, entry))
|
c.generics.add(makeInstPair(fn, entry))
|
||||||
|
|
|
||||||
|
|
@ -1206,9 +1206,10 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
# Macros and Templates can have generic parameters, but they are
|
# Macros and Templates can have generic parameters, but they are
|
||||||
# only used for overload resolution (there is no instantiation of
|
# only used for overload resolution (there is no instantiation of
|
||||||
# the symbol, so we must process the body now)
|
# the symbol, so we must process the body now)
|
||||||
|
pushProcCon(c, s)
|
||||||
if n.sons[genericParamsPos].kind == nkEmpty or usePseudoGenerics:
|
if n.sons[genericParamsPos].kind == nkEmpty or usePseudoGenerics:
|
||||||
if not usePseudoGenerics: paramsTypeCheck(c, s.typ)
|
if not usePseudoGenerics: paramsTypeCheck(c, s.typ)
|
||||||
pushProcCon(c, s)
|
|
||||||
c.p.wasForwarded = proto != nil
|
c.p.wasForwarded = proto != nil
|
||||||
maybeAddResult(c, s, n)
|
maybeAddResult(c, s, n)
|
||||||
if sfImportc notin s.flags:
|
if sfImportc notin s.flags:
|
||||||
|
|
@ -1217,7 +1218,6 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
# unfortunately we cannot skip this step when in 'system.compiles'
|
# unfortunately we cannot skip this step when in 'system.compiles'
|
||||||
# context as it may even be evaluated in 'system.compiles':
|
# context as it may even be evaluated in 'system.compiles':
|
||||||
n.sons[bodyPos] = transformBody(c.module, semBody, s)
|
n.sons[bodyPos] = transformBody(c.module, semBody, s)
|
||||||
popProcCon(c)
|
|
||||||
else:
|
else:
|
||||||
if s.typ.sons[0] != nil and kind != skIterator:
|
if s.typ.sons[0] != nil and kind != skIterator:
|
||||||
addDecl(c, newSym(skUnknown, getIdent"result", nil, n.info))
|
addDecl(c, newSym(skUnknown, getIdent"result", nil, n.info))
|
||||||
|
|
@ -1228,6 +1228,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
if sfImportc in s.flags:
|
if sfImportc in s.flags:
|
||||||
# so we just ignore the body after semantic checking for importc:
|
# so we just ignore the body after semantic checking for importc:
|
||||||
n.sons[bodyPos] = ast.emptyNode
|
n.sons[bodyPos] = ast.emptyNode
|
||||||
|
popProcCon(c)
|
||||||
else:
|
else:
|
||||||
if proto != nil: localError(n.info, errImplOfXexpected, proto.name.s)
|
if proto != nil: localError(n.info, errImplOfXexpected, proto.name.s)
|
||||||
if {sfImportc, sfBorrow} * s.flags == {} and s.magic == mNone:
|
if {sfImportc, sfBorrow} * s.flags == {} and s.magic == mNone:
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ type
|
||||||
# is this a top-level symbol or a nested proc?
|
# is this a top-level symbol or a nested proc?
|
||||||
call*: PNode # modified call
|
call*: PNode # modified call
|
||||||
bindings*: TIdTable # maps types to types
|
bindings*: TIdTable # maps types to types
|
||||||
|
magic*: TMagic # magic of operation
|
||||||
baseTypeMatch: bool # needed for conversions from T to openarray[T]
|
baseTypeMatch: bool # needed for conversions from T to openarray[T]
|
||||||
# for example
|
# for example
|
||||||
fauxMatch*: TTypeKind # the match was successful only due to the use
|
fauxMatch*: TTypeKind # the match was successful only due to the use
|
||||||
|
|
@ -114,6 +115,7 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
|
||||||
c.calleeScope = 1
|
c.calleeScope = 1
|
||||||
else:
|
else:
|
||||||
c.calleeScope = calleeScope
|
c.calleeScope = calleeScope
|
||||||
|
c.magic = c.calleeSym.magic
|
||||||
initIdTable(c.bindings)
|
initIdTable(c.bindings)
|
||||||
c.errors = nil
|
c.errors = nil
|
||||||
if binding != nil and callee.kind in routineKinds:
|
if binding != nil and callee.kind in routineKinds:
|
||||||
|
|
@ -1691,7 +1693,7 @@ proc partialMatch*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
|
||||||
matchesAux(c, n, nOrig, m, marker)
|
matchesAux(c, n, nOrig, m, marker)
|
||||||
|
|
||||||
proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
|
proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
|
||||||
if m.calleeSym != nil and m.calleeSym.magic in {mArrGet, mArrPut}:
|
if m.magic in {mArrGet, mArrPut}:
|
||||||
m.state = csMatch
|
m.state = csMatch
|
||||||
m.call = n
|
m.call = n
|
||||||
return
|
return
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue