mirror of
https://github.com/nim-lang/Nim.git
synced 2026-06-12 06:38:11 +00:00
lazy operand sem'checking (beware)
This commit is contained in:
@@ -19,13 +19,9 @@ import
|
||||
|
||||
# implementation
|
||||
|
||||
type
|
||||
TExprFlag = enum
|
||||
efLValue, efWantIterator, efInTypeof, efWantStmt, efDetermineType
|
||||
TExprFlags = set[TExprFlag]
|
||||
|
||||
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
||||
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
||||
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.procvar.}
|
||||
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.
|
||||
procvar.}
|
||||
proc semExprNoType(c: PContext, n: PNode): PNode
|
||||
proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
||||
proc semProcBody(c: PContext, n: PNode): PNode
|
||||
@@ -200,14 +196,12 @@ proc addCodeForGenerics(c: PContext, n: PNode) =
|
||||
addSon(n, prc.ast)
|
||||
c.lastGenericIdx = c.generics.len
|
||||
|
||||
proc semExprNoFlags(c: PContext, n: PNode): PNode {.procvar.} =
|
||||
result = semExpr(c, n, {})
|
||||
|
||||
proc myOpen(module: PSym): PPassContext =
|
||||
var c = newContext(module)
|
||||
if c.p != nil: InternalError(module.info, "sem.myOpen")
|
||||
c.semConstExpr = semConstExpr
|
||||
c.semExpr = semExprNoFlags
|
||||
c.semExpr = semExpr
|
||||
c.semExprWithType = semExprWithType
|
||||
c.semConstBoolExpr = semConstBoolExpr
|
||||
c.semOverloadedCall = semOverloadedCall
|
||||
c.semTypeNode = semTypeNode
|
||||
|
||||
@@ -39,6 +39,10 @@ type
|
||||
TInstantiationPair* = object
|
||||
genericSym*: PSym
|
||||
inst*: PInstantiation
|
||||
|
||||
TExprFlag* = enum
|
||||
efLValue, efWantIterator, efInTypeof, efWantStmt, efDetermineType
|
||||
TExprFlags* = set[TExprFlag]
|
||||
|
||||
PContext* = ref TContext
|
||||
TContext* = object of TPassContext # a context represents a module
|
||||
@@ -64,7 +68,8 @@ type
|
||||
# to some new symbol in a generic instantiation
|
||||
libs*: TLinkedList # all libs used by this module
|
||||
semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
|
||||
semExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
|
||||
semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
||||
semExprWithType*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
||||
semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet
|
||||
semOverloadedCall*: proc (c: PContext, n, nOrig: PNode,
|
||||
filter: TSymKinds): PNode {.nimcall.}
|
||||
|
||||
@@ -31,10 +31,6 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode =
|
||||
|
||||
proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
||||
|
||||
proc newDeref(n: PNode): PNode {.inline.} =
|
||||
result = newNodeIT(nkHiddenDeref, n.info, n.typ.sons[0])
|
||||
addSon(result, n)
|
||||
|
||||
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
result = semExpr(c, n, flags)
|
||||
if result.kind == nkEmpty:
|
||||
@@ -319,7 +315,7 @@ proc semIs(c: PContext, n: PNode): PNode =
|
||||
|
||||
proc semOpAux(c: PContext, n: PNode) =
|
||||
const flags = {efDetermineType}
|
||||
for i in countup(1, n.sonsLen- 1):
|
||||
for i in countup(1, n.sonsLen-1):
|
||||
var a = n.sons[i]
|
||||
if a.kind == nkExprEqExpr and sonsLen(a) == 2:
|
||||
var info = a.sons[0].info
|
||||
@@ -328,7 +324,7 @@ proc semOpAux(c: PContext, n: PNode) =
|
||||
a.typ = a.sons[1].typ
|
||||
else:
|
||||
n.sons[i] = semExprWithType(c, a, flags)
|
||||
|
||||
|
||||
proc overloadedCallOpr(c: PContext, n: PNode): PNode =
|
||||
# quick check if there is *any* () operator overloaded:
|
||||
var par = getIdent("()")
|
||||
@@ -694,7 +690,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
# this seems to be a hotspot in the compiler!
|
||||
let nOrig = n.copyTree
|
||||
semOpAux(c, n)
|
||||
#semLazyOpAux(c, n)
|
||||
result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
|
||||
if result == nil:
|
||||
result = overloadedCallOpr(c, n)
|
||||
@@ -706,6 +702,7 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
of skMacro: result = semMacroExpr(c, result, nOrig, callee)
|
||||
of skTemplate: result = semTemplateExpr(c, result, callee)
|
||||
else:
|
||||
semFinishOperands(c, n)
|
||||
activate(c, n)
|
||||
fixAbstractType(c, result)
|
||||
analyseIfAddressTakenInCall(c, result)
|
||||
@@ -845,16 +842,17 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
return semSym(c, n, s, flags)
|
||||
|
||||
n.sons[0] = semExprWithType(c, n.sons[0], flags)
|
||||
restoreOldStyleType(n.sons[0])
|
||||
#restoreOldStyleType(n.sons[0])
|
||||
var i = considerAcc(n.sons[1])
|
||||
var ty = n.sons[0].typ
|
||||
var f: PSym = nil
|
||||
result = nil
|
||||
if isTypeExpr(n.sons[0]):
|
||||
if isTypeExpr(n.sons[0]) or ty.kind == tyTypeDesc and ty.len == 1:
|
||||
if ty.kind == tyTypeDesc: ty = ty.sons[0]
|
||||
case ty.kind
|
||||
of tyEnum:
|
||||
of tyEnum:
|
||||
# look up if the identifier belongs to the enum:
|
||||
while ty != nil:
|
||||
while ty != nil:
|
||||
f = getSymFromList(ty.n, i)
|
||||
if f != nil: break
|
||||
ty = ty.sons[0] # enum inheritance
|
||||
@@ -881,7 +879,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
# XXX: This is probably not relevant any more
|
||||
# reset to prevent 'nil' bug: see "tests/reject/tenumitems.nim":
|
||||
ty = n.sons[0].Typ
|
||||
|
||||
|
||||
ty = skipTypes(ty, {tyGenericInst, tyVar, tyPtr, tyRef})
|
||||
var check: PNode = nil
|
||||
if ty.kind == tyObject:
|
||||
|
||||
@@ -484,10 +484,17 @@ proc semForVars(c: PContext, n: PNode): PNode =
|
||||
n.sons[length-1] = SemStmt(c, n.sons[length-1])
|
||||
Dec(c.p.nestedLoopCounter)
|
||||
|
||||
proc newDeref(n: PNode): PNode {.inline.} =
|
||||
result = newNodeIT(nkHiddenDeref, n.info, n.typ.sons[0])
|
||||
addSon(result, n)
|
||||
|
||||
proc implicitIterator(c: PContext, it: string, arg: PNode): PNode =
|
||||
result = newNodeI(nkCall, arg.info)
|
||||
result.add(newIdentNode(it.getIdent, arg.info))
|
||||
result.add(arg)
|
||||
if arg.typ != nil and arg.typ.kind == tyVar:
|
||||
result.add newDeref(arg)
|
||||
else:
|
||||
result.add arg
|
||||
result = semExprNoDeref(c, result, {efWantIterator})
|
||||
|
||||
proc semFor(c: PContext, n: PNode): PNode =
|
||||
@@ -776,8 +783,7 @@ proc activate(c: PContext, n: PNode) =
|
||||
# XXX: This proc is part of my plan for getting rid of
|
||||
# forward declarations. stay tuned.
|
||||
when false:
|
||||
# well for now it breaks code ... I added the test case in main.nim of the
|
||||
# compiler itself to break bootstrapping :P
|
||||
# well for now it breaks code ...
|
||||
case n.kind
|
||||
of nkLambdaKinds:
|
||||
discard semLambda(c, n, {})
|
||||
@@ -1142,8 +1148,8 @@ proc instantiateDestructor*(c: PContext, typ: PType): bool =
|
||||
else:
|
||||
return false
|
||||
|
||||
proc insertDestructors(c: PContext, varSection: PNode):
|
||||
tuple[outer: PNode, inner: PNode] =
|
||||
proc insertDestructors(c: PContext,
|
||||
varSection: PNode): tuple[outer, inner: PNode] =
|
||||
# Accepts a var or let section.
|
||||
#
|
||||
# When a var section has variables with destructors
|
||||
|
||||
@@ -799,6 +799,28 @@ proc setSon(father: PNode, at: int, son: PNode) =
|
||||
if sonsLen(father) <= at: setlen(father.sons, at + 1)
|
||||
father.sons[at] = son
|
||||
|
||||
# we are allowed to modify the calling node in the 'prepare*' procs:
|
||||
proc prepareOperand(c: PContext; formal: PType; a: PNode): PNode =
|
||||
if formal.kind == tyExpr and formal.len != 1:
|
||||
# {tyTypeDesc, tyExpr, tyStmt, tyProxy}:
|
||||
# a.typ == nil is valid
|
||||
result = a
|
||||
elif a.typ.isNil:
|
||||
result = c.semExprWithType(c, a, {efDetermineType})
|
||||
else:
|
||||
result = a
|
||||
|
||||
proc prepareOperand(c: PContext; a: PNode): PNode =
|
||||
if a.typ.isNil:
|
||||
result = c.semExprWithType(c, a, {efDetermineType})
|
||||
else:
|
||||
result = a
|
||||
|
||||
proc prepareNamedParam(a: PNode) =
|
||||
if a.sons[0].kind != nkIdent:
|
||||
var info = a.sons[0].info
|
||||
a.sons[0] = newIdentNode(considerAcc(a.sons[0]), info)
|
||||
|
||||
proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||
m: var TCandidate, marker: var TIntSet) =
|
||||
template checkConstraint(n: expr) {.immediate, dirty.} =
|
||||
@@ -823,6 +845,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||
if n.sons[a].kind == nkExprEqExpr:
|
||||
# named param
|
||||
# check if m.callee has such a param:
|
||||
prepareNamedParam(n.sons[a])
|
||||
if n.sons[a].sons[0].kind != nkIdent:
|
||||
LocalError(n.sons[a].info, errNamedParamHasToBeIdent)
|
||||
m.state = csNoMatch
|
||||
@@ -838,9 +861,11 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||
m.state = csNoMatch
|
||||
return
|
||||
m.baseTypeMatch = false
|
||||
n.sons[a].sons[1] = prepareOperand(c, formal.typ, n.sons[a].sons[1])
|
||||
n.sons[a].typ = n.sons[a].sons[1].typ
|
||||
var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ,
|
||||
n.sons[a].sons[1], nOrig.sons[a].sons[1])
|
||||
if arg == nil:
|
||||
if arg == nil:
|
||||
m.state = csNoMatch
|
||||
return
|
||||
checkConstraint(n.sons[a].sons[1])
|
||||
@@ -852,30 +877,33 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||
if f != formalLen - 1: container = nil
|
||||
else:
|
||||
setSon(m.call, formal.position + 1, arg)
|
||||
else:
|
||||
else:
|
||||
# unnamed param
|
||||
if f >= formalLen:
|
||||
if f >= formalLen:
|
||||
# too many arguments?
|
||||
if tfVarArgs in m.callee.flags:
|
||||
if tfVarArgs in m.callee.flags:
|
||||
# is ok... but don't increment any counters...
|
||||
if skipTypes(n.sons[a].typ, abstractVar).kind == tyString:
|
||||
addSon(m.call, implicitConv(nkHiddenStdConv, getSysType(tyCString),
|
||||
# we have no formal here to snoop at:
|
||||
n.sons[a] = prepareOperand(c, n.sons[a])
|
||||
if skipTypes(n.sons[a].typ, abstractVar).kind == tyString:
|
||||
addSon(m.call, implicitConv(nkHiddenStdConv, getSysType(tyCString),
|
||||
copyTree(n.sons[a]), m, c))
|
||||
else:
|
||||
else:
|
||||
addSon(m.call, copyTree(n.sons[a]))
|
||||
elif formal != nil:
|
||||
m.baseTypeMatch = false
|
||||
n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
|
||||
var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ,
|
||||
n.sons[a], nOrig.sons[a])
|
||||
if (arg != nil) and m.baseTypeMatch and (container != nil):
|
||||
if (arg != nil) and m.baseTypeMatch and (container != nil):
|
||||
addSon(container, arg)
|
||||
else:
|
||||
else:
|
||||
m.state = csNoMatch
|
||||
return
|
||||
else:
|
||||
return
|
||||
else:
|
||||
m.state = csNoMatch
|
||||
return
|
||||
else:
|
||||
return
|
||||
else:
|
||||
if m.callee.n.sons[f].kind != nkSym:
|
||||
InternalError(n.sons[a].info, "matches")
|
||||
return
|
||||
@@ -886,6 +914,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||
m.state = csNoMatch
|
||||
return
|
||||
m.baseTypeMatch = false
|
||||
n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
|
||||
var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ,
|
||||
n.sons[a], nOrig.sons[a])
|
||||
if arg == nil:
|
||||
@@ -898,12 +927,18 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||
setSon(m.call, formal.position + 1,
|
||||
implicitConv(nkHiddenStdConv, formal.typ, container, m, c))
|
||||
if f != formalLen - 1: container = nil
|
||||
else:
|
||||
else:
|
||||
setSon(m.call, formal.position + 1, arg)
|
||||
checkConstraint(n.sons[a])
|
||||
inc(a)
|
||||
inc(f)
|
||||
|
||||
proc semFinishOperands*(c: PContext, n: PNode) =
|
||||
# this needs to be called to ensure that after overloading resolution every
|
||||
# argument has been sem'checked:
|
||||
for i in 1 .. <n.len:
|
||||
n.sons[i] = prepareOperand(c, n.sons[i])
|
||||
|
||||
proc partialMatch*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
|
||||
# for 'suggest' support:
|
||||
var marker = initIntSet()
|
||||
|
||||
7
todo.txt
7
todo.txt
@@ -1,6 +1,9 @@
|
||||
version 0.9.2
|
||||
=============
|
||||
|
||||
- lazy overloading resolution:
|
||||
* get rid of ``expr[typ]``, use perhaps ``static[typ]`` instead
|
||||
* typedesc[T] needs to be documented in ast.nim
|
||||
- FFI:
|
||||
* test libffi on windows
|
||||
* test: times.format with the FFI
|
||||
@@ -15,6 +18,8 @@ version 0.9.2
|
||||
version 0.9.4
|
||||
=============
|
||||
|
||||
- provide tool/API to track leaks/object counts
|
||||
- use big blocks in the allocator
|
||||
- make 'bind' default for templates and introduce 'mixin';
|
||||
special rule for ``[]=``
|
||||
- implicit deref for parameter matching; overloading based on 'var T'
|
||||
@@ -123,3 +128,5 @@ Bugs
|
||||
- blocks can "export" an identifier but the CCG generates {} for them ...
|
||||
- JS gen: fix exception handling
|
||||
- the better scoping for locals is the wrong default for endb
|
||||
- osproc execProcesses can deadlock if all processes fail (as experienced
|
||||
in c++ mode)
|
||||
|
||||
Reference in New Issue
Block a user