Skip to content

Commit badb6c0

Browse files
committed
improved support for typedesc values
* can be stored in constants and variables (including in containers like sequences) * can be passed to and returned from macros
1 parent 92b0d64 commit badb6c0

File tree

11 files changed

+90
-79
lines changed

11 files changed

+90
-79
lines changed

compiler/ast.nim

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,12 @@ type
344344
tfFromGeneric, # type is an instantiation of a generic; this is needed
345345
# because for instantiations of objects, structural
346346
# type equality has to be used
347+
tfInstantiated # XXX: used to mark generic params after instantiation.
348+
# if the concrete type happens to be an implicit generic
349+
# this can lead to invalid proc signatures in the second
350+
# pass of semProcTypeNode performed after instantiation.
351+
# this won't be needed if we don't perform this redundant
352+
# second pass (stay tuned).
347353
tfAll, # type class requires all constraints to be met (default)
348354
tfAny, # type class requires any constraint to be met
349355
tfCapturesEnv, # whether proc really captures some environment

compiler/ccgstmts.nim

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ proc genConstStmt(p: BProc, t: PNode) =
163163
if it.kind == nkCommentStmt: continue
164164
if it.kind != nkConstDef: InternalError(t.info, "genConstStmt")
165165
var c = it.sons[0].sym
166+
if c.typ.containsCompileTimeOnly: continue
166167
if sfFakeConst in c.flags:
167168
genSingleVar(p, it)
168169
elif c.typ.kind in ConstantDataTypes and lfNoDecl notin c.loc.flags and

compiler/ccgtypes.nim

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,14 @@ proc mangleName(s: PSym): PRope =
140140
proc isCompileTimeOnly(t: PType): bool =
141141
result = t.kind in {tyTypedesc, tyExpr}
142142

143+
proc containsCompileTimeOnly(t: PType): bool =
144+
if isCompileTimeOnly(t): return true
145+
if t.sons != nil:
146+
for i in 0 .. <t.sonsLen:
147+
if t.sons[i] != nil and isCompileTimeOnly(t.sons[i]):
148+
return true
149+
return false
150+
143151
var anonTypeName = toRope"TY"
144152

145153
proc typeName(typ: PType): PRope =
@@ -174,7 +182,7 @@ proc mapType(typ: PType): TCTypeKind =
174182
of tyOpenArray, tyArrayConstr, tyArray, tyVarargs: result = ctArray
175183
of tyObject, tyTuple: result = ctStruct
176184
of tyGenericBody, tyGenericInst, tyGenericParam, tyDistinct, tyOrdinal,
177-
tyConst, tyMutable, tyIter, tyTypeDesc:
185+
tyConst, tyMutable, tyIter, tyTypeDesc:
178186
result = mapType(lastSon(typ))
179187
of tyEnum:
180188
if firstOrd(typ) < 0:

compiler/evals.nim

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -865,11 +865,11 @@ proc evalTypeTrait*(n: PNode, context: PSym): PNode =
865865
# by the type traits procs' signatures, but until the
866866
# code is more mature it doesn't hurt to be extra safe
867867
internalAssert n.sons.len >= 2 and n.sons[1].kind == nkSym
868-
868+
869869
let typ = n.sons[1].sym.typ.skipTypes({tyTypeDesc})
870870
case n.sons[0].sym.name.s.normalize
871871
of "name":
872-
result = newStrNode(nkStrLit, typ.typeToString(preferExported))
872+
result = newStrNode(nkStrLit, typ.typeToString(preferName))
873873
result.typ = newType(tyString, context)
874874
result.info = n.info
875875
else:
@@ -965,7 +965,9 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
965965
of mParseExprToAst: result = evalParseExpr(c, n)
966966
of mParseStmtToAst: result = evalParseStmt(c, n)
967967
of mExpandToAst: result = evalExpandToAst(c, n)
968-
of mTypeTrait: result = evalTypeTrait(n, c.module)
968+
of mTypeTrait:
969+
n.sons[1] = evalAux(c, n.sons[1], {})
970+
result = evalTypeTrait(n, c.module)
969971
of mSlurp: result = evalSlurp(evalAux(c, n.sons[1], {}), c.module)
970972
of mStaticExec:
971973
let cmd = evalAux(c, n.sons[1], {})

compiler/procfind.nim

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ proc equalGenericParams(procA, procB: PNode): bool =
2828
return
2929
a = procA.sons[i].sym
3030
b = procB.sons[i].sym
31-
if (a.name.id != b.name.id) or not sameTypeOrNil(a.typ, b.typ): return
31+
if (a.name.id != b.name.id) or
32+
not sameTypeOrNil(a.typ, b.typ, {TypeDescExactMatch}): return
3233
if (a.ast != nil) and (b.ast != nil):
3334
if not ExprStructuralEquivalent(a.ast, b.ast): return
3435
result = true

