bugfixes for generics; new threads implementation still broken

This commit is contained in:
Araq 2011-09-20 00:56:48 +02:00
commit fd62116f6e
19 changed files with 260 additions and 126 deletions

View file

@ -279,8 +279,8 @@ type
TTypeFlags* = set[TTypeFlag]
TSymKind* = enum # the different symbols (start with the prefix sk);
# order is important for the documentation generator!
TSymKind* = enum # the different symbols (start with the prefix sk);
# order is important for the documentation generator!
skUnknown, # unknown symbol: used for parsing assembler blocks
# and first phase symbol lookup in generics
skConditional, # symbol for the preprocessor (may become obsolete)
@ -848,6 +848,10 @@ proc initNodeTable(x: var TNodeTable) =
proc sonsLen(n: PType): int =
if isNil(n.sons): result = 0
else: result = len(n.sons)
proc len*(n: PType): int =
if isNil(n.sons): result = 0
else: result = len(n.sons)
proc newSons(father: PType, length: int) =
if isNil(father.sons): father.sons = @[]

View file

@ -46,7 +46,6 @@ proc StrTableContains*(t: TStrTable, n: PSym): bool
proc StrTableAdd*(t: var TStrTable, n: PSym)
proc StrTableGet*(t: TStrTable, name: PIdent): PSym
# the iterator scheme:
type
TTabIter*{.final.} = object # consider all fields here private
h*: THash # current hash
@ -749,6 +748,10 @@ proc IdTablePut(t: var TIdTable, key: PIdObj, val: PObject) =
IdTableRawInsert(t.data, key, val)
inc(t.counter)
iterator IdTablePairs*(t: TIdTable): tuple[key: PIdObj, val: PObject] =
for i in 0 .. high(t.data):
if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)
proc writeIdNodeTable(t: TIdNodeTable) =
nil

View file

@ -49,6 +49,13 @@ proc ProcessCmdLine(pass: TCmdLinePass, command, filename: var string) =
if optRun notin gGlobalOptions and arguments != "":
rawMessage(errArgsNeedRunOption, [])
proc prependCurDir(f: string): string =
when defined(unix):
if os.isAbsolute(f): result = f
else: result = "./" & f
else:
result = f
proc HandleCmdLine() =
var start = epochTime()
if paramCount() == 0:
@ -79,11 +86,8 @@ proc HandleCmdLine() =
rawMessage(hintSuccessX, [$gLinesCompiled,
formatFloat(epochTime() - start, ffDecimal, 3)])
if optRun in gGlobalOptions:
when defined(unix):
var prog = "./" & quoteIfContainsWhite(changeFileExt(filename, ""))
else:
var prog = quoteIfContainsWhite(changeFileExt(filename, ""))
execExternalProgram(prog & ' ' & arguments)
var ex = quoteIfContainsWhite(changeFileExt(filename, "").prependCurDir)
execExternalProgram(ex & ' ' & arguments)
#GC_disableMarkAndSweep()
cmdLineInfo = newLineInfo("command line", -1, -1)

View file

@ -53,6 +53,7 @@ const
wExtern, wImportcpp, wImportobjc}
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideEffect,
wThread}
allRoutinePragmas* = procPragmas + iteratorPragmas + lambdaPragmas
proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords)
proc pragmaAsm*(c: PContext, n: PNode): char

View file

@ -146,7 +146,7 @@ proc addCodeForGenerics(c: PContext, n: PNode) =
addSon(n, prc.ast)
lastGenericIdx = Len(generics)
proc semExprNoFlags(c: PContext, n: PNode): PNode =
proc semExprNoFlags(c: PContext, n: PNode): PNode {.procvar.} =
result = semExpr(c, n, {})
proc myOpen(module: PSym, filename: string): PPassContext =

View file

@ -1178,9 +1178,10 @@ 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:
elif n.sons[0].kind == nkSymChoice or n[0].kind == nkBracketExpr and
n[0][0].kind == nkSymChoice:
result = semDirectOp(c, n, flags)
else:
else:
result = semIndirectOp(c, n, flags)
of nkMacroStmt:
result = semMacroStmt(c, n)

View file

