diff --git a/compiler/astdef.nim b/compiler/astdef.nim index 242cdf3ef6ab..6e00b9b8e869 100644 --- a/compiler/astdef.nim +++ b/compiler/astdef.nim @@ -329,7 +329,7 @@ type nfLazyType # node has a lazy type TNodeFlags* = set[TNodeFlag] - TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 47) + TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 48) tfVarargs, # procedure has C styled varargs # tyArray type represeting a varargs list tfNoSideEffect, # procedure type does not allow side effects diff --git a/compiler/seminst.nim b/compiler/seminst.nim index a34467636a3b..35bcc5a18616 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -212,6 +212,7 @@ proc instGenericContainer(c: PContext, info: TLineInfo, header: PType, addDecl(c, param) result = replaceTypeVarsT(cl, header) + assert cl.nodeUpdates.len == 0 closeScope(c) proc referencesAnotherParam(n: PNode, p: PSym): bool = @@ -260,6 +261,9 @@ proc instantiateProcType(c: PContext, pt: LayeredIdTable, if resulti.kind == tyFromExpr: resulti.incl tfNonConstExpr var paramType = replaceTypeVarsT(cl, resulti) + assert cl.nodeUpdates.len == 0 + postInstantiation(c, paramType) + if needsStaticSkipping: paramType = paramType.skipTypes({tyStatic}) if needsTypeDescSkipping: @@ -318,6 +322,8 @@ proc instantiateProcType(c: PContext, pt: LayeredIdTable, resetIdTable(cl.localCache) cl.isReturnType = true result.setReturnType replaceTypeVarsT(cl, result.returnType) + assert cl.nodeUpdates.len == 0 + postInstantiation(c, result.returnType) cl.isReturnType = false result.n[0] = originalParams[0].copyTree if result[0] != nil: diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 5f846c80ac59..2252260bf13b 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -9,7 +9,7 @@ # This module does the instantiation of generic types. -import std / tables +import std / [intsets, tables] import ast, astalgo, msgs, types, magicsys, semdata, renderer, options, lineinfos, modulegraphs, layeredtable @@ -79,6 +79,21 @@ type isReturnType*: bool owner*: PSym # where this instantiation comes from recursionLimit: int + nodeUpdates*: seq[(PNode, PType)] # nodes need to be updated later. + # In following code, when instantiating `Bar[int]`, + # it is referenced in `when` statement before it is instantiated. + # ```nim + # type + # Foo[T] = object + # when T is ref: # T is `Bar[int]` + # x: int + # + # Bar[T] = ref object + # x: Foo[Bar[T]] + # + # var x: Bar[int] + # ``` + # So reevaluate the statement after it is instantiated. proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType, isInstValue = false): PType proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym, t: PType): PSym @@ -99,6 +114,29 @@ proc replaceTypeVarsT*(cl: var TReplTypeVars, t: PType, isInstValue = false): PT result = replaceTypeVarsTAux(cl, t, isInstValue) checkMetaInvariants(cl, result) +proc findNotYetInstantiated(t: PType): PType = + result = nil + + if t != nil: + if t.kind == tyGenericInst and t.last.kind == tyForward: + return t + + for child in t.kids: + let r = findNotYetInstantiated(child) + if r != nil: + return r + +proc findNotYetInstantiated(n: PNode): PType = + result = nil + let r = findNotYetInstantiated(n.typ) + if r != nil: + return r + + for child in n: + let r = findNotYetInstantiated(child) + if r != nil: + return r + proc prepareNode*(cl: var TReplTypeVars, n: PNode): PNode = ## instantiates a given generic expression, not a type node if n.kind == nkSym and n.sym.kind == skType and @@ -300,6 +338,7 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0; expectedType: PT result = newNodeI(nkRecList, n.info) of nkRecWhen: var branch: PNode = nil # the branch to take + var unableToEval = false for i in 0..