compiler/semexprs.nim

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ proc restoreOldStyleType(n: PNode) =
1919
#
2020
# This is strictly for backward compatibility until
2121
# the transition to types as first-class values is complete.
22-
n.typ = n.typ.skipTypes({tyTypeDesc})
22+
if n.typ.kind == tyTypeDesc and n.typ.sonsLen == 1:
23+
n.typ = n.typ.sons[0]
2324

2425
proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode =
2526
markUsed(n, s)
@@ -376,6 +377,8 @@ proc semArrayConstr(c: PContext, n: PNode): PNode =
376377

377378
addSon(result, semExprWithType(c, x))
378379
var typ = skipTypes(result.sons[0].typ, {tyGenericInst, tyVar, tyOrdinal})
380+
# turn any concrete typedesc into the absract typedesc type
381+
if typ.kind == tyTypeDesc: typ.sons = nil
379382
for i in countup(1, sonsLen(n) - 1):
380383
x = n.sons[i]
381384
if x.kind == nkExprColonExpr and sonsLen(x) == 2:

compiler/seminst.nim

Lines changed: 5 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
3333
#t = instGenericContainer(c, a, t)
3434
t = generateTypeInstance(c, pt, a, t)
3535
#t = ReplaceTypeVarsT(cl, t)
36+
t.flags.incl tfInstantiated
3637
s.typ = t
3738
addDecl(c, s)
3839
entry.concreteTypes[i] = t
@@ -41,7 +42,8 @@ proc sameInstantiation(a, b: TInstantiatedSymbol): bool =
4142
if a.genericSym.id == b.genericSym.id and
4243
a.concreteTypes.len == b.concreteTypes.len:
4344
for i in 0 .. < a.concreteTypes.len:
44-
if not sameType(a.concreteTypes[i], b.concreteTypes[i]): return
45+
if not compareTypes(a.concreteTypes[i], b.concreteTypes[i],
46+
flags = {TypeDescExactMatch}): return
4547
result = true
4648

4749
proc GenericCacheGet(c: PContext, entry: var TInstantiatedSymbol): PSym =
@@ -122,33 +124,6 @@ proc sideEffectsCheck(c: PContext, s: PSym) =
122124
s.ast.sons[genericParamsPos].kind == nkEmpty:
123125
c.threadEntries.add(s)
124126

125-
proc applyConcreteTypesToSig(genericProc: PSym, concTypes: seq[PType]): PType =
126-
# XXX: This is intended to replace the use of semParamList in generateInstance.
127-
# The results of semParamList's analysis are already encoded in the original
128-
# proc type and any concrete types may be aplied directly over it.
129-
# Besides being more efficient, it will remove the awkward case of
130-
# genericParams == nil in semParamList.
131-
# Currenly, it fails in some cases such as:
132-
# proc inc2*[T](x: var ordinal[T], y = 1) {.magic: "Inc", noSideEffect.}
133-
let sig = genericProc.typ
134-
result = copyType(sig, getCurrOwner(), false)
135-
result.n = sig.n.shallowCopy
136-
137-
for i in countup(0, sig.len - 1):
138-
let tOrig = sig.sons[i]
139-
if tOrig == nil: continue
140-
let oGenParams = genericProc.ast.sons[genericParamsPos]
141-
if skipTypes(tOrig, skipPtrs).kind in {tyGenericParam}:
142-
var tConcrete = concTypes[tOrig.sym.position]
143-
if i > 0:
144-
let param = sig.n.sons[i].sym.copySym
145-
param.typ = tConcrete
146-
result.n.sons[i] = newSymNode(param)
147-
result.sons[i] = tConcrete
148-
else:
149-
result.sons[i] = tOrig
150-
if i > 0: result.n.sons[i] = sig.n.sons[i]
151-
152127
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
153128
info: TLineInfo): PSym =
154129
# no need to instantiate generic templates/macros:
@@ -182,12 +157,8 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
182157
n.sons[genericParamsPos] = ast.emptyNode
183158
# semantic checking for the parameters:
184159
if n.sons[paramsPos].kind != nkEmpty:
185-
if false and nimdbg:
186-
result.typ = applyConcreteTypesToSig(fn, entry.concreteTypes)
187-
addParams(c, result.typ.n, fn.kind)
188-
else:
189-
removeDefaultParamValues(n.sons[ParamsPos])
190-
semParamList(c, n.sons[ParamsPos], nil, result)
160+
removeDefaultParamValues(n.sons[ParamsPos])
161+
semParamList(c, n.sons[ParamsPos], nil, result)
191162
else:
192163
result.typ = newTypeS(tyProc, c)
193164
rawAddSon(result.typ, nil)

