Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
zah committed Mar 21, 2018
1 parent 1d4f014 commit 9606c1f
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 4 deletions.
2 changes: 1 addition & 1 deletion compiler/semexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2200,7 +2200,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
# because of the changed symbol binding, this does not mean that we
# don't have to check the symbol for semantics here again!
result = semSym(c, n, n.sym, flags)
of nkEmpty, nkNone, nkCommentStmt:
of nkEmpty, nkNone, nkCommentStmt, nkType:
discard
of nkNilLit:
if result.typ == nil: result.typ = getSysType(tyNil)
Expand Down
30 changes: 30 additions & 0 deletions compiler/seminst.nim
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,8 @@ proc sideEffectsCheck(c: PContext, s: PSym) =

proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
allowMetaTypes = false): PType =
internalAssert header.kind == tyGenericInvocation

var
typeMap: LayeredIdTable
cl: TReplTypeVars
Expand All @@ -185,7 +187,35 @@ proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
cl.info = info
cl.c = c
cl.allowMetaTypes = allowMetaTypes

# We must add all generic params in scope, because the generic body
# may include tyFromExpr nodes depending on these generic params.
# XXX: This looks quite similar to the code in matchUserTypeClass,
# perhaps the code can be extracted in a shared function.
openScope(c)
let genericTyp = header.base
for i in 0 .. (genericTyp.len - 2):
let genParam = genericTyp[i]
var param: PSym

template paramSym(kind): untyped =
newSym(kind, genParam.sym.name, genericTyp.sym, genParam.sym.info)

if genParam.kind == tyStatic:
param = paramSym skConst
param.ast = header[i+1].n
param.typ = header[i+1]
else:
param = paramSym skType
param.typ = makeTypeDesc(c, header[i+1])

# this scope was not created by the user,
# unused params shoudn't be reported.
param.flags.incl sfUsed
addDecl(c, param)

result = replaceTypeVarsT(cl, header)
closeScope(c)

proc instantiateProcType(c: PContext, pt: TIdTable,
prc: PSym, info: TLineInfo) =
Expand Down
5 changes: 4 additions & 1 deletion compiler/semtypes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1396,7 +1396,10 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
fixupTypeOf(c, prev, typExpr)
result = typExpr.typ
else:
result = semTypeExpr(c, n, prev)
if c.inGenericContext > 0 and n.kind == nkCall:
result = makeTypeFromExpr(c, n.copyTree)
else:
result = semTypeExpr(c, n, prev)
of nkWhenStmt:
var whenResult = semWhen(c, n, false)
if whenResult.kind == nkStmtList: whenResult.kind = nkStmtListType
Expand Down
4 changes: 4 additions & 0 deletions compiler/semtypinst.nim
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,10 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =

of tyFromExpr:
if cl.allowMetaTypes: return
# This assert is triggered when a tyFromExpr was created in a cyclic
# way. You should break the cycle at the point of creation by introducing
# a call such as: `n.typ = makeTypeFromExpr(c, n.copyTree)`
# Otherwise, the cycle will be fatal for the prepareNode call below
assert t.n.typ != t
var n = prepareNode(cl, t.n)
if n.kind != nkEmpty:
Expand Down
2 changes: 1 addition & 1 deletion compiler/sigmatch.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1883,7 +1883,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
return arg
elif f.kind == tyTypeDesc:
return arg
elif f.kind == tyStatic:
elif f.kind == tyStatic and arg.typ.n != nil:
return arg.typ.n
else:
return argSemantized # argOrig
Expand Down
35 changes: 34 additions & 1 deletion tests/metatype/ttypeselectors.nim
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import macros
import
macros, typetraits

template selectType(x: int): typeDesc =
when x < 10:
Expand All @@ -11,6 +12,9 @@ template simpleTypeTempl: typeDesc =

macro typeFromMacro: typedesc = string

# The tests below check that the result variable of the
# selected type matches the literal types in the code:

proc t1*(x: int): simpleTypeTempl() =
result = "test"

Expand All @@ -37,3 +41,32 @@ proc t6*(x: type(t3(0))): type(t1(0)) =
proc t7*(x: int): type($x) =
result = "test"

# This is a more compicated example involving a type
# selection through a macro:
# https://github.com/nim-lang/Nim/issues/7230

macro getBase*(bits: static[int]): untyped =
if bits >= 128:
result = newTree(nnkBracketExpr, ident("MpUintBase"), ident("uint64"))
else:
result = newTree(nnkBracketExpr, ident("MpUintBase"), ident("uint32"))

type
BaseUint* = SomeUnsignedInt or MpUintBase

MpUintBase*[T] = object
lo*, hi*: T

## This gets type mismatch
MpUint*[bits: static[int]] = getBase(bits)

var m1: MpUint[128]
var m2: MpUint[64]
var m3: getBase(32)

static:
# assert m1.type.name == "MpUintBase[uint64]"
assert m1.lo.type.name == "uint64"
assert m2.lo.type.name == "uint32"
assert m3.type.name == "MpUintBase[system.uint32]"

0 comments on commit 9606c1f

Please sign in to comment.