From fe18ec5dc089831c6ea634ade211d8d0dadfec86 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 17 Dec 2023 18:43:52 +0100 Subject: [PATCH] types refactoring; WIP (#23086) --- compiler/ast.nim | 36 +++++++++++++++++++-- compiler/astyaml.nim | 72 ++++++++---------------------------------- compiler/enumtostr.nim | 2 +- compiler/patterns.nim | 2 +- compiler/sem.nim | 14 ++++---- compiler/semcall.nim | 11 ++++--- compiler/seminst.nim | 21 ++++++------ compiler/suggest.nim | 4 +-- compiler/types.nim | 4 +-- compiler/vm.nim | 6 ++-- compiler/vtables.nim | 2 +- 11 files changed, 79 insertions(+), 95 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index ce86d7369c..06b6cd3573 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -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..= 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.. 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: diff --git a/compiler/astyaml.nim b/compiler/astyaml.nim index b098d92b93..c7e090cd3b 100644 --- a/compiler/astyaml.nim +++ b/compiler/astyaml.nim @@ -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.. 0: + if result == nil and t.baseClass != nil: result = searchObjCase(t.baseClass.skipTypes({tyAlias, tyGenericInst, tyRef, tyPtr}), field) doAssert result != nil diff --git a/compiler/patterns.nim b/compiler/patterns.nim index 04d8593ccb..32ec7fb537 100644 --- a/compiler/patterns.nim +++ b/compiler/patterns.nim @@ -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 diff --git a/compiler/sem.nim b/compiler/sem.nim index 47b9600f51..1ae7d46264 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -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.. 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.. 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.. 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 diff --git a/compiler/types.nim b/compiler/types.nim index 7d7d3349db..04f953f79d 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -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: diff --git a/compiler/vm.nim b/compiler/vm.nim index 7063a72688..88419d5ddf 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -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..