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
This commit is contained in:
parent
2e7a0e1cdd
commit
121b9e26fb
18 changed files with 265 additions and 26 deletions
|
|
@ -981,6 +981,7 @@ const
|
|||
|
||||
nkPragmaCallKinds* = {nkExprColonExpr, nkCall, nkCallStrLit}
|
||||
nkLiterals* = {nkCharLit..nkTripleStrLit}
|
||||
nkFloatLiterals* = {nkFloatLit..nkFloat128Lit}
|
||||
nkLambdaKinds* = {nkLambda, nkDo}
|
||||
declarativeDefs* = {nkProcDef, nkFuncDef, nkMethodDef, nkIteratorDef, nkConverterDef}
|
||||
procDefs* = nkLambdaKinds + declarativeDefs
|
||||
|
|
@ -1476,7 +1477,7 @@ proc copyNode*(src: PNode): PNode =
|
|||
echo "COMES FROM ", src.id
|
||||
case src.kind
|
||||
of nkCharLit..nkUInt64Lit: result.intVal = src.intVal
|
||||
of nkFloatLit..nkFloat128Lit: result.floatVal = src.floatVal
|
||||
of nkFloatLiterals: result.floatVal = src.floatVal
|
||||
of nkSym: result.sym = src.sym
|
||||
of nkIdent: result.ident = src.ident
|
||||
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
|
||||
|
|
@ -1495,7 +1496,7 @@ proc shallowCopy*(src: PNode): PNode =
|
|||
echo "COMES FROM ", src.id
|
||||
case src.kind
|
||||
of nkCharLit..nkUInt64Lit: result.intVal = src.intVal
|
||||
of nkFloatLit..nkFloat128Lit: result.floatVal = src.floatVal
|
||||
of nkFloatLiterals: result.floatVal = src.floatVal
|
||||
of nkSym: result.sym = src.sym
|
||||
of nkIdent: result.ident = src.ident
|
||||
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
|
||||
|
|
@ -1515,7 +1516,7 @@ proc copyTree*(src: PNode): PNode =
|
|||
echo "COMES FROM ", src.id
|
||||
case src.kind
|
||||
of nkCharLit..nkUInt64Lit: result.intVal = src.intVal
|
||||
of nkFloatLit..nkFloat128Lit: result.floatVal = src.floatVal
|
||||
of nkFloatLiterals: result.floatVal = src.floatVal
|
||||
of nkSym: result.sym = src.sym
|
||||
of nkIdent: result.ident = src.ident
|
||||
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
|
||||
|
|
@ -1564,7 +1565,7 @@ proc getInt*(a: PNode): BiggestInt =
|
|||
|
||||
proc getFloat*(a: PNode): BiggestFloat =
|
||||
case a.kind
|
||||
of nkFloatLit..nkFloat128Lit: result = a.floatVal
|
||||
of nkFloatLiterals: result = a.floatVal
|
||||
else:
|
||||
internalError(a.info, "getFloat")
|
||||
result = 0.0
|
||||
|
|
|
|||
|
|
@ -842,6 +842,13 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
|
|||
# always call for sideeffects:
|
||||
assert t.kind != tyTuple
|
||||
discard getRecordDesc(m, t, result, check)
|
||||
# The resulting type will include commas and these won't play well
|
||||
# with the C macros for defining procs such as N_NIMCALL. We must
|
||||
# create a typedef for the type and use it in the proc signature:
|
||||
let typedefName = ~"TY" & $sig
|
||||
addf(m.s[cfsTypes], "typedef $1 $2;$n", [result, typedefName])
|
||||
m.typeCache[sig] = typedefName
|
||||
result = typedefName
|
||||
else:
|
||||
when false:
|
||||
if t.sym != nil and t.sym.name.s == "KeyValuePair":
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ proc considerQuotedIdent*(n: PNode, origin: PNode = nil): PIdent =
|
|||
case x.kind
|
||||
of nkIdent: id.add(x.ident.s)
|
||||
of nkSym: id.add(x.sym.name.s)
|
||||
of nkLiterals - nkFloatLiterals: id.add(x.renderTree)
|
||||
else: handleError(n, origin)
|
||||
result = getIdent(id)
|
||||
of nkOpenSymChoice, nkClosedSymChoice:
|
||||
|
|
@ -456,4 +457,4 @@ proc pickSym*(c: PContext, n: PNode; kinds: set[TSymKind];
|
|||
a = nextOverloadIter(o, c, n)
|
||||
|
||||
proc isInfixAs*(n: PNode): bool =
|
||||
return n.kind == nkInfix and considerQuotedIdent(n[0]).s == "as"
|
||||
return n.kind == nkInfix and considerQuotedIdent(n[0]).s == "as"
|
||||
|
|
|
|||
|
|
@ -884,6 +884,9 @@ const
|
|||
|
||||
proc readTypeParameter(c: PContext, typ: PType,
|
||||
paramName: PIdent, info: TLineInfo): PNode =
|
||||
# Note: This function will return emptyNode when attempting to read
|
||||
# a static type parameter that is not yet resolved (e.g. this may
|
||||
# happen in proc signatures such as `proc(x: T): array[T.sizeParam, U]`
|
||||
if typ.kind in {tyUserTypeClass, tyUserTypeClassInst}:
|
||||
for statement in typ.n:
|
||||
case statement.kind
|
||||
|
|
@ -914,7 +917,10 @@ proc readTypeParameter(c: PContext, typ: PType,
|
|||
if tParam.sym.name.id == paramName.id:
|
||||
let rawTyp = ty.sons[s + 1]
|
||||
if rawTyp.kind == tyStatic:
|
||||
return rawTyp.n
|
||||
if rawTyp.n != nil:
|
||||
return rawTyp.n
|
||||
else:
|
||||
return emptyNode
|
||||
else:
|
||||
let foundTyp = makeTypeDesc(c, rawTyp)
|
||||
return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info)
|
||||
|
|
@ -1079,21 +1085,43 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
template tryReadingGenericParam(t: PType) =
|
||||
case t.kind
|
||||
of tyTypeParamsHolders:
|
||||
return readTypeParameter(c, t, i, n.info)
|
||||
result = readTypeParameter(c, t, i, n.info)
|
||||
if result == emptyNode:
|
||||
result = n
|
||||
n.typ = makeTypeFromExpr(c, n.copyTree)
|
||||
return
|
||||
of tyUserTypeClasses:
|
||||
if t.isResolvedUserTypeClass:
|
||||
return readTypeParameter(c, t, i, n.info)
|
||||
else:
|
||||
n.typ = makeTypeFromExpr(c, copyTree(n))
|
||||
return n
|
||||
of tyGenericParam:
|
||||
of tyGenericParam, tyAnything:
|
||||
n.typ = makeTypeFromExpr(c, copyTree(n))
|
||||
return n
|
||||
else:
|
||||
discard
|
||||
|
||||
if isTypeExpr(n.sons[0]) or (ty.kind == tyTypeDesc and ty.base.kind != tyNone):
|
||||
if ty.kind == tyTypeDesc: ty = ty.base
|
||||
var argIsType = false
|
||||
|
||||
if ty.kind == tyTypeDesc:
|
||||
if ty.base.kind == tyNone:
|
||||
# This is a still unresolved typedesc parameter.
|
||||
# If this is a regular proc, then all bets are off and we must return
|
||||
# tyFromExpr, but when this happen in a macro this is not a built-in
|
||||
# field access and we leave the compiler to compile a normal call:
|
||||
if getCurrOwner(c).kind != skMacro:
|
||||
n.typ = makeTypeFromExpr(c, n.copyTree)
|
||||
return n
|
||||
else:
|
||||
return nil
|
||||
else:
|
||||
ty = ty.base
|
||||
argIsType = true
|
||||
else:
|
||||
argIsType = isTypeExpr(n.sons[0])
|
||||
|
||||
if argIsType:
|
||||
ty = ty.skipTypes(tyDotOpTransparent)
|
||||
case ty.kind
|
||||
of tyEnum:
|
||||
|
|
@ -2186,7 +2214,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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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) =
|
||||
|
|
|
|||
|
|
@ -1397,7 +1397,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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -1884,7 +1884,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
|
||||
|
|
|
|||
|
|
@ -1136,6 +1136,8 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
|
|||
of tyTypeClasses:
|
||||
if tfGenericTypeParam in t.flags or taConcept in flags: #or taField notin flags:
|
||||
discard
|
||||
elif t.isResolvedUserTypeClass:
|
||||
result = typeAllowedAux(marker, t.lastSon, kind, flags)
|
||||
elif kind notin {skParam, skResult}:
|
||||
result = t
|
||||
of tyGenericBody, tyGenericParam, tyGenericInvocation,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue