diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 752a2b599465..0047fd68e160 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -247,26 +247,39 @@ proc instantiateProcType(c: PContext, pt: TIdTable, if i > 1: resetIdTable(cl.symMap) resetIdTable(cl.localCache) + + # take a note of the original type. If't a free type parameter + # we'll need to keep it unbount for the `fitNode` operation below... + var typeToFit = result[i] + let needsStaticSkipping = result[i].kind == tyFromExpr result[i] = replaceTypeVarsT(cl, result[i]) if needsStaticSkipping: result[i] = result[i].skipTypes({tyStatic}) + + # ...otherwise, we use the instantiated type in `fitNode` + if typeToFit.kind != tyTypeDesc or typeToFit.base.kind != tyNone: + typeToFit = result[i] + internalAssert c.config, originalParams[i].kind == nkSym let oldParam = originalParams[i].sym let param = copySym(oldParam) param.owner = prc param.typ = result[i] + + # The default value is instantiated and fitted against the final + # concrete param type. We avoid calling `replaceTypeVarsN` on the + # call head symbol, because this leads to infinite recursion. if oldParam.ast != nil: var def = oldParam.ast.copyTree if def.kind == nkCall: for i in 1 ..< def.len: def[i] = replaceTypeVarsN(cl, def[i]) def = semExprWithType(c, def) - param.ast = fitNode(c, param.typ, def, def.info) - param.typ = param.ast.typ + param.ast = fitNode(c, typeToFit, def, def.info) + param.typ = result[i] result.n[i] = newSymNode(param) - result[i] = param.typ propagateToOwner(result, result[i]) addDecl(c, param) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 85c6e30565f1..2f16151f2e15 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1045,6 +1045,10 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, if typ == nil: typ = def.typ + if typ.kind == tyTypeDesc: + # default typedesc values are mapped to the unbound typedesc type: + typ = newTypeWithSons(c, tyTypeDesc, @[newTypeS(tyNone, c)]) + else: # if def.typ != nil and def.typ.kind != tyNone: # example code that triggers it: diff --git a/tests/metatype/ttypedesc2.nim b/tests/metatype/ttypedesc2.nim index 4b6cfe6bc768..94a7367e78fe 100644 --- a/tests/metatype/ttypedesc2.nim +++ b/tests/metatype/ttypedesc2.nim @@ -34,3 +34,17 @@ when true: type Point[T] = tuple[x, y: T] proc origin(T: typedesc): Point[T] = discard discard origin(int) + +# https://github.com/nim-lang/Nim/issues/7516 +import typetraits + +proc hasDefault1(T: type = int): auto = return T.name +doAssert hasDefault1(int) == "int" +doAssert hasDefault1(string) == "string" +doAssert hasDefault1() == "int" + +proc hasDefault2(T = string): auto = return T.name +doAssert hasDefault2(int) == "int" +doAssert hasDefault2(string) == "string" +doAssert hasDefault2() == "string" +