@ -29,6 +29,10 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
break
if t.kind == tyGenericParam:
InternalError(a.info, "instantiateGenericParamList: " & q.name.s)
elif t.kind == tyGenericInvokation:
#t = instGenericContainer(c, a, t)
t = generateTypeInstance(c, pt, a, t)
#t = ReplaceTypeVarsT(cl, t)
s.typ = t
addDecl(c, s)
entry.concreteTypes[i] = t
@ -94,6 +98,14 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
closeScope(c.tab)
popInfoContext()
proc sideEffectsCheck(c: PContext, s: PSym) =
if {sfNoSideEffect, sfSideEffect} * s.flags ==
{sfNoSideEffect, sfSideEffect}:
LocalError(s.info, errXhasSideEffects, s.name.s)
elif sfThread in s.flags and semthreads.needsGlobalAnalysis() and
s.ast.sons[genericParamsPos].kind == nkEmpty:
c.threadEntries.add(s)
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
info: TLineInfo): PSym =
# generates an instantiated proc
@ -133,7 +145,10 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
var oldPrc = GenericCacheGet(c, entry)
if oldPrc == nil:
generics.add(entry)
if n.sons[pragmasPos].kind != nkEmpty:
pragma(c, result, n.sons[pragmasPos], allRoutinePragmas)
instantiateBody(c, n, result)
sideEffectsCheck(c, result)
else:
result = oldPrc
popInfoContext()

View file

@ -554,13 +554,6 @@ proc semBorrow(c: PContext, n: PNode, s: PSym) =
n.sons[codePos] = newSymNode(b)
else:
LocalError(n.info, errNoSymbolToBorrowFromFound)
proc sideEffectsCheck(c: PContext, s: PSym) =
if {sfNoSideEffect, sfSideEffect} * s.flags ==
{sfNoSideEffect, sfSideEffect}:
LocalError(s.info, errXhasSideEffects, s.name.s)
elif sfThread in s.flags and semthreads.needsGlobalAnalysis():
c.threadEntries.add(s)
proc addResult(c: PContext, t: PType, info: TLineInfo) =
if t != nil:

View file

