Merge branch 'master' of github.com:Araq/Nimrod

This commit is contained in:
Araq 2013-08-30 12:44:27 +02:00
commit 8710118b2c
22 changed files with 384 additions and 133 deletions

View file

@ -626,6 +626,7 @@ type
case kind*: TSymKind
of skType:
typeInstCache*: seq[PType]
typScope*: PScope
of routineKinds:
procInstCache*: seq[PInstantiation]
scope*: PScope # the scope where the proc was defined
@ -799,9 +800,9 @@ const
# imported via 'importc: "fullname"' and no format string.
# creator procs:
proc NewSym*(symKind: TSymKind, Name: PIdent, owner: PSym,
proc newSym*(symKind: TSymKind, Name: PIdent, owner: PSym,
info: TLineInfo): PSym
proc NewType*(kind: TTypeKind, owner: PSym): PType
proc newType*(kind: TTypeKind, owner: PSym): PType
proc newNode*(kind: TNodeKind): PNode
proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode
proc newIntTypeNode*(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode
@ -1111,7 +1112,7 @@ proc copySym(s: PSym, keepId: bool = false): PSym =
result.loc = s.loc
result.annex = s.annex # BUGFIX
proc NewSym(symKind: TSymKind, Name: PIdent, owner: PSym,
proc newSym(symKind: TSymKind, Name: PIdent, owner: PSym,
info: TLineInfo): PSym =
# generates a symbol and initializes the hash field too
new(result)

View file

@ -904,18 +904,15 @@ proc evalParseStmt(c: PEvalContext, n: PNode): PNode =
code.info.line.int)
#result.typ = newType(tyStmt, c.module)
proc evalTypeTrait*(n: PNode, context: PSym): PNode =
## XXX: This should be pretty much guaranteed to be true
# by the type traits procs' signatures, but until the
# code is more mature it doesn't hurt to be extra safe
internalAssert n.sons.len >= 2 and n.sons[1].kind == nkSym
proc evalTypeTrait*(trait, operand: PNode, context: PSym): PNode =
InternalAssert operand.kind == nkSym
let typ = n.sons[1].sym.typ.skipTypes({tyTypeDesc})
case n.sons[0].sym.name.s.normalize
let typ = operand.sym.typ.skipTypes({tyTypeDesc})
case trait.sym.name.s.normalize
of "name":
result = newStrNode(nkStrLit, typ.typeToString(preferExported))
result = newStrNode(nkStrLit, typ.typeToString(preferName))
result.typ = newType(tyString, context)
result.info = n.info
result.info = trait.info
else:
internalAssert false
@ -1037,8 +1034,8 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
of mParseStmtToAst: result = evalParseStmt(c, n)
of mExpandToAst: result = evalExpandToAst(c, n)
of mTypeTrait:
n.sons[1] = evalAux(c, n.sons[1], {})
result = evalTypeTrait(n, c.module)
let operand = evalAux(c, n.sons[1], {})
result = evalTypeTrait(n[0], operand, c.module)
of mIs:
n.sons[1] = evalAux(c, n.sons[1], {})
result = evalIsOp(n)

View file

@ -156,6 +156,8 @@ var
const oKeepVariableNames* = true
const oUseLateInstantiation* = false
proc mainCommandArg*: string =
## This is intended for commands like check or parse
## which will work on the main project file unless

View file

@ -225,14 +225,14 @@ proc fillTypeS(dest: PType, kind: TTypeKind, c: PContext) =
dest.owner = getCurrOwner()
dest.size = - 1
proc makeRangeType*(c: PContext, first, last: biggestInt,
info: TLineInfo): PType =
proc makeRangeType*(c: PContext; first, last: biggestInt;
info: TLineInfo; intType = getSysType(tyInt)): PType =
var n = newNodeI(nkRange, info)
addSon(n, newIntNode(nkIntLit, first))
addSon(n, newIntNode(nkIntLit, last))
addSon(n, newIntTypeNode(nkIntLit, first, intType))
addSon(n, newIntTypeNode(nkIntLit, last, intType))
result = newTypeS(tyRange, c)
result.n = n
rawAddSon(result, getSysType(tyInt)) # basetype of range
addSonSkipIntLit(result, intType) # basetype of range
proc markIndirect*(c: PContext, s: PSym) {.inline.} =
if s.kind in {skProc, skConverter, skMethod, skIterator}:

View file

@ -113,7 +113,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
of skGenericParam:
if s.typ.kind == tyExpr:
result = newSymNode(s, n.info)
result.typ = s.typ.lastSon
result.typ = s.typ
elif s.ast != nil:
result = semExpr(c, s.ast)
else:

View file

@ -561,9 +561,10 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
case n.kind
of nkSym:
var s = n.sym
if s.kind == skEnumField:
case s.kind
of skEnumField:
result = newIntNodeT(s.position, n)
elif s.kind == skConst:
of skConst:
case s.magic
of mIsMainModule: result = newIntNodeT(ord(sfMainModule in m.flags), n)
of mCompileDate: result = newStrNodeT(times.getDateStr(), n)
@ -581,10 +582,17 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
of mNegInf: result = newFloatNodeT(NegInf, n)
else:
if sfFakeConst notin s.flags: result = copyTree(s.ast)
elif s.kind in {skProc, skMethod}: # BUGFIX
of {skProc, skMethod}:
result = n
elif s.kind in {skType, skGenericParam}:
of skType:
result = newSymNodeTypeDesc(s, n.info)
of skGenericParam:
if s.typ.kind == tyExpr:
result = s.typ.n
result.typ = s.typ.sons[0]
else:
result = newSymNodeTypeDesc(s, n.info)
else: nil
of nkCharLit..nkNilLit:
result = copyNode(n)
of nkIfExpr:

View file

@ -130,13 +130,50 @@ proc sideEffectsCheck(c: PContext, s: PSym) =
s.ast.sons[genericParamsPos].kind == nkEmpty:
c.threadEntries.add(s)
proc lateInstantiateGeneric(c: PContext, invocation: PType, info: TLineInfo): PType =
InternalAssert invocation.kind == tyGenericInvokation
let cacheHit = searchInstTypes(invocation)
if cacheHit != nil:
result = cacheHit
else:
let s = invocation.sons[0].sym
let oldScope = c.currentScope
c.currentScope = s.typScope
openScope(c)
pushInfoContext(info)
for i in 0 .. <s.typ.n.sons.len:
let genericParam = s.typ.n[i].sym
let symKind = if genericParam.typ.kind == tyExpr: skConst
else: skType
var boundSym = newSym(symKind, s.typ.n[i].sym.name, s, info)
boundSym.typ = invocation.sons[i+1].skipTypes({tyExpr})
boundSym.ast = invocation.sons[i+1].n
addDecl(c, boundSym)
# XXX: copyTree would have been unnecessary here if semTypeNode
# didn't modify its input parameters. Currently, it does modify
# at least the record lists of the passed object and tuple types
var instantiated = semTypeNode(c, copyTree(s.ast[2]), nil)
popInfoContext()
closeScope(c)
c.currentScope = oldScope
if instantiated != nil:
result = invocation
result.kind = tyGenericInst
result.sons.add instantiated
cacheTypeInst result
proc instGenericContainer(c: PContext, info: TLineInfo, header: PType): PType =
var cl: TReplTypeVars
InitIdTable(cl.symMap)
InitIdTable(cl.typeMap)
cl.info = info
cl.c = c
result = ReplaceTypeVarsT(cl, header)
when oUseLateInstantiation:
lateInstantiateGeneric(c, header, info)
else:
var cl: TReplTypeVars
InitIdTable(cl.symMap)
InitIdTable(cl.typeMap)
cl.info = info
cl.c = c
result = ReplaceTypeVarsT(cl, header)
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
result = instGenericContainer(c, n.info, header)

View file

@ -40,7 +40,7 @@ proc semTypeTraits(c: PContext, n: PNode): PNode =
(typArg.kind == skParam and typArg.typ.sonsLen > 0):
# This is either a type known to sem or a typedesc
# param to a regular proc (again, known at instantiation)
result = evalTypeTrait(n, GetCurrOwner())
result = evalTypeTrait(n[0], n[1], GetCurrOwner())
else:
# a typedesc variable, pass unmodified to evals
result = n

View file

@ -729,12 +729,16 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
# like: mydata.seq
rawAddSon(s.typ, newTypeS(tyEmpty, c))
s.ast = a
inc c.InGenericContext
var body = semTypeNode(c, a.sons[2], nil)
dec c.InGenericContext
if body != nil:
body.sym = s
body.size = -1 # could not be computed properly
when oUseLateInstantiation:
var body: PType = nil
s.typScope = c.currentScope.parent
else:
inc c.InGenericContext
var body = semTypeNode(c, a.sons[2], nil)
dec c.InGenericContext
if body != nil:
body.sym = s
body.size = -1 # could not be computed properly
s.typ.sons[sonsLen(s.typ) - 1] = body
popOwner()
closeScope(c)

View file

@ -156,7 +156,7 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
LocalError(n.Info, errRangeIsEmpty)
var a = semConstExpr(c, n[1])
var b = semConstExpr(c, n[2])
if not sameType(a.typ, b.typ):
if not sameType(a.typ, b.typ):
LocalError(n.info, errPureTypeMismatch)
elif a.typ.kind notin {tyInt..tyInt64,tyEnum,tyBool,tyChar,
tyFloat..tyFloat128,tyUInt8..tyUInt32}:
@ -195,17 +195,19 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType =
else:
let e = semExprWithType(c, n.sons[1], {efDetermineType})
if e.kind in {nkIntLit..nkUInt64Lit}:
indx = newTypeS(tyRange, c)
indx.n = newNodeI(nkRange, n.info)
addSon(indx.n, newIntTypeNode(e.kind, 0, e.typ))
addSon(indx.n, newIntTypeNode(e.kind, e.intVal-1, e.typ))
addSonSkipIntLit(indx, e.typ)
indx = makeRangeType(c, 0, e.intVal-1, n.info, e.typ)
elif e.kind == nkSym and e.typ.kind == tyExpr:
if e.sym.ast != nil: return semArray(c, e.sym.ast, nil)
InternalAssert c.InGenericContext > 0
if not isOrdinalType(e.typ.lastSon):
localError(n[1].info, errOrdinalTypeExpected)
indx = e.typ
else:
indx = e.typ.skipTypes({tyTypeDesc})
addSonSkipIntLit(result, indx)
if indx.kind == tyGenericInst: indx = lastSon(indx)
if indx.kind != tyGenericParam:
if not isOrdinalType(indx):
if indx.kind notin {tyGenericParam, tyExpr}:
if not isOrdinalType(indx):
LocalError(n.sons[1].info, errOrdinalTypeExpected)
elif enumHasHoles(indx):
LocalError(n.sons[1].info, errEnumXHasHoles, indx.sym.name.s)
@ -587,6 +589,8 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
else:
if sfGenSym notin param.flags: addDecl(c, param)
let typedescId = getIdent"typedesc"
proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
paramType: PType, paramName: string,
info: TLineInfo, anon = false): PType =
@ -634,6 +638,9 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
result = addImplicitGeneric(c.newTypeWithSons(tyExpr, paramType.sons))
of tyTypeDesc:
if tfUnresolved notin paramType.flags:
# naked typedescs are not bindOnce types
if paramType.sonsLen == 0 and paramTypId != nil and
paramTypId.id == typedescId.id: paramTypId = nil
result = addImplicitGeneric(c.newTypeWithSons(tyTypeDesc, paramType.sons))
of tyDistinct:
if paramType.sonsLen == 1:
@ -760,7 +767,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
r.flags.incl tfRetType
result.sons[0] = skipIntLit(r)
res.typ = result.sons[0]
proc semStmtListType(c: PContext, n: PNode, prev: PType): PType =
checkMinSonsLen(n, 1)
var length = sonsLen(n)
@ -846,7 +853,10 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
LocalError(n.info, errCannotInstantiateX, s.name.s)
result = newOrPrevType(tyError, prev, c)
else:
result = instGenericContainer(c, n, result)
when oUseLateInstantiation:
result = lateInstantiateGeneric(c, result, n.info)
else:
result = instGenericContainer(c, n, result)
proc semTypeExpr(c: PContext, n: PNode): PType =
var n = semExprWithType(c, n, {efDetermineType})
@ -1073,8 +1083,9 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
if constraint.kind != nkEmpty:
typ = semTypeNode(c, constraint, nil)
if typ.kind != tyExpr or typ.len == 0:
if typ.len == 0 and typ.kind == tyTypeDesc:
typ = newTypeS(tyGenericParam, c)
if typ.kind == tyTypeDesc:
if typ.len == 0:
typ = newTypeS(tyTypeDesc, c)
else:
typ = semGenericConstraints(c, typ)

View file

@ -31,7 +31,7 @@ proc checkConstructedType*(info: TLineInfo, typ: PType) =
if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags:
localError(info, errInheritanceOnlyWithNonFinalObjects)
proc searchInstTypes(key: PType): PType =
proc searchInstTypes*(key: PType): PType =
let genericTyp = key.sons[0]
InternalAssert genericTyp.kind == tyGenericBody and
key.sons[0] == genericTyp and
@ -55,7 +55,7 @@ proc searchInstTypes(key: PType): PType =
return inst
proc cacheTypeInst(inst: PType) =
proc cacheTypeInst*(inst: PType) =
# XXX: add to module's generics
# update the refcount
let genericTyp = inst.sons[0]
@ -208,6 +208,12 @@ proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
of tyInt:
result = skipIntLit(t)
else:
if t.kind == tyArray:
let idxt = t.sons[0]
if idxt.kind == tyExpr and
idxt.sym != nil and idxt.sym.kind == skGenericParam:
let value = lookupTypeVar(cl, idxt).n
t.sons[0] = makeRangeType(cl.c, 0, value.intVal - 1, value.info)
if containsGenericType(t):
result = copyType(t, t.owner, false)
incl(result.flags, tfFromGeneric)

View file

@ -626,7 +626,8 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
of tyGenericParam, tyTypeClass:
var x = PType(idTableGet(c.bindings, f))
if x == nil:
if c.calleeSym.kind == skType and f.kind == tyGenericParam and not c.typedescMatched:
if c.calleeSym != nil and c.calleeSym.kind == skType and
f.kind == tyGenericParam and not c.typedescMatched:
# XXX: The fact that generic types currently use tyGenericParam for
# their parameters is really a misnomer. tyGenericParam means "match
# any value" and what we need is "match any type", which can be encoded
@ -670,7 +671,9 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
result = isNone
else:
InternalAssert prev.sonsLen == 1
result = typeRel(c, prev.sons[0], a)
let toMatch = if tfUnresolved in f.flags: a
else: a.sons[0]
result = typeRel(c, prev.sons[0], toMatch)
of tyExpr, tyStmt:
result = isGeneric
of tyProxy:
@ -772,6 +775,7 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
if evaluated != nil:
r = isGeneric
arg.typ = newTypeS(tyExpr, c)
arg.typ.sons = @[evaluated.typ]
arg.typ.n = evaluated
if r == isGeneric: