Skip to content

Commit 121b9e2

Browse files
zahAraq
authored andcommitted
Static[T] fixes (#7333)
* fix the usage of unresolved static[T] parameters in proc signatures * fix tsametype and tmacrogenerics * Allow creating composite type classes with concepts and using them in type signatures * Allow integers to be used in ident concatenations * Support using imported C++ generic types in proc signatures * fixes #7230 * closes #7379 * re-enable some metatype tests
1 parent 2e7a0e1 commit 121b9e2

18 files changed

+265
-26
lines changed

compiler/ast.nim

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -981,6 +981,7 @@ const
981981

982982
nkPragmaCallKinds* = {nkExprColonExpr, nkCall, nkCallStrLit}
983983
nkLiterals* = {nkCharLit..nkTripleStrLit}
984+
nkFloatLiterals* = {nkFloatLit..nkFloat128Lit}
984985
nkLambdaKinds* = {nkLambda, nkDo}
985986
declarativeDefs* = {nkProcDef, nkFuncDef, nkMethodDef, nkIteratorDef, nkConverterDef}
986987
procDefs* = nkLambdaKinds + declarativeDefs
@@ -1476,7 +1477,7 @@ proc copyNode*(src: PNode): PNode =
14761477
echo "COMES FROM ", src.id
14771478
case src.kind
14781479
of nkCharLit..nkUInt64Lit: result.intVal = src.intVal
1479-
of nkFloatLit..nkFloat128Lit: result.floatVal = src.floatVal
1480+
of nkFloatLiterals: result.floatVal = src.floatVal
14801481
of nkSym: result.sym = src.sym
14811482
of nkIdent: result.ident = src.ident
14821483
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
@@ -1495,7 +1496,7 @@ proc shallowCopy*(src: PNode): PNode =
14951496
echo "COMES FROM ", src.id
14961497
case src.kind
14971498
of nkCharLit..nkUInt64Lit: result.intVal = src.intVal
1498-
of nkFloatLit..nkFloat128Lit: result.floatVal = src.floatVal
1499+
of nkFloatLiterals: result.floatVal = src.floatVal
14991500
of nkSym: result.sym = src.sym
15001501
of nkIdent: result.ident = src.ident
15011502
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
@@ -1515,7 +1516,7 @@ proc copyTree*(src: PNode): PNode =
15151516
echo "COMES FROM ", src.id
15161517
case src.kind
15171518
of nkCharLit..nkUInt64Lit: result.intVal = src.intVal
1518-
of nkFloatLit..nkFloat128Lit: result.floatVal = src.floatVal
1519+
of nkFloatLiterals: result.floatVal = src.floatVal
15191520
of nkSym: result.sym = src.sym
15201521
of nkIdent: result.ident = src.ident
15211522
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
@@ -1564,7 +1565,7 @@ proc getInt*(a: PNode): BiggestInt =
15641565

15651566
proc getFloat*(a: PNode): BiggestFloat =
15661567
case a.kind
1567-
of nkFloatLit..nkFloat128Lit: result = a.floatVal
1568+
of nkFloatLiterals: result = a.floatVal
15681569
else:
15691570
internalError(a.info, "getFloat")
15701571
result = 0.0

compiler/ccgtypes.nim

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -842,6 +842,13 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
842842
# always call for sideeffects:
843843
assert t.kind != tyTuple
844844
discard getRecordDesc(m, t, result, check)
845+
# The resulting type will include commas and these won't play well
846+
# with the C macros for defining procs such as N_NIMCALL. We must
847+
# create a typedef for the type and use it in the proc signature:
848+
let typedefName = ~"TY" & $sig
849+
addf(m.s[cfsTypes], "typedef $1 $2;$n", [result, typedefName])
850+
m.typeCache[sig] = typedefName
851+
result = typedefName
845852
else:
846853
when false:
847854
if t.sym != nil and t.sym.name.s == "KeyValuePair":

compiler/lookups.nim

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ proc considerQuotedIdent*(n: PNode, origin: PNode = nil): PIdent =
4444
case x.kind
4545
of nkIdent: id.add(x.ident.s)
4646
of nkSym: id.add(x.sym.name.s)
47+
of nkLiterals - nkFloatLiterals: id.add(x.renderTree)
4748
else: handleError(n, origin)
4849
result = getIdent(id)
4950
of nkOpenSymChoice, nkClosedSymChoice:
@@ -456,4 +457,4 @@ proc pickSym*(c: PContext, n: PNode; kinds: set[TSymKind];
456457
a = nextOverloadIter(o, c, n)
457458

458459
proc isInfixAs*(n: PNode): bool =
459-
return n.kind == nkInfix and considerQuotedIdent(n[0]).s == "as"
460+
return n.kind == nkInfix and considerQuotedIdent(n[0]).s == "as"

compiler/semexprs.nim

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -884,6 +884,9 @@ const
884884

885885
proc readTypeParameter(c: PContext, typ: PType,
886886
paramName: PIdent, info: TLineInfo): PNode =
887+
# Note: This function will return emptyNode when attempting to read
888+
# a static type parameter that is not yet resolved (e.g. this may
889+
# happen in proc signatures such as `proc(x: T): array[T.sizeParam, U]`
887890
if typ.kind in {tyUserTypeClass, tyUserTypeClassInst}:
888891
for statement in typ.n:
889892
case statement.kind
@@ -914,7 +917,10 @@ proc readTypeParameter(c: PContext, typ: PType,
914917
if tParam.sym.name.id == paramName.id:
915918
let rawTyp = ty.sons[s + 1]
916919
if rawTyp.kind == tyStatic:
917-
return rawTyp.n
920+
if rawTyp.n != nil:
921+
return rawTyp.n
922+
else:
923+
return emptyNode
918924
else:
919925
let foundTyp = makeTypeDesc(c, rawTyp)
920926
return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info)
@@ -1079,21 +1085,43 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
10791085
template tryReadingGenericParam(t: PType) =
10801086
case t.kind
10811087
of tyTypeParamsHolders:
1082-
return readTypeParameter(c, t, i, n.info)
1088+
result = readTypeParameter(c, t, i, n.info)
1089+
if result == emptyNode:
1090+
result = n
1091+
n.typ = makeTypeFromExpr(c, n.copyTree)
1092+
return
10831093
of tyUserTypeClasses:
10841094
if t.isResolvedUserTypeClass:
10851095
return readTypeParameter(c, t, i, n.info)
10861096
else:
10871097
n.typ = makeTypeFromExpr(c, copyTree(n))
10881098
return n
1089-
of tyGenericParam:
1099+
of tyGenericParam, tyAnything:
10901100
n.typ = makeTypeFromExpr(c, copyTree(n))
10911101
return n
10921102
else:
10931103
discard
10941104

1095-
if isTypeExpr(n.sons[0]) or (ty.kind == tyTypeDesc and ty.base.kind != tyNone):
1096-
if ty.kind == tyTypeDesc: ty = ty.base
1105+
var argIsType = false
1106+
1107+
if ty.kind == tyTypeDesc:
1108+
if ty.base.kind == tyNone:
1109+
# This is a still unresolved typedesc parameter.
1110+
# If this is a regular proc, then all bets are off and we must return
1111+
# tyFromExpr, but when this happen in a macro this is not a built-in
1112+
# field access and we leave the compiler to compile a normal call:
1113+
if getCurrOwner(c).kind != skMacro:
1114+
n.typ = makeTypeFromExpr(c, n.copyTree)
1115+
return n
1116+
else:
1117+
return nil
1118+
else:
1119+
ty = ty.base
1120+
argIsType = true
1121+
else:
1122+
argIsType = isTypeExpr(n.sons[0])
1123+
1124+
if argIsType:
10971125
ty = ty.skipTypes(tyDotOpTransparent)
10981126
case ty.kind
10991127
of tyEnum:
@@ -2186,7 +2214,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
21862214
# because of the changed symbol binding, this does not mean that we
21872215
# don't have to check the symbol for semantics here again!
21882216
result = semSym(c, n, n.sym, flags)
2189-
of nkEmpty, nkNone, nkCommentStmt:
2217+
of nkEmpty, nkNone, nkCommentStmt, nkType:
21902218
discard
21912219
of nkNilLit:
21922220
if result.typ == nil: result.typ = getSysType(tyNil)

compiler/seminst.nim

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,8 @@ proc sideEffectsCheck(c: PContext, s: PSym) =
174174

175175
proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
176176
allowMetaTypes = false): PType =
177+
internalAssert header.kind == tyGenericInvocation
178+
177179
var
178180
typeMap: LayeredIdTable
179181
cl: TReplTypeVars
@@ -185,7 +187,35 @@ proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
185187
cl.info = info
186188
cl.c = c
187189
cl.allowMetaTypes = allowMetaTypes
190+
191+
# We must add all generic params in scope, because the generic body
192+
# may include tyFromExpr nodes depending on these generic params.
193+
# XXX: This looks quite similar to the code in matchUserTypeClass,
194+
# perhaps the code can be extracted in a shared function.
195+
openScope(c)
196+
let genericTyp = header.base
197+
for i in 0 .. (genericTyp.len - 2):
198+
let genParam = genericTyp[i]
199+
var param: PSym
200+
201+
template paramSym(kind): untyped =
202+
newSym(kind, genParam.sym.name, genericTyp.sym, genParam.sym.info)
203+
204+
if genParam.kind == tyStatic:
205+
param = paramSym skConst
206+
param.ast = header[i+1].n
207+
param.typ = header[i+1]
208+
else:
209+
param = paramSym skType
210+
param.typ = makeTypeDesc(c, header[i+1])
211+
212+
# this scope was not created by the user,
213+
# unused params shoudn't be reported.
214+
param.flags.incl sfUsed
215+
addDecl(c, param)
216+
188217
result = replaceTypeVarsT(cl, header)
218+
closeScope(c)
189219

190220
proc instantiateProcType(c: PContext, pt: TIdTable,
191221
prc: PSym, info: TLineInfo) =

compiler/semtypes.nim

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1397,7 +1397,10 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
13971397
fixupTypeOf(c, prev, typExpr)
13981398
result = typExpr.typ
13991399
else:
1400-
result = semTypeExpr(c, n, prev)
1400+
if c.inGenericContext > 0 and n.kind == nkCall:
1401+
result = makeTypeFromExpr(c, n.copyTree)
1402+
else:
1403+
result = semTypeExpr(c, n, prev)
14011404
of nkWhenStmt:
14021405
var whenResult = semWhen(c, n, false)
14031406
if whenResult.kind == nkStmtList: whenResult.kind = nkStmtListType

compiler/semtypinst.nim

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,10 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
460460

461461
of tyFromExpr:
462462
if cl.allowMetaTypes: return
463+
# This assert is triggered when a tyFromExpr was created in a cyclic
464+
# way. You should break the cycle at the point of creation by introducing
465+
# a call such as: `n.typ = makeTypeFromExpr(c, n.copyTree)`
466+
# Otherwise, the cycle will be fatal for the prepareNode call below
463467
assert t.n.typ != t
464468
var n = prepareNode(cl, t.n)
465469
if n.kind != nkEmpty:

compiler/sigmatch.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1884,7 +1884,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
18841884
return arg
18851885
elif f.kind == tyTypeDesc:
18861886
return arg
1887-
elif f.kind == tyStatic:
1887+
elif f.kind == tyStatic and arg.typ.n != nil:
18881888
return arg.typ.n
18891889
else:
18901890
return argSemantized # argOrig

compiler/types.nim

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1136,6 +1136,8 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
11361136
of tyTypeClasses:
11371137
if tfGenericTypeParam in t.flags or taConcept in flags: #or taField notin flags:
11381138
discard
1139+
elif t.isResolvedUserTypeClass:
1140+
result = typeAllowedAux(marker, t.lastSon, kind, flags)
11391141
elif kind notin {skParam, skResult}:
11401142
result = t
11411143
of tyGenericBody, tyGenericParam, tyGenericInvocation,

tests/concepts/tseqofconcept.nim

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
discard """
2+
output: "1\n2\n3"
3+
"""
4+
5+
type
6+
MyConcept = concept x
7+
someProc(x)
8+
9+
SomeSeq = seq[MyConcept]
10+
11+
proc someProc(x:int) = echo x
12+
13+
proc work (s: SomeSeq) =
14+
for item in s:
15+
someProc item
16+
17+
var s = @[1, 2, 3]
18+
work s
19+

0 commit comments

Comments
 (0)