diff options
Diffstat (limited to 'compiler/semtypinst.nim')
-rw-r--r-- | compiler/semtypinst.nim | 119 |
1 files changed, 71 insertions, 48 deletions
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index c53464f80..c5caf8b92 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -1,7 +1,7 @@ # # # The Nim Compiler -# (c) Copyright 2014 Andreas Rumpf +# (c) Copyright 2015 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -16,9 +16,9 @@ const proc sharedPtrCheck(info: TLineInfo, t: PType) = if t.kind == tyPtr and t.len > 1: - if t.sons[0].sym.magic in {mShared, mGuarded}: + if t.sons[0].sym.magic == mShared: incl(t.flags, tfShared) - if t.sons[0].sym.magic == mGuarded: incl(t.flags, tfGuarded) + #if t.sons[0].sym.magic == mGuarded: incl(t.flags, tfGuarded) if tfHasGCedMem in t.flags or t.isGCedMem: localError(info, errGenerated, "shared memory may not refer to GC'ed thread local memory") @@ -34,9 +34,9 @@ proc checkPartialConstructedType(info: TLineInfo, t: PType) = proc checkConstructedType*(info: TLineInfo, typ: PType) = var t = typ.skipTypes({tyDistinct}) if t.kind in tyTypeClasses: discard - elif tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject: + elif tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject: localError(info, errInvalidPragmaX, "acyclic") - elif t.kind == tyVar and t.sons[0].kind == tyVar: + elif t.kind == tyVar and t.sons[0].kind == tyVar: localError(info, errVarVarTypeNotAllowed) elif computeSize(t) == szIllegalRecursion: localError(info, errIllegalRecursionInTypeX, typeToString(t)) @@ -44,7 +44,7 @@ proc checkConstructedType*(info: TLineInfo, typ: PType) = sharedPtrCheck(info, t) when false: if t.kind == tyObject and t.sons[0] != nil: - if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags: + if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags: localError(info, errInheritanceOnlyWithNonFinalObjects) proc searchInstTypes*(key: PType): PType = @@ -61,7 +61,7 @@ proc searchInstTypes*(key: PType): PType = if inst.sons.len < key.sons.len: # XXX: This happens for prematurely cached # types such as TChannel[empty]. Why? - # See the notes for PActor in handleGenericInvokation + # See the notes for PActor in handleGenericInvocation return block matchType: for j in 1 .. high(key.sons): @@ -69,7 +69,7 @@ proc searchInstTypes*(key: PType): PType = if not compareTypes(inst.sons[j], key.sons[j], flags = {ExactGenericParams}): break matchType - + return inst proc cacheTypeInst*(inst: PType) = @@ -79,7 +79,7 @@ proc cacheTypeInst*(inst: PType) = genericTyp.sym.typeInstCache.safeAdd(inst) type - TReplTypeVars* {.final.} = object + TReplTypeVars* {.final.} = object c*: PContext typeMap*: TIdTable # map PType to PType symMap*: TIdTable # map PSym to PSym @@ -89,6 +89,7 @@ type info*: TLineInfo allowMetaTypes*: bool # allow types such as seq[Number] # i.e. the result contains unresolved generics + skipTypedesc*: bool # wether we should skip typeDescs proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym @@ -101,7 +102,6 @@ template checkMetaInvariants(cl: TReplTypeVars, t: PType) = echo "UNEXPECTED META ", t.id, " ", instantiationInfo(-1) debug t writeStackTrace() - quit 1 proc replaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType = result = replaceTypeVarsTAux(cl, t) @@ -152,7 +152,7 @@ proc reResolveCallsWithTypedescParams(cl: var TReplTypeVars, n: PNode): PNode = if needsFixing: n.sons[0] = newSymNode(n.sons[0].sym.owner) return cl.c.semOverloadedCall(cl.c, n, n, {skProc}) - + for i in 0 .. <n.safeLen: n.sons[i] = reResolveCallsWithTypedescParams(cl, n[i]) @@ -204,18 +204,18 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode = newSons(result, length) for i in countup(0, length - 1): result.sons[i] = replaceTypeVarsN(cl, n.sons[i]) - -proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym = + +proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym = if s == nil: return nil result = PSym(idTableGet(cl.symMap, s)) - if result == nil: + if result == nil: result = copySym(s, false) incl(result.flags, sfFromGeneric) idTablePut(cl.symMap, s, result) result.owner = s.owner result.typ = replaceTypeVarsT(cl, s.typ) result.ast = replaceTypeVarsN(cl, s.ast) - + proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType = result = PType(idTableGet(cl.typeMap, t)) if result == nil: @@ -224,7 +224,7 @@ proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType = result = errorType(cl.c) # In order to prevent endless recursions, we must remember # this bad lookup and replace it with errorType everywhere. - # These code paths are only active in nimrod check + # These code paths are only active in "nim check" idTablePut(cl.typeMap, t, result) elif result.kind == tyGenericParam and not cl.allowMetaTypes: internalError(cl.info, "substitution with generic parameter") @@ -233,11 +233,13 @@ proc instCopyType*(cl: var TReplTypeVars, t: PType): PType = # XXX: relying on allowMetaTypes is a kludge result = copyType(t, t.owner, cl.allowMetaTypes) result.flags.incl tfFromGeneric - result.flags.excl tfInstClearedFlags + if not (t.kind in tyMetaTypes or + (t.kind == tyStatic and t.n == nil)): + result.flags.excl tfInstClearedFlags -proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType = - # tyGenericInvokation[A, tyGenericInvokation[A, B]] - # is difficult to handle: +proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = + # tyGenericInvocation[A, tyGenericInvocation[A, B]] + # is difficult to handle: var body = t.sons[0] if body.kind != tyGenericBody: internalError(cl.info, "no generic body") var header: PType = t @@ -246,7 +248,7 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType = result = PType(idTableGet(cl.localCache, t)) else: result = searchInstTypes(t) - if result != nil: return + if result != nil and eqTypeFlags*result.flags == eqTypeFlags*t.flags: return for i in countup(1, sonsLen(t) - 1): var x = t.sons[i] if x.kind == tyGenericParam: @@ -257,14 +259,14 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType = propagateToOwner(header, x) else: propagateToOwner(header, x) - + if header != t: # search again after first pass: result = searchInstTypes(header) - if result != nil: return + if result != nil and eqTypeFlags*result.flags == eqTypeFlags*t.flags: return else: header = instCopyType(cl, t) - + result = newType(tyGenericInst, t.sons[0].owner) result.flags = header.flags # be careful not to propagate unnecessary flags here (don't use rawAddSon) @@ -277,25 +279,29 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType = else: idTablePut(cl.localCache, t, result) + let oldSkipTypedesc = cl.skipTypedesc + cl.skipTypedesc = true for i in countup(1, sonsLen(t) - 1): var x = replaceTypeVarsT(cl, t.sons[i]) - assert x.kind != tyGenericInvokation + assert x.kind != tyGenericInvocation header.sons[i] = x propagateToOwner(header, x) idTablePut(cl.typeMap, body.sons[i-1], x) - + for i in countup(1, sonsLen(t) - 1): # if one of the params is not concrete, we cannot do anything # but we already raised an error! rawAddSon(result, header.sons[i]) var newbody = replaceTypeVarsT(cl, lastSon(body)) + cl.skipTypedesc = oldSkipTypedesc newbody.flags = newbody.flags + (t.flags + body.flags - tfInstClearedFlags) result.flags = result.flags + newbody.flags - tfInstClearedFlags - newbody.callConv = body.callConv + # This is actually wrong: tgeneric_closure fails with this line: + #newbody.callConv = body.callConv # This type may be a generic alias and we want to resolve it here. # One step is enough, because the recursive nature of - # handleGenericInvokation will handle the alias-to-alias-to-alias case + # handleGenericInvocation will handle the alias-to-alias-to-alias case if newbody.isGenericAlias: newbody = newbody.skipGenericAlias rawAddSon(result, newbody) checkPartialConstructedType(cl.info, newbody) @@ -303,14 +309,20 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType = if dc != nil and sfFromGeneric notin newbody.deepCopy.flags: # 'deepCopy' needs to be instantiated for # generics *when the type is constructed*: - newbody.deepCopy = cl.c.instDeepCopy(cl.c, dc, result, cl.info) + newbody.deepCopy = cl.c.instTypeBoundOp(cl.c, dc, result, cl.info, + attachedDeepCopy) + let asgn = newbody.assignment + if asgn != nil and sfFromGeneric notin asgn.flags: + # '=' needs to be instantiated for generics when the type is constructed: + newbody.assignment = cl.c.instTypeBoundOp(cl.c, asgn, result, cl.info, + attachedAsgn) proc eraseVoidParams*(t: PType) = # transform '(): void' into '()' because old parts of the compiler really - # doesn't deal with '(): void': + # don't deal with '(): void': if t.sons[0] != nil and t.sons[0].kind == tyEmpty: t.sons[0] = nil - + for i in 1 .. <t.sonsLen: # don't touch any memory unless necessary if t.sons[i].kind == tyEmpty: @@ -332,7 +344,7 @@ proc skipIntLiteralParams*(t: PType) = if skipped != p: t.sons[i] = skipped if i > 0: t.n.sons[i].sym.typ = skipped - + # when the typeof operator is used on a static input # param, the results gets infected with static as well: if t.sons[0] != nil and t.sons[0].kind == tyStatic: @@ -341,6 +353,8 @@ proc skipIntLiteralParams*(t: PType) = proc propagateFieldFlags(t: PType, n: PNode) = # This is meant for objects and tuples # The type must be fully instantiated! + if n.isNil: + return internalAssert n.kind != nkRecWhen case n.kind of nkSym: @@ -357,10 +371,10 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = if t.kind in {tyStatic, tyGenericParam, tyIter} + tyTypeClasses: let lookup = PType(idTableGet(cl.typeMap, t)) if lookup != nil: return lookup - + case t.kind - of tyGenericInvokation: - result = handleGenericInvokation(cl, t) + of tyGenericInvocation: + result = handleGenericInvocation(cl, t) of tyGenericBody: localError(cl.info, errCannotInstantiateX, typeToString(t)) @@ -369,8 +383,10 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = of tyFromExpr: if cl.allowMetaTypes: return + assert t.n.typ != t var n = prepareNode(cl, t.n) - n = cl.c.semConstExpr(cl.c, n) + if n.kind != nkEmpty: + n = cl.c.semConstExpr(cl.c, n) if n.typ.kind == tyTypeDesc: # XXX: sometimes, chained typedescs enter here. # It may be worth investigating why this is happening, @@ -389,51 +405,58 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = else: result = n.typ - of tyInt: + of tyInt, tyFloat: result = skipIntLit(t) - # XXX now there are also float literals - + of tyTypeDesc: let lookup = PType(idTableGet(cl.typeMap, t)) # lookupTypeVar(cl, t) if lookup != nil: result = lookup - if tfUnresolved in t.flags: result = result.base + if tfUnresolved in t.flags or cl.skipTypedesc: result = result.base elif t.sons[0].kind != tyNone: result = makeTypeDesc(cl.c, replaceTypeVarsT(cl, t.sons[0])) - + of tyUserTypeClass: result = t of tyGenericInst: + result = PType(idTableGet(cl.localCache, t)) + if result != nil: return result result = instCopyType(cl, t) + idTablePut(cl.localCache, t, result) for i in 1 .. <result.sonsLen: result.sons[i] = replaceTypeVarsT(cl, result.sons[i]) propagateToOwner(result, result.lastSon) - + else: if containsGenericType(t): + #if not cl.allowMetaTypes: + result = PType(idTableGet(cl.localCache, t)) + if result != nil: return result result = instCopyType(cl, t) result.size = -1 # needs to be recomputed - + #if not cl.allowMetaTypes: + idTablePut(cl.localCache, t, result) + for i in countup(0, sonsLen(result) - 1): if result.sons[i] != nil: result.sons[i] = replaceTypeVarsT(cl, result.sons[i]) propagateToOwner(result, result.sons[i]) result.n = replaceTypeVarsN(cl, result.n) - + case result.kind of tyArray: let idx = result.sons[0] internalAssert idx.kind != tyStatic - + of tyObject, tyTuple: propagateFieldFlags(result, result.n) - + of tyProc: eraseVoidParams(result) skipIntLiteralParams(result) - + else: discard proc initTypeVars*(p: PContext, pt: TIdTable, info: TLineInfo): TReplTypeVars = @@ -448,7 +471,7 @@ proc replaceTypesInBody*(p: PContext, pt: TIdTable, n: PNode): PNode = pushInfoContext(n.info) result = replaceTypeVarsN(cl, n) popInfoContext() - + proc generateTypeInstance*(p: PContext, pt: TIdTable, info: TLineInfo, t: PType): PType = var cl = initTypeVars(p, pt, info) |