From 5bfec52fe3d61be672aeaba7f5ba183ce37c70b8 Mon Sep 17 00:00:00 2001 From: metagn <10591326+metagn@users.noreply.github.com> Date: Mon, 4 Sep 2023 19:10:53 +0300 Subject: [PATCH 1/5] fix sym of created generic instantiation type fixes #22639 --- compiler/semtypinst.nim | 12 +++++++++++ tests/generics/timpl_ast.nim | 39 ++++++++++++++++++++++++++++++++---- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index d01ca28e4322f..ba0bfb62001dd 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -433,6 +433,18 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = # One step is enough, because the recursive nature of # handleGenericInvocation will handle the alias-to-alias-to-alias case if newbody.isGenericAlias: newbody = newbody.skipGenericAlias + + let origSym = newbody.sym + if origSym != nil and sfFromGeneric notin origSym.flags: + # same as `replaceTypeVarsS` but directly set the type without recursion: + newbody.sym = copySym(origSym, cl.c.idgen) + incl(newbody.sym.flags, sfFromGeneric) + newbody.sym.owner = origSym.owner + newbody.sym.typ = newbody + # unfortunately calling `replaceTypeVarsN` causes recursion, so this AST + # is the original generic body AST + newbody.sym.ast = origSym.ast + rawAddSon(result, newbody) checkPartialConstructedType(cl.c.config, cl.info, newbody) if not cl.allowMetaTypes: diff --git a/tests/generics/timpl_ast.nim b/tests/generics/timpl_ast.nim index 69a59e24d4aba..97fe128cd20d5 100644 --- a/tests/generics/timpl_ast.nim +++ b/tests/generics/timpl_ast.nim @@ -1,7 +1,3 @@ -discard """ - action: compile -""" - import std/macros import std/assertions @@ -47,3 +43,38 @@ block: # issues #9899, ##14708 macro parse(s: static string) = result = parseStmt(s) parse("type " & implRepr(Option)) + +block: # issue #22639 + type + Spectrum[N: static int] = object + data: array[N, float] + AngleInterpolator = object + data: seq[Spectrum[60]] + proc initInterpolator(num: int): AngleInterpolator = + result = AngleInterpolator() + for i in 0 ..< num: + result.data.add Spectrum[60]() + macro genCompatibleTuple(t: typed): untyped = + let typ = t.getType[1].getTypeImpl[2] + result = nnkTupleTy.newTree() + for i, ch in typ: # is `nnkObjectTy` + result.add nnkIdentDefs.newTree(ident(ch[0].strVal), # ch is `nnkIdentDefs` + ch[1], + newEmptyNode()) + proc fullSize[T: object | tuple](x: T): int = + var tmp: genCompatibleTuple(T) + result = 0 + for field, val in fieldPairs(x): + result += sizeof(val) + doAssert result == sizeof(tmp) + + let reflectivity = initInterpolator(1) + for el in reflectivity.data: + doAssert fullSize(el) == sizeof(el) + doAssert fullSize(reflectivity.data[0]) == sizeof(reflectivity.data[0]) + doAssert genCompatibleTuple(Spectrum[60]) is tuple[data: array[60, float]] + doAssert genCompatibleTuple(Spectrum[120]) is tuple[data: array[120, float]] + type Foo[T] = object + data: T + doAssert genCompatibleTuple(Foo[int]) is tuple[data: int] + doAssert genCompatibleTuple(Foo[float]) is tuple[data: float] From 6a6bd5a2e356cd12b15f764e238a24393308f7cb Mon Sep 17 00:00:00 2001 From: metagn <10591326+metagn@users.noreply.github.com> Date: Mon, 4 Sep 2023 22:57:26 +0300 Subject: [PATCH 2/5] adapt isGenericSubtype, apply suggestion --- compiler/semtypinst.nim | 2 +- compiler/sigmatch.nim | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index ba0bfb62001dd..54ea9769c6e2f 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -443,7 +443,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = newbody.sym.typ = newbody # unfortunately calling `replaceTypeVarsN` causes recursion, so this AST # is the original generic body AST - newbody.sym.ast = origSym.ast + newbody.sym.ast = copyTree(origSym.ast) rawAddSon(result, newbody) checkPartialConstructedType(cl.c.config, cl.info, newbody) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index bb99463b64dd4..10e65541ff3e4 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -505,6 +505,14 @@ proc skipToObject(t: PType; skipped: var SkippedPtr): PType = if r.kind == tyObject and ptrs <= 1: result = r else: result = nil +proc getObjectSym(t: PType, skip: var SkippedPtr): PSym = + if tfFromGeneric in t.flags and t.typeInst.kind == tyGenericInst: + let oldSkip = skip + result = t.typeInst[0].skipToObject(skip).sym + assert skip == oldSkip + else: + result = t.sym + proc isGenericSubtype(c: var TCandidate; a, f: PType, d: var int, fGenericOrigin: PType): bool = assert f.kind in {tyGenericInst, tyGenericInvocation, tyGenericBody} var askip = skippedNone @@ -512,11 +520,12 @@ proc isGenericSubtype(c: var TCandidate; a, f: PType, d: var int, fGenericOrigin var t = a.skipToObject(askip) let r = f.skipToObject(fskip) if r == nil: return false + let rSym = getObjectSym(r, fskip) var depth = 0 var last = a # XXX sameObjectType can return false here. Need to investigate # why that is but sameObjectType does way too much work here anyway. - while t != nil and r.sym != t.sym and askip == fskip: + while t != nil and rSym != getObjectSym(t, askip) and askip == fskip: t = t[0] if t == nil: break last = t @@ -1602,7 +1611,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, # crossing path with metatypes/aliases, so we need to separate them # by checking sym.id let genericSubtype = isGenericSubtype(c, x, f, depth, f) - if not (genericSubtype and aobj.sym.id != fobj.sym.id) and aOrig.kind != tyGenericBody: + if not (genericSubtype and getObjectSym(aobj, askip).id != getObjectSym(fobj, fskip).id) and aOrig.kind != tyGenericBody: depth = -1 if depth >= 0: From 1356a21bccfaed3994f714a031b5612c98b70f66 Mon Sep 17 00:00:00 2001 From: metagn <10591326+metagn@users.noreply.github.com> Date: Mon, 4 Sep 2023 23:56:20 +0300 Subject: [PATCH 3/5] remove unnecessary skip matching --- compiler/sigmatch.nim | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 10e65541ff3e4..a6cda65b15a24 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -505,11 +505,10 @@ proc skipToObject(t: PType; skipped: var SkippedPtr): PType = if r.kind == tyObject and ptrs <= 1: result = r else: result = nil -proc getObjectSym(t: PType, skip: var SkippedPtr): PSym = +proc getObjectSym(t: PType): PSym = if tfFromGeneric in t.flags and t.typeInst.kind == tyGenericInst: - let oldSkip = skip - result = t.typeInst[0].skipToObject(skip).sym - assert skip == oldSkip + var dummy: SkippedPtr + result = t.typeInst[0].skipToObject(dummy).sym else: result = t.sym @@ -520,12 +519,12 @@ proc isGenericSubtype(c: var TCandidate; a, f: PType, d: var int, fGenericOrigin var t = a.skipToObject(askip) let r = f.skipToObject(fskip) if r == nil: return false - let rSym = getObjectSym(r, fskip) + let rSym = getObjectSym(r) var depth = 0 var last = a # XXX sameObjectType can return false here. Need to investigate # why that is but sameObjectType does way too much work here anyway. - while t != nil and rSym != getObjectSym(t, askip) and askip == fskip: + while t != nil and rSym != getObjectSym(t) and askip == fskip: t = t[0] if t == nil: break last = t @@ -1611,7 +1610,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, # crossing path with metatypes/aliases, so we need to separate them # by checking sym.id let genericSubtype = isGenericSubtype(c, x, f, depth, f) - if not (genericSubtype and getObjectSym(aobj, askip).id != getObjectSym(fobj, fskip).id) and aOrig.kind != tyGenericBody: + if not (genericSubtype and getObjectSym(aobj).id != getObjectSym(fobj).id) and aOrig.kind != tyGenericBody: depth = -1 if depth >= 0: From 9602de143652e12c4881fb816c2eaed89ff63ee2 Mon Sep 17 00:00:00 2001 From: metagn <10591326+metagn@users.noreply.github.com> Date: Tue, 5 Sep 2023 01:00:56 +0300 Subject: [PATCH 4/5] simpler skip, fixed privateaccess --- compiler/sigmatch.nim | 3 +-- compiler/suggest.nim | 6 ++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index a6cda65b15a24..00872b57878a1 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -507,8 +507,7 @@ proc skipToObject(t: PType; skipped: var SkippedPtr): PType = proc getObjectSym(t: PType): PSym = if tfFromGeneric in t.flags and t.typeInst.kind == tyGenericInst: - var dummy: SkippedPtr - result = t.typeInst[0].skipToObject(dummy).sym + result = t.typeInst[0].skipTypes(skipPtrs).sym else: result = t.sym diff --git a/compiler/suggest.nim b/compiler/suggest.nim index c7efad1af64e3..5554991bd7369 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -280,10 +280,8 @@ proc fieldVisible*(c: PContext, f: PSym): bool {.inline.} = for module in c.friendModules: if fmoduleId == module.id: return true if f.kind == skField: - var symObj = f.owner - if symObj.typ.skipTypes({tyGenericBody, tyGenericInst, tyGenericInvocation, tyAlias}).kind in {tyRef, tyPtr}: - symObj = symObj.typ.toObjectFromRefPtrGeneric.sym - assert symObj != nil + var symObj = f.owner.typ.toObjectFromRefPtrGeneric.sym + assert symObj != nil for scope in allScopes(c.currentScope): for sym in scope.allowPrivateAccess: if symObj.id == sym.id: return true From 0e1e58f94d670dc22a8d93364a6b01ed5a4f5084 Mon Sep 17 00:00:00 2001 From: metagn <10591326+metagn@users.noreply.github.com> Date: Tue, 5 Sep 2023 02:07:42 +0300 Subject: [PATCH 5/5] revert skip --- compiler/sigmatch.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 00872b57878a1..a6cda65b15a24 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -507,7 +507,8 @@ proc skipToObject(t: PType; skipped: var SkippedPtr): PType = proc getObjectSym(t: PType): PSym = if tfFromGeneric in t.flags and t.typeInst.kind == tyGenericInst: - result = t.typeInst[0].skipTypes(skipPtrs).sym + var dummy: SkippedPtr + result = t.typeInst[0].skipToObject(dummy).sym else: result = t.sym