From 42e378184ce9a40d2ab9cb479e3233e56820991b Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Sat, 22 Mar 2025 20:02:45 +1100 Subject: [PATCH 1/4] Disable skipping generics for aliases --- compiler/docgen.nim | 1 + compiler/semexprs.nim | 15 ++++++++++++--- compiler/types.nim | 1 + 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 2b25ded7df2ce..e176029d8b917 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -1202,6 +1202,7 @@ proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind, nonExports = false): result.json["signature"]["pragmas"].add %($pragma) if n[genericParamsPos].kind != nkEmpty: result.json["signature"]["genericParams"] = newJArray() + echo result.json.pretty() for genericParam in n[genericParamsPos]: var param = %{"name": %($genericParam)} if genericParam.sym.typ.len > 0: diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 2aa646dd60d91..2c1ae8c43dd60 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1361,7 +1361,7 @@ const tyDotOpTransparent = {tyVar, tyLent, tyPtr, tyRef, tyOwned, tyAlias, tySink} proc readTypeParameter(c: PContext, typ: PType, - paramName: PIdent, info: TLineInfo): PNode = + paramName: PIdent, info: TLineInfo, skip = true): 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]` @@ -1388,7 +1388,10 @@ proc readTypeParameter(c: PContext, typ: PType, if typ.kind != tyUserTypeClass: let ty = if typ.kind == tyCompositeTypeClass: typ.firstGenericParam.skipGenericAlias - else: typ.skipGenericAlias + elif skip: typ.skipGenericAlias + else: typ + if isCompilerDebug(): + echo "Type is this ", typ, " ", ty, " ", typ.kind let tbody = ty[0] for s in 0.. 0: result = semGenericStmt(c, n) @@ -1576,6 +1583,8 @@ proc tryReadingTypeField(c: PContext, n: PNode, i: PIdent, ty: PType): PNode = result = tryReadingTypeField(c, n, i, ty.skipModifier) if result == nil: result = tryReadingGenericParam(c, n, i, ty) + if isCompilerDebug(): + echo "Got ", result else: result = tryReadingGenericParam(c, n, i, ty) diff --git a/compiler/types.nim b/compiler/types.nim index 16853e5ffa175..8f686d24693ee 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1204,6 +1204,7 @@ proc sameChildrenAux(a, b: PType, c: var TSameTypeClosure): bool = if not result: return proc isGenericAlias*(t: PType): bool = + # TODO: Check that it is just passing everything return t.kind == tyGenericInst and t.skipModifier.skipTypes({tyAlias}).kind == tyGenericInst proc genericAliasDepth*(t: PType): int = From 6fdf49556ecaeaf7d57588f2bf04131d953e4718 Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Sat, 29 Mar 2025 19:09:01 +1100 Subject: [PATCH 2/4] Remove debug echos --- compiler/semexprs.nim | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 2c1ae8c43dd60..968537e0cb511 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1390,8 +1390,6 @@ proc readTypeParameter(c: PContext, typ: PType, let ty = if typ.kind == tyCompositeTypeClass: typ.firstGenericParam.skipGenericAlias elif skip: typ.skipGenericAlias else: typ - if isCompilerDebug(): - echo "Type is this ", typ, " ", ty, " ", typ.kind let tbody = ty[0] for s in 0.. 0: result = semGenericStmt(c, n) @@ -1583,8 +1577,6 @@ proc tryReadingTypeField(c: PContext, n: PNode, i: PIdent, ty: PType): PNode = result = tryReadingTypeField(c, n, i, ty.skipModifier) if result == nil: result = tryReadingGenericParam(c, n, i, ty) - if isCompilerDebug(): - echo "Got ", result else: result = tryReadingGenericParam(c, n, i, ty) @@ -3304,8 +3296,6 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType when defined(nimCompilerStacktraceHints): setFrameMsg c.config$n.info & " " & $n.kind when false: # see `tdebugutils` - if isCompilerDebug(): - echo (">", c.config$n.info, n, flags, n.kind) defer: if isCompilerDebug(): echo ("<", c.config$n.info, n, ?.result.typ) From 2c76ad5379e8fe0d969c19aad71f9022a9ff3a63 Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Sat, 29 Mar 2025 19:26:50 +1100 Subject: [PATCH 3/4] Add test case I forgot to commit Add some documentation on the new parameter --- compiler/docgen.nim | 1 - compiler/semexprs.nim | 13 ++++++++++--- compiler/types.nim | 1 - tests/generics/t24791.nim | 11 +++++++++++ 4 files changed, 21 insertions(+), 5 deletions(-) create mode 100644 tests/generics/t24791.nim diff --git a/compiler/docgen.nim b/compiler/docgen.nim index e176029d8b917..2b25ded7df2ce 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -1202,7 +1202,6 @@ proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind, nonExports = false): result.json["signature"]["pragmas"].add %($pragma) if n[genericParamsPos].kind != nkEmpty: result.json["signature"]["genericParams"] = newJArray() - echo result.json.pretty() for genericParam in n[genericParamsPos]: var param = %{"name": %($genericParam)} if genericParam.sym.typ.len > 0: diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 968537e0cb511..30f4aa6ad0dbe 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1362,6 +1362,7 @@ const proc readTypeParameter(c: PContext, typ: PType, paramName: PIdent, info: TLineInfo, skip = true): PNode = + ## - **skip**: Skips generic aliases and tries to get the parameter from the aliased type. # 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]` @@ -1387,9 +1388,12 @@ proc readTypeParameter(c: PContext, typ: PType, discard if typ.kind != tyUserTypeClass: - let ty = if typ.kind == tyCompositeTypeClass: typ.firstGenericParam.skipGenericAlias - elif skip: typ.skipGenericAlias - else: typ + let ty = block: + let ty = if typ.kind == tyCompositeTypeClass: typ.firstGenericParam + else: typ + if skip: typ.skipGenericAlias() + else: typ + let tbody = ty[0] for s in 0.. 0: @@ -3296,6 +3301,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType when defined(nimCompilerStacktraceHints): setFrameMsg c.config$n.info & " " & $n.kind when false: # see `tdebugutils` + if isCompilerDebug(): + echo (">", c.config$n.info, n, flags, n.kind) defer: if isCompilerDebug(): echo ("<", c.config$n.info, n, ?.result.typ) diff --git a/compiler/types.nim b/compiler/types.nim index 8f686d24693ee..16853e5ffa175 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1204,7 +1204,6 @@ proc sameChildrenAux(a, b: PType, c: var TSameTypeClosure): bool = if not result: return proc isGenericAlias*(t: PType): bool = - # TODO: Check that it is just passing everything return t.kind == tyGenericInst and t.skipModifier.skipTypes({tyAlias}).kind == tyGenericInst proc genericAliasDepth*(t: PType): int = diff --git a/tests/generics/t24791.nim b/tests/generics/t24791.nim new file mode 100644 index 0000000000000..1b70c97a4c082 --- /dev/null +++ b/tests/generics/t24791.nim @@ -0,0 +1,11 @@ +import std/options + +type + Foo[D: static int; T] = T + Bar[D] = Option[D] + Bizz = Foo[1, string] + Buzz = Foo[2, Option[string]] + +assert Bar[string].D is string +assert Bizz.D == 1 +assert Buzz.D == 2 From 46be3826bc636d0cbaf62f32aae4e02a0d8b2c76 Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Sat, 29 Mar 2025 19:31:44 +1100 Subject: [PATCH 4/4] Add check that the inner type is read first --- tests/generics/t24791.nim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/generics/t24791.nim b/tests/generics/t24791.nim index 1b70c97a4c082..570308dcc778f 100644 --- a/tests/generics/t24791.nim +++ b/tests/generics/t24791.nim @@ -6,6 +6,9 @@ type Bizz = Foo[1, string] Buzz = Foo[2, Option[string]] -assert Bar[string].D is string + CheckPriority[T: static int; D] = Option[D] + +assert Bar[string].D is string assert Bizz.D == 1 assert Buzz.D == 2 +assert CheckPriority[3, string].T is string