types refactoring; WIP (#23086)

This commit is contained in:
Andreas Rumpf
2023-12-17 18:43:52 +01:00
committed by GitHub
parent 9b08abaa05
commit fe18ec5dc0
11 changed files with 79 additions and 95 deletions

View File

@@ -1602,6 +1602,14 @@ proc signatureLen*(t: PType): int {.inline.} =
proc paramsLen*(t: PType): int {.inline.} =
result = t.sons.len - 1
proc genericParamsLen*(t: PType): int {.inline.} =
assert t.kind == tyGenericInst
result = t.sons.len - 2 # without 'head' and 'body'
proc genericInvocationParamsLen*(t: PType): int {.inline.} =
assert t.kind == tyGenericInvocation
result = t.sons.len - 1 # without 'head'
proc kidsLen*(t: PType): int {.inline.} =
result = t.sons.len
@@ -1611,17 +1619,34 @@ proc hasElementType*(t: PType): bool {.inline.} = t.sons.len > 0
proc isEmptyTupleType*(t: PType): bool {.inline.} = t.sons.len == 0
proc isSingletonTupleType*(t: PType): bool {.inline.} = t.sons.len == 1
proc genericConstraint*(t: PType): PType {.inline.} = t.sons[0]
iterator genericInstParams*(t: PType): (bool, PType) =
for i in 1..<t.sons.len-1:
yield (i!=1, t.sons[i])
iterator genericInstParamPairs*(a, b: PType): (int, PType, PType) =
for i in 1..<min(a.sons.len, b.sons.len)-1:
yield (i-1, a.sons[i], b.sons[i])
iterator genericInvocationParams*(t: PType): (bool, PType) =
for i in 1..<t.sons.len:
yield (i!=1, t.sons[i])
iterator genericBodyParams*(t: PType): (bool, PType) =
iterator genericInvocationAndBodyElements*(a, b: PType): (PType, PType) =
for i in 1..<a.sons.len:
yield (a.sons[i], b.sons[i-1])
iterator genericInvocationParamPairs*(a, b: PType): (bool, PType, PType) =
for i in 1..<a.sons.len:
if i >= b.sons.len:
yield (false, nil, nil)
else:
yield (true, a.sons[i], b.sons[i])
iterator genericBodyParams*(t: PType): (int, PType) =
for i in 0..<t.sons.len-1:
yield (i!=0, t.sons[i])
yield (i, t.sons[i])
iterator userTypeClassInstParams*(t: PType): (bool, PType) =
for i in 1..<t.sons.len-1:
@@ -1676,6 +1701,11 @@ proc newSons*(father: PNode, length: int) =
proc newSons*(father: PType, length: int) =
setLen(father.sons, length)
proc truncateInferredTypeCandidates*(t: PType) {.inline.} =
assert t.kind == tyInferred
if t.sons.len > 1:
setLen(t.sons, 1)
proc assignType*(dest, src: PType) =
dest.kind = src.kind
dest.flags = src.flags
@@ -2041,7 +2071,7 @@ proc skipGenericOwner*(s: PSym): PSym =
## symbol. This proc skips such owners and goes straight to the owner
## of the generic itself (the module or the enclosing proc).
result = if s.kind == skModule:
s
s
elif s.kind in skProcKinds and sfFromGeneric in s.flags and s.owner.kind != skModule:
s.owner.owner
else:

View File

@@ -45,38 +45,11 @@ proc lineInfoToStr*(conf: ConfigRef; info: TLineInfo): string =
result.addYamlString(toFilename(conf, info))
result.addf ", $1, $2]", [toLinenumber(info), toColumn(info)]
proc treeToYamlAux(
res: var string;
conf: ConfigRef;
n: PNode;
marker: var IntSet;
indent, maxRecDepth: int;
)
proc treeToYamlAux(res: var string; conf: ConfigRef; n: PNode; marker: var IntSet; indent, maxRecDepth: int)
proc symToYamlAux(res: var string; conf: ConfigRef; n: PSym; marker: var IntSet; indent, maxRecDepth: int)
proc typeToYamlAux(res: var string; conf: ConfigRef; n: PType; marker: var IntSet; indent, maxRecDepth: int)
proc symToYamlAux(
res: var string;
conf: ConfigRef;
n: PSym;
marker: var IntSet;
indent, maxRecDepth: int;
)
proc typeToYamlAux(
res: var string;
conf: ConfigRef;
n: PType;
marker: var IntSet;
indent, maxRecDepth: int;
)
proc symToYamlAux(
res: var string;
conf: ConfigRef;
n: PSym;
marker: var IntSet;
indent: int;
maxRecDepth: int;
) =
proc symToYamlAux(res: var string; conf: ConfigRef; n: PSym; marker: var IntSet; indent: int; maxRecDepth: int) =
if n == nil:
res.add("null")
elif containsOrIncl(marker, n.id):
@@ -106,14 +79,7 @@ proc symToYamlAux(
res.addf("\n$1lode: $2", [istr])
res.treeToYamlAux(conf, n.loc.lode, marker, indent + 1, maxRecDepth - 1)
proc typeToYamlAux(
res: var string;
conf: ConfigRef;
n: PType;
marker: var IntSet;
indent: int;
maxRecDepth: int;
) =
proc typeToYamlAux(res: var string; conf: ConfigRef; n: PType; marker: var IntSet; indent: int; maxRecDepth: int) =
if n == nil:
res.add("null")
elif containsOrIncl(marker, n.id):
@@ -130,20 +96,14 @@ proc typeToYamlAux(
res.addf("\n$1callconv: $2", [istr, makeYamlString($n.callConv)])
res.addf("\n$1size: $2", [istr, $(n.size)])
res.addf("\n$1align: $2", [istr, $(n.align)])
if n.len > 0:
if n.hasElementType:
res.addf("\n$1sons:")
for i in 0..<n.len:
for a in n.kids:
res.addf("\n - ")
res.typeToYamlAux(conf, n[i], marker, indent + 1, maxRecDepth - 1)
res.typeToYamlAux(conf, a, marker, indent + 1, maxRecDepth - 1)
proc treeToYamlAux(
res: var string;
conf: ConfigRef;
n: PNode;
marker: var IntSet;
indent: int;
maxRecDepth: int;
) =
proc treeToYamlAux(res: var string; conf: ConfigRef; n: PNode; marker: var IntSet; indent: int;
maxRecDepth: int) =
if n == nil:
res.add("null")
else:
@@ -178,23 +138,17 @@ proc treeToYamlAux(
res.addf("\n$1typ: ", [istr])
res.typeToYamlAux(conf, n.typ, marker, indent + 1, maxRecDepth)
proc treeToYaml*(
conf: ConfigRef; n: PNode; indent: int = 0; maxRecDepth: int = -1
): string =
proc treeToYaml*(conf: ConfigRef; n: PNode; indent: int = 0; maxRecDepth: int = -1): string =
var marker = initIntSet()
result = newStringOfCap(1024)
result.treeToYamlAux(conf, n, marker, indent, maxRecDepth)
proc typeToYaml*(
conf: ConfigRef; n: PType; indent: int = 0; maxRecDepth: int = -1
): string =
proc typeToYaml*(conf: ConfigRef; n: PType; indent: int = 0; maxRecDepth: int = -1): string =
var marker = initIntSet()
result = newStringOfCap(1024)
result.typeToYamlAux(conf, n, marker, indent, maxRecDepth)
proc symToYaml*(
conf: ConfigRef; n: PSym; indent: int = 0; maxRecDepth: int = -1
): string =
proc symToYaml*(conf: ConfigRef; n: PSym; indent: int = 0; maxRecDepth: int = -1): string =
var marker = initIntSet()
result = newStringOfCap(1024)
result.symToYamlAux(conf, n, marker, indent, maxRecDepth)

View File

@@ -63,7 +63,7 @@ proc searchObjCaseImpl(obj: PNode; field: PSym): PNode =
proc searchObjCase(t: PType; field: PSym): PNode =
result = searchObjCaseImpl(t.n, field)
if result == nil and t.len > 0:
if result == nil and t.baseClass != nil:
result = searchObjCase(t.baseClass.skipTypes({tyAlias, tyGenericInst, tyRef, tyPtr}), field)
doAssert result != nil

View File

@@ -276,7 +276,7 @@ proc addToArgList(result, n: PNode) =
proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
## returns a tree to semcheck if the rule triggered; nil otherwise
var ctx = TPatternContext(owner: s, c: c, formals: s.typ.len-1)
var ctx = TPatternContext(owner: s, c: c, formals: s.typ.paramsLen)
var m = matchStmtList(ctx, s.ast[patternPos], n)
if isNil(m): return nil
# each parameter should have been bound; we simply setup a call and

View File

@@ -144,7 +144,7 @@ proc commonType*(c: PContext; x, y: PType): PType =
elif b.kind == tyTyped: result = b
elif a.kind == tyTypeDesc:
# turn any concrete typedesc into the abstract typedesc type
if a.len == 0: result = a
if not a.hasElementType: result = a
else:
result = newType(tyTypeDesc, c.idgen, a.owner)
rawAddSon(result, newType(tyNone, c.idgen, a.owner))
@@ -153,17 +153,17 @@ proc commonType*(c: PContext; x, y: PType): PType =
# check for seq[empty] vs. seq[int]
let idx = ord(b.kind == tyArray)
if a[idx].kind == tyEmpty: return y
elif a.kind == tyTuple and b.kind == tyTuple and a.len == b.len:
elif a.kind == tyTuple and b.kind == tyTuple and sameTupleLengths(a, b):
var nt: PType = nil
for i in 0..<a.len:
let aEmpty = isEmptyContainer(a[i])
let bEmpty = isEmptyContainer(b[i])
for i, aa, bb in tupleTypePairs(a, b):
let aEmpty = isEmptyContainer(aa)
let bEmpty = isEmptyContainer(bb)
if aEmpty != bEmpty:
if nt.isNil:
nt = copyType(a, c.idgen, a.owner)
copyTypeProps(c.graph, c.idgen.module, nt, a)
nt[i] = if aEmpty: b[i] else: a[i]
nt[i] = if aEmpty: bb else: aa
if not nt.isNil: result = nt
#elif b[idx].kind == tyEmpty: return x
elif a.kind == tyRange and b.kind == tyRange:
@@ -503,7 +503,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
else:
var retType = s.typ.returnType
if retType.kind == tyTypeDesc and tfUnresolved in retType.flags and
retType.len == 1:
retType.hasElementType:
# bug #11941: template fails(T: type X, v: auto): T
# does not mean we expect a tyTypeDesc.
retType = retType.skipModifier

View File

@@ -581,7 +581,7 @@ proc inheritBindings(c: PContext, x: var TCandidate, expectedType: PType) =
## Helper proc to inherit bound generic parameters from expectedType into x.
## Does nothing if 'inferGenericTypes' isn't in c.features.
if inferGenericTypes notin c.features: return
if expectedType == nil or x.callee[0] == nil: return # required for inference
if expectedType == nil or x.callee.returnType == nil: return # required for inference
var
flatUnbound: seq[PType] = @[]
@@ -593,14 +593,14 @@ proc inheritBindings(c: PContext, x: var TCandidate, expectedType: PType) =
## skips types and puts the skipped version on stack
# It might make sense to skip here one by one. It's not part of the main
# type reduction because the right side normally won't be skipped
const toSkip = { tyVar, tyLent, tyStatic, tyCompositeTypeClass, tySink }
const toSkip = {tyVar, tyLent, tyStatic, tyCompositeTypeClass, tySink}
let
x = a.skipTypes(toSkip)
y = if a.kind notin toSkip: b
else: b.skipTypes(toSkip)
typeStack.add((x, y))
stackPut(x.callee[0], expectedType)
stackPut(x.callee.returnType, expectedType)
while typeStack.len() > 0:
let (t, u) = typeStack.pop()
@@ -608,10 +608,11 @@ proc inheritBindings(c: PContext, x: var TCandidate, expectedType: PType) =
continue
case t.kind
of ConcreteTypes, tyGenericInvocation, tyUncheckedArray:
# XXX This logic makes no sense for `tyUncheckedArray`
# nested, add all the types to stack
let
startIdx = if u.kind in ConcreteTypes: 0 else: 1
endIdx = min(u.len() - startIdx, t.len())
endIdx = min(u.kidsLen() - startIdx, t.kidsLen())
for i in startIdx ..< endIdx:
# early exit with current impl
@@ -749,7 +750,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
proc setGenericParams(c: PContext, n, expectedParams: PNode) =
## sems generic params in subscript expression
for i in 1..<n.len:
let
let
constraint =
if expectedParams != nil and i <= expectedParams.len:
expectedParams[i - 1].typ

View File

@@ -181,8 +181,7 @@ proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
# perhaps the code can be extracted in a shared function.
openScope(c)
let genericTyp = header.base
for i in 0..<genericTyp.len - 1:
let genParam = genericTyp[i]
for i, genParam in genericBodyParams(genericTyp):
var param: PSym
template paramSym(kind): untyped =
@@ -234,18 +233,18 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
var result = instCopyType(cl, prc.typ)
let originalParams = result.n
result.n = originalParams.shallowCopy
for i in 1..<result.len:
for i, resulti in paramTypes(result):
# twrong_field_caching requires these 'resetIdTable' calls:
if i > 1:
if i > FirstParamAt:
resetIdTable(cl.symMap)
resetIdTable(cl.localCache)
# take a note of the original type. If't a free type or static parameter
# we'll need to keep it unbound for the `fitNode` operation below...
var typeToFit = result[i]
var typeToFit = resulti
let needsStaticSkipping = result[i].kind == tyFromExpr
result[i] = replaceTypeVarsT(cl, result[i])
let needsStaticSkipping = resulti.kind == tyFromExpr
result[i] = replaceTypeVarsT(cl, resulti)
if needsStaticSkipping:
result[i] = result[i].skipTypes({tyStatic})
@@ -295,7 +294,7 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
resetIdTable(cl.symMap)
resetIdTable(cl.localCache)
cl.isReturnType = true
result[0] = replaceTypeVarsT(cl, result[0])
result.setReturnType replaceTypeVarsT(cl, result.returnType)
cl.isReturnType = false
result.n[0] = originalParams[0].copyTree
if result[0] != nil:
@@ -377,15 +376,15 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
# generic[void](), generic[int]()
# see ttypeor.nim test.
var i = 0
newSeq(entry.concreteTypes, fn.typ.len+gp.len-1)
newSeq(entry.concreteTypes, fn.typ.paramsLen+gp.len)
for s in instantiateGenericParamList(c, gp, pt):
addDecl(c, s)
entry.concreteTypes[i] = s.typ
inc i
pushProcCon(c, result)
instantiateProcType(c, pt, result, info)
for j in 1..<result.typ.len:
entry.concreteTypes[i] = result.typ[j]
for _, param in paramTypes(result.typ):
entry.concreteTypes[i] = param
inc i
if tfTriggersCompileTime in result.typ.flags:
incl(result.flags, sfCompileTime)

View File

@@ -337,7 +337,7 @@ proc fieldVisible*(c: PContext, f: PSym): bool {.inline.} =
proc getQuality(s: PSym): range[0..100] =
result = 100
if s.typ != nil and s.typ.len > 1:
if s.typ != nil and s.typ.paramsLen > 0:
var exp = s.typ.firstParamType.skipTypes({tyGenericInst, tyVar, tyLent, tyAlias, tySink})
if exp.kind == tyVarargs: exp = elemType(exp)
if exp.kind in {tyUntyped, tyTyped, tyGenericParam, tyAnything}: result = 50
@@ -407,7 +407,7 @@ proc suggestVar(c: PContext, n: PNode, outputs: var Suggestions) =
wholeSymTab(nameFits(c, it, n), ideCon)
proc typeFits(c: PContext, s: PSym, firstArg: PType): bool {.inline.} =
if s.typ != nil and s.typ.len > 1 and s.typ.firstParamType != nil:
if s.typ != nil and s.typ.paramsLen > 0 and s.typ.firstParamType != nil:
# special rule: if system and some weird generic match via 'tyUntyped'
# or 'tyGenericParam' we won't list it either to reduce the noise (nobody
# wants 'system.`-|` as suggestion

View File

@@ -566,8 +566,8 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
result.add(']')
of tyGenericBody:
result = typeToString(t.typeBodyImpl) & '['
for needsComma, a in t.genericBodyParams:
if needsComma: result.add(", ")
for i, a in t.genericBodyParams:
if i > 0: result.add(", ")
result.add(typeToString(a, preferTypeName))
result.add(']')
of tyTypeDesc:

View File

@@ -2486,12 +2486,12 @@ proc evalMacroCall*(module: PSym; idgen: IdGenerator; g: ModuleGraph; templInstC
tos.slots[0] = TFullReg(kind: rkNode, node: newNodeI(nkEmpty, n.info))
# setup parameters:
for i in 1..<sym.typ.len:
tos.slots[i] = setupMacroParam(n[i], sym.typ[i])
for i, param in paramTypes(sym.typ):
tos.slots[i-FirstParamAt+1] = setupMacroParam(n[i-FirstParamAt+1], param)
let gp = sym.ast[genericParamsPos]
for i in 0..<gp.len:
let idx = sym.typ.len + i
let idx = sym.typ.signatureLen + i
if idx < n.len:
tos.slots[idx] = setupMacroParam(n[idx], gp[i].sym.typ)
else:

View File

@@ -10,7 +10,7 @@ proc dispatch(x: Base, params: ...) =
]#
var base = methods[0].ast[dispatcherPos].sym
result = base
var paramLen = base.typ.len
var paramLen = base.typ.signatureLen
var body = newNodeI(nkStmtList, base.info)
var disp = newNodeI(nkIfStmt, base.info)