summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2023-12-17 18:43:52 +0100
committerGitHub <noreply@github.com>2023-12-17 18:43:52 +0100
commitfe18ec5dc089831c6ea634ade211d8d0dadfec86 (patch)
treebba4a9600c3c53face21ad6cdec45be54f01ca65 /compiler
parent9b08abaa0574c32f414c09bb4ef183739003884d (diff)
downloadNim-fe18ec5dc089831c6ea634ade211d8d0dadfec86.tar.gz
types refactoring; WIP (#23086)
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ast.nim36
-rw-r--r--compiler/astyaml.nim76
-rw-r--r--compiler/enumtostr.nim2
-rw-r--r--compiler/patterns.nim2
-rw-r--r--compiler/sem.nim14
-rw-r--r--compiler/semcall.nim11
-rw-r--r--compiler/seminst.nim21
-rw-r--r--compiler/suggest.nim4
-rw-r--r--compiler/types.nim4
-rw-r--r--compiler/vm.nim6
-rw-r--r--compiler/vtables.nim2
11 files changed, 81 insertions, 97 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index ce86d7369..06b6cd357 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..<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:
diff --git a/compiler/astyaml.nim b/compiler/astyaml.nim
index b098d92b9..c7e090cd3 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 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 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: 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)
-
-proc treeToYamlAux(
-    res: var string;
-    conf: ConfigRef;
-    n: PNode;
-    marker: var IntSet;
-    indent: int;
-    maxRecDepth: int;
-) =
+        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) =
   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)
diff --git a/compiler/enumtostr.nim b/compiler/enumtostr.nim
index 908c48ccb..dc516d2e5 100644
--- a/compiler/enumtostr.nim
+++ b/compiler/enumtostr.nim
@@ -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
 
diff --git a/compiler/patterns.nim b/compiler/patterns.nim
index 04d8593cc..32ec7fb53 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 47b9600f5..1ae7d4626 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..<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
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index f6beb1aeb..ff3479b92 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -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
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index c64c120d6..64452441b 100644
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -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)
diff --git a/compiler/suggest.nim b/compiler/suggest.nim
index 9e0fc13e4..5eb2c03ab 100644
--- a/compiler/suggest.nim
+++ b/compiler/suggest.nim
@@ -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
diff --git a/compiler/types.nim b/compiler/types.nim
index 7d7d3349d..04f953f79 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 7063a7268..88419d5dd 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..<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:
diff --git a/compiler/vtables.nim b/compiler/vtables.nim
index b9b13badc..928c64dd5 100644
--- a/compiler/vtables.nim
+++ b/compiler/vtables.nim
@@ -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)