Skip to content

Commit

Permalink
Support default type parameters
Browse files Browse the repository at this point in the history
progress on #7516
  • Loading branch information
zah committed Jun 12, 2018
1 parent 567f353 commit 6d69bac
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 3 deletions.
19 changes: 16 additions & 3 deletions compiler/seminst.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
4 changes: 4 additions & 0 deletions compiler/semtypes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1046,6 +1046,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:
Expand Down
14 changes: 14 additions & 0 deletions tests/metatype/ttypedesc2.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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"

0 comments on commit 6d69bac

Please sign in to comment.