diff options
Diffstat (limited to 'compiler/semtypinst.nim')
-rwxr-xr-x | compiler/semtypinst.nim | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim new file mode 100755 index 000000000..b6126e285 --- /dev/null +++ b/compiler/semtypinst.nim @@ -0,0 +1,151 @@ +# +# +# The Nimrod Compiler +# (c) Copyright 2011 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +# This module does the instantiation of generic procs and types. + +import ast, astalgo, msgs, types, semdata + +proc checkConstructedType*(info: TLineInfo, t: PType) = + if tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject: + LocalError(info, errInvalidPragmaX, "acyclic") + elif computeSize(t) < 0: + LocalError(info, errIllegalRecursionInTypeX, typeToString(t)) + elif t.kind == tyVar and t.sons[0].kind == tyVar: + LocalError(info, errVarVarTypeNotAllowed) + when false: + if t.kind == tyObject and t.sons[0] != nil: + if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags: + localError(info, errInheritanceOnlyWithNonFinalObjects) + +proc containsGenericTypeIter(t: PType, closure: PObject): bool = + result = t.kind in GenericTypes + +proc containsGenericType*(t: PType): bool = + result = iterOverType(t, containsGenericTypeIter, nil) + +proc searchInstTypes(tab: TIdTable, key: PType): PType = + # returns nil if we need to declare this type + result = PType(IdTableGet(tab, key)) + if (result == nil) and (tab.counter > 0): + # we have to do a slow linear search because types may need + # to be compared by their structure: + for h in countup(0, high(tab.data)): + var t = PType(tab.data[h].key) + if t != nil: + if key.containerId == t.containerID: + var match = true + for j in countup(0, sonsLen(t) - 1): + # XXX sameType is not really correct for nested generics? + if not sameType(t.sons[j], key.sons[j]): + match = false + break + if match: + return PType(tab.data[h].val) + +type + TReplTypeVars* {.final.} = object + c*: PContext + typeMap*: TIdTable # map PType to PType + symMap*: TIdTable # map PSym to PSym + info*: TLineInfo + +proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType +proc ReplaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym +proc ReplaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode = + if n != nil: + result = copyNode(n) + result.typ = ReplaceTypeVarsT(cl, n.typ) + case n.kind + of nkNone..pred(nkSym), succ(nkSym)..nkNilLit: + nil + of nkSym: + result.sym = ReplaceTypeVarsS(cl, n.sym) + else: + var length = sonsLen(n) + if length > 0: + 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 = + if s == nil: return nil + result = PSym(idTableGet(cl.symMap, s)) + if result == nil: + result = copySym(s, false) + incl(result.flags, sfFromGeneric) + idTablePut(cl.symMap, s, result) + result.typ = ReplaceTypeVarsT(cl, s.typ) + result.owner = s.owner + result.ast = ReplaceTypeVarsN(cl, s.ast) + +proc lookupTypeVar(cl: TReplTypeVars, t: PType): PType = + result = PType(idTableGet(cl.typeMap, t)) + if result == nil: + GlobalError(t.sym.info, errCannotInstantiateX, typeToString(t)) + elif result.kind == tyGenericParam: + InternalError(cl.info, "substitution with generic parameter") + +proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType = + var body, newbody, x, header: PType + result = t + if t == nil: return + case t.kind + of tyGenericParam: + result = lookupTypeVar(cl, t) + of tyGenericInvokation: + body = t.sons[0] + if body.kind != tyGenericBody: InternalError(cl.info, "no generic body") + header = nil + for i in countup(1, sonsLen(t) - 1): + if t.sons[i].kind == tyGenericParam: + x = lookupTypeVar(cl, t.sons[i]) + 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) + newbody = ReplaceTypeVarsT(cl, lastSon(body)) + newbody.n = ReplaceTypeVarsN(cl, lastSon(body).n) + addSon(result, newbody) + #writeln(output, ropeToStr(Typetoyaml(newbody))); + checkConstructedType(cl.info, newbody) + of tyGenericBody: + InternalError(cl.info, "ReplaceTypeVarsT: tyGenericBody") + result = ReplaceTypeVarsT(cl, lastSon(t)) + else: + if containsGenericType(t): + result = copyType(t, t.owner, false) + for i in countup(0, sonsLen(result) - 1): + result.sons[i] = ReplaceTypeVarsT(cl, result.sons[i]) + 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) + +proc generateTypeInstance*(p: PContext, pt: TIdTable, arg: PNode, + t: PType): PType = + var cl: TReplTypeVars + InitIdTable(cl.symMap) + copyIdTable(cl.typeMap, pt) + cl.info = arg.info + cl.c = p + pushInfoContext(arg.info) + result = ReplaceTypeVarsT(cl, t) + popInfoContext() + |