@ -216,23 +216,6 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
addSon(result.n, newSymNode(field))
addSon(result, typ)
proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
if s.typ == nil or s.typ.kind != tyGenericBody:
GlobalError(n.info, errCannotInstantiateX, s.name.s)
result = newOrPrevType(tyGenericInvokation, prev, c)
if s.typ.containerID == 0: InternalError(n.info, "semtypes.semGeneric")
if sonsLen(n) != sonsLen(s.typ):
GlobalError(n.info, errWrongNumberOfArguments)
addSon(result, s.typ)
var isConcrete = true # iterate over arguments:
for i in countup(1, sonsLen(n)-1):
var elem = semTypeNode(c, n.sons[i], nil)
if elem.kind in {tyGenericParam, tyGenericInvokation}: isConcrete = false
addSon(result, elem)
if isConcrete:
if s.ast == nil: GlobalError(n.info, errCannotInstantiateX, s.name.s)
result = instGenericContainer(c, n, result)
proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
allowed: TSymFlags): PSym =
# identifier with visibility
@ -489,7 +472,6 @@ proc addTypeVarsOfGenericBody(c: PContext, t: PType, genericParams: PNode,
if ContainsOrIncl(cl, t.id): return
case t.kind
of tyGenericBody:
#debug(t)
result = newTypeS(tyGenericInvokation, c)
addSon(result, t)
for i in countup(0, sonsLen(t) - 2):
@ -505,11 +487,9 @@ proc addTypeVarsOfGenericBody(c: PContext, t: PType, genericParams: PNode,
addSon(genericParams, newSymNode(s))
addSon(result, t.sons[i])
of tyGenericInst:
#debug(t)
var L = sonsLen(t) - 1
t.sons[L] = addTypeVarsOfGenericBody(c, t.sons[L], genericParams, cl)
of tyGenericInvokation:
#debug(t)
for i in countup(1, sonsLen(t) - 1):
t.sons[i] = addTypeVarsOfGenericBody(c, t.sons[i], genericParams, cl)
else:
@ -520,7 +500,6 @@ proc paramType(c: PContext, n, genericParams: PNode, cl: var TIntSet): PType =
result = semTypeNode(c, n, nil)
if genericParams != nil and sonsLen(genericParams) == 0:
result = addTypeVarsOfGenericBody(c, result, genericParams, cl)
#if result.kind == tyGenericInvokation: debug(result)
proc semProcTypeNode(c: PContext, n, genericParams: PNode,
prev: PType): PType =
@ -546,6 +525,9 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
var length = sonsLen(a)
if a.sons[length-2].kind != nkEmpty:
typ = paramType(c, a.sons[length-2], genericParams, cl)
#if matchType(typ, [(tyVar, 0)], tyGenericInvokation):
# debug a.sons[length-2][0][1]
else:
typ = nil
if a.sons[length-1].kind != nkEmpty:
@ -557,8 +539,9 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
# and def.typ != nil and def.typ.kind != tyNone:
# example code that triggers it:
# proc sort[T](cmp: proc(a, b: T): int = cmp)
def = fitNode(c, typ, def)
else:
if not containsGenericType(typ):
def = fitNode(c, typ, def)
else:
def = ast.emptyNode
if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue
for j in countup(0, length-3):
@ -578,6 +561,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
result.sons[0] = r
res.typ = result.sons[0]
#if matchType(result, [(tyProc, 1), (tyVar, 0)], tyGenericInvokation):
# debug result
proc semStmtListType(c: PContext, n: PNode, prev: PType): PType =
checkMinSonsLen(n, 1)
@ -603,6 +588,50 @@ proc semBlockType(c: PContext, n: PNode, prev: PType): PType =
closeScope(c.tab)
Dec(c.p.nestedBlockCounter)
proc semGenericParamInInvokation(c: PContext, n: PNode): PType =
# XXX hack 1022 for generics ... would have been nice if the compiler had
# been designed with them in mind from start ...
when false:
if n.kind == nkSym:
# for generics we need to lookup the type var again:
var s = SymtabGet(c.Tab, n.sym.name)
if s != nil:
if s.kind == skType and s.typ != nil:
var t = n.sym.typ
echo "came here"
return t
else:
echo "s is crap:"
debug(s)
else:
echo "s is nil!!!!"
result = semTypeNode(c, n, nil)
proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
if s.typ == nil or s.typ.kind != tyGenericBody:
GlobalError(n.info, errCannotInstantiateX, s.name.s)
result = newOrPrevType(tyGenericInvokation, prev, c)
if s.typ.containerID == 0: InternalError(n.info, "semtypes.semGeneric")
if sonsLen(n) != sonsLen(s.typ):
GlobalError(n.info, errWrongNumberOfArguments)
addSon(result, s.typ)
var isConcrete = true # iterate over arguments:
for i in countup(1, sonsLen(n)-1):
var elem = semGenericParamInInvokation(c, n.sons[i])
if containsGenericType(elem): isConcrete = false
#if elem.kind in {tyGenericParam, tyGenericInvokation}: isConcrete = false
addSon(result, elem)
if isConcrete:
if s.ast == nil: GlobalError(n.info, errCannotInstantiateX, s.name.s)
result = instGenericContainer(c, n, result)
proc FixupRemainingGenericInvokations(c: PContext, n: PNode,
typ: PType): PType =
if typ.kind == tyGenericInvokation:
nil
else:
result = typ
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
result = nil
if gCmd == cmdIdeTools: suggestExpr(c, n)

View file

@ -92,51 +92,90 @@ proc ReplaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym =
proc lookupTypeVar(cl: TReplTypeVars, t: PType): PType =
result = PType(idTableGet(cl.typeMap, t))
if result == nil:
if result == nil:
GlobalError(t.sym.info, errCannotInstantiateX, typeToString(t))
elif result.kind == tyGenericParam:
InternalError(cl.info, "substitution with generic parameter")
proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
# tyGenericInvokation[A, tyGenericInvokation[A, B]]
# is difficult to handle:
var body = t.sons[0]
if body.kind != tyGenericBody: InternalError(cl.info, "no generic body")
var header: PType = nil
for i in countup(1, sonsLen(t) - 1):
var x = replaceTypeVarsT(cl, t.sons[i])
if t.sons[i].kind == tyGenericParam:
if header == nil: header = copyType(t, t.owner, false)
header.sons[i] = x
when false:
var x: PType
if t.sons[i].kind == tyGenericParam:
x = lookupTypeVar(cl, t.sons[i])
when true:
# search for some instantiation here:
result = searchInstTypes(gInstTypes, t)
if result != nil: return
for i in countup(1, sonsLen(t) - 1):
var x = t.sons[i]
if x.kind == tyGenericParam:
x = lookupTypeVar(cl, x)
if header == nil: header = copyType(t, t.owner, false)
header.sons[i] = x
else:
x = t.sons[i]
idTablePut(cl.typeMap, body.sons[i-1], x)
if header == nil: header = t
result = searchInstTypes(gInstTypes, header)
if result != nil: return
result = newType(tyGenericInst, t.sons[0].owner)
for i in countup(0, sonsLen(t) - 1):
# if one of the params is not concrete, we cannot do anything
# but we already raised an error!
addSon(result, header.sons[i])
idTablePut(gInstTypes, header, result)
var newbody = ReplaceTypeVarsT(cl, lastSon(body))
newbody.flags = newbody.flags + t.flags + body.flags
newbody.n = ReplaceTypeVarsN(cl, lastSon(body).n)
addSon(result, newbody)
#writeln(output, ropeToStr(Typetoyaml(newbody)));
checkPartialConstructedType(cl.info, newbody)
#idTablePut(cl.typeMap, body.sons[i-1], x)
if header != nil:
# search again after first pass:
result = searchInstTypes(gInstTypes, header)
if result != nil: return
else:
header = copyType(t, t.owner, false)
# ugh need another pass for deeply recursive generic types (e.g. PActor)
# we need to add the candidate here, before it's fully instantiated for
# recursive instantions:
result = newType(tyGenericInst, t.sons[0].owner)
idTablePut(gInstTypes, header, result)
for i in countup(1, sonsLen(t) - 1):
var x = replaceTypeVarsT(cl, t.sons[i])
assert x.kind != tyGenericInvokation
header.sons[i] = x
idTablePut(cl.typeMap, body.sons[i-1], x)
for i in countup(0, sonsLen(t) - 1):
# if one of the params is not concrete, we cannot do anything
# but we already raised an error!
addSon(result, header.sons[i])
var newbody = ReplaceTypeVarsT(cl, lastSon(body))
newbody.flags = newbody.flags + t.flags + body.flags
result.flags = result.flags + newbody.flags
newbody.callConv = body.callConv
newbody.n = ReplaceTypeVarsN(cl, lastSon(body).n)
addSon(result, newbody)
checkPartialConstructedType(cl.info, newbody)
else:
for i in countup(1, sonsLen(t) - 1):
if PType(idTableGet(cl.typeMap, t.sons[i])) == nil: debug(t)
var x = replaceTypeVarsT(cl, t.sons[i])
if t.sons[i].kind == tyGenericParam:
if header == nil: header = copyType(t, t.owner, false)
header.sons[i] = x
assert x.kind != tyGenericInvokation
idTablePut(cl.typeMap, body.sons[i-1], x)
if header == nil: header = t
result = searchInstTypes(gInstTypes, header)
if result != nil: return
result = newType(tyGenericInst, t.sons[0].owner)
for i in countup(0, sonsLen(t) - 1):
# if one of the params is not concrete, we cannot do anything
# but we already raised an error!
addSon(result, header.sons[i])
idTablePut(gInstTypes, header, result)
var newbody = ReplaceTypeVarsT(cl, lastSon(body))
newbody.flags = newbody.flags + t.flags + body.flags
newbody.n = ReplaceTypeVarsN(cl, lastSon(body).n)
addSon(result, newbody)
checkPartialConstructedType(cl.info, newbody)
proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
result = t
if t == nil: return
case t.kind
of tyGenericParam:
of tyGenericParam:
result = lookupTypeVar(cl, t)
if result.kind == tyGenericInvokation:
result = handleGenericInvokation(cl, result)
of tyGenericInvokation:
result = handleGenericInvokation(cl, t)
of tyGenericBody:
@ -151,9 +190,10 @@ proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
result.n = ReplaceTypeVarsN(cl, result.n)
if result.Kind in GenericTypes:
LocalError(cl.info, errCannotInstantiateX, TypeToString(t, preferName))
#writeln(output, ropeToStr(Typetoyaml(result)))
#checkConstructedType(cl.info, result)
if result.kind == tyProc and result.sons[0] != nil:
if result.sons[0].kind == tyEmpty:
result.sons[0] = nil
proc generateTypeInstance*(p: PContext, pt: TIdTable, arg: PNode,
t: PType): PType =
var cl: TReplTypeVars

View file

@ -137,6 +137,8 @@ proc concreteType(mapping: TIdTable, t: PType): PType =
# example code that triggers it:
# proc sort[T](cmp: proc(a, b: T): int = cmp)
if result.kind != tyGenericParam: break
of tyGenericInvokation:
assert false
else:
result = t # Note: empty is valid here
@ -388,8 +390,10 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
of tyGenericInvokation:
assert(f.sons[0].kind == tyGenericBody)
if a.kind == tyGenericInvokation:
InternalError("typeRel: tyGenericInvokation -> tyGenericInvokation")
if (a.kind == tyGenericInst):
#InternalError("typeRel: tyGenericInvokation -> tyGenericInvokation")
# simply no match for now:
nil
elif a.kind == tyGenericInst:
if (f.sons[0].containerID == a.sons[0].containerID) and
(sonsLen(a) - 1 == sonsLen(f)):
assert(a.sons[0].kind == tyGenericBody)
@ -404,7 +408,7 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
# we steal the generic parameters from the tyGenericBody:
for i in countup(1, sonsLen(f) - 1):
var x = PType(idTableGet(mapping, f.sons[0].sons[i - 1]))
if x == nil or x.kind == tyGenericParam:
if x == nil or x.kind in {tyGenericInvokation, tyGenericParam}:
InternalError("wrong instantiated type!")
idTablePut(mapping, f.sons[i], x)
of tyGenericParam:
@ -413,8 +417,7 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
if sonsLen(f) == 0:
# no constraints
var concrete = concreteType(mapping, a)
if concrete != nil:
#MessageOut('putting: ' + f.sym.name.s);
if concrete != nil:
idTablePut(mapping, f, concrete)
result = isGeneric
else:

View file

@ -728,7 +728,16 @@ proc typeAllowedNode(marker: var TIntSet, n: PNode, kind: TSymKind): bool =
else:
for i in countup(0, sonsLen(n) - 1):
result = typeAllowedNode(marker, n.sons[i], kind)
if not result: return
if not result: break
proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]],
last: TTypeKind): bool =
var a = a
for k, i in pattern.items:
if a.kind != k: return false
if i >= a.sonslen or a.sons[i] == nil: return false
a = a.sons[i]
result = a.kind == last
proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
assert(kind in {skVar, skConst, skParam, skResult})
@ -751,13 +760,14 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
of tyProc:
for i in countup(1, sonsLen(t) - 1):
result = typeAllowedAux(marker, t.sons[i], skParam)
if not result: return
if t.sons[0] != nil: result = typeAllowedAux(marker, t.sons[0], skResult)
if not result: break
if result and t.sons[0] != nil:
result = typeAllowedAux(marker, t.sons[0], skResult)
of tyExpr, tyStmt, tyTypeDesc:
result = true
of tyGenericBody, tyGenericParam, tyForward, tyNone, tyGenericInvokation:
result = false #InternalError('shit found');
of tyEmpty, tyNil:
of tyEmpty, tyNil:
result = kind == skConst
of tyString, tyBool, tyChar, tyEnum, tyInt..tyFloat128, tyCString, tyPointer:
result = true
@ -781,13 +791,13 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
of tyArrayConstr, tyTuple, tySet:
for i in countup(0, sonsLen(t) - 1):
result = typeAllowedAux(marker, t.sons[i], kind)
if not result: return
if not result: break
of tyObject:
for i in countup(0, sonsLen(t) - 1):
result = typeAllowedAux(marker, t.sons[i], skVar)
if not result: return
if t.n != nil: result = typeAllowedNode(marker, t.n, skVar)
if not result: break
if result and t.n != nil: result = typeAllowedNode(marker, t.n, skVar)
proc typeAllowed(t: PType, kind: TSymKind): bool =
var marker = InitIntSet()
result = typeAllowedAux(marker, t, kind)