compiler/semmagic.nim

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,14 @@ proc semInstantiationInfo(c: PContext, n: PNode): PNode =
3434
proc semTypeTraits(c: PContext, n: PNode): PNode =
3535
checkMinSonsLen(n, 2)
3636
internalAssert n.sons[1].kind == nkSym
37-
if n.sons[1].sym.kind == skType:
37+
let typArg = n.sons[1].sym
38+
if typArg.kind == skType or
39+
(typArg.kind == skParam and typArg.typ.sonsLen > 0):
40+
# This is either a type known to sem or a typedesc
41+
# param to a regular proc (again, known at instantiation)
3842
result = evalTypeTrait(n, GetCurrOwner())
3943
else:
40-
# pass unmodified to evals
44+
# a typedesc variable, pass unmodified to evals
4145
result = n
4246

4347
proc semOrd(c: PContext, n: PNode): PNode =

compiler/semtypes.nim

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
552552
incl(result.flags, tfFinal)
553553

554554
proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
555-
if kind == skMacro:
555+
if kind == skMacro and param.typ.kind != tyTypeDesc:
556556
# within a macro, every param has the type PNimrodNode!
557557
# and param.typ.kind in {tyTypeDesc, tyExpr, tyStmt}:
558558
let nn = getSysSym"PNimrodNode"
@@ -579,7 +579,8 @@ proc paramTypeClass(c: PContext, paramType: PType, procKind: TSymKind):
579579
result.typ = newTypeS(tyExpr, c)
580580
result.typ.sons = paramType.sons
581581
of tyTypeDesc:
582-
if procKind notin {skTemplate, skMacro}:
582+
if procKind notin {skTemplate, skMacro} and
583+
tfInstantiated notin paramType.flags:
583584
result.typ = newTypeS(tyTypeDesc, c)
584585
result.typ.sons = paramType.sons
585586
of tyDistinct:
@@ -777,19 +778,12 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
777778
else:
778779
result = instGenericContainer(c, n, result)
779780

780-
proc semTypeFromMacro(c: PContext, n: PNode): PType =
781-
# Expands a macro or template until a type is returned
782-
# results in an error type if the macro expands to something different
783-
var sym = expectMacroOrTemplateCall(c, n)
784-
markUsed(n, sym)
785-
case sym.kind
786-
of skMacro:
787-
result = semTypeNode(c, semMacroExpr(c, n, n, sym), nil)
788-
of skTemplate:
789-
result = semTypeNode(c, semTemplateExpr(c, n, sym), nil)
781+
proc semTypeExpr(c: PContext, n: PNode): PType =
782+
var n = semExprWithType(c, n)
783+
if n.kind == nkSym and n.sym.kind == skType:
784+
result = n.sym.typ
790785
else:
791-
LocalError(n.info, errXisNoMacroOrTemplate, n.renderTree)
792-
result = errorType(c)
786+
LocalError(n.info, errTypeExpected, n.renderTree)
793787

794788
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
795789
result = nil
@@ -823,7 +817,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
823817
result.addSonSkipIntLit(t2)
824818
result.flags.incl(if op.id == ord(wAnd): tfAll else: tfAny)
825819
else:
826-
result = semTypeFromMacro(c, n)
820+
result = semTypeExpr(c, n)
827821
of nkCurlyExpr:
828822
result = semTypeNode(c, n.sons[0], nil)
829823
if result != nil:

compiler/sigmatch.nim

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ proc matchTypeClass(c: var TCandidate, typeClass, t: PType): TTypeRelation =
271271
of tyTypeClass:
272272
match = matchTypeClass(c, req, t) == isGeneric
273273
else: nil
274-
elif t.kind in {tyTypeDesc, tyObject}:
274+
elif t.kind in {tyObject}:
275275
match = sameType(t, req)
276276

277277
if tfAny in typeClass.flags:
@@ -659,7 +659,8 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
659659
of isGeneric:
660660
inc(m.genericMatches)
661661
if m.calleeSym != nil and m.calleeSym.kind in {skMacro, skTemplate}:
662-
result = argOrig
662+
if f.kind == tyTypeDesc: result = arg
663+
else: result = argOrig
663664
else:
664665
result = copyTree(arg)
665666
result.typ = getInstantiatedType(c, arg, m, f)

0 commit comments

Comments
 (0)