From 07fc303d6fbbb86be2ae375f01c112cab0b86464 Mon Sep 17 00:00:00 2001 From: metagn Date: Sun, 6 Oct 2024 00:51:50 +0300 Subject: [PATCH 1/3] fix calls to implicitly generic params in generic contexts --- compiler/semexprs.nim | 3 +++ compiler/sigmatch.nim | 6 +++++ compiler/types.nim | 3 ++- tests/proc/tgenericdefaultparam.nim | 36 +++++++++++++++++++++++++++++ 4 files changed, 47 insertions(+), 1 deletion(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 2885142a76e9..ca2a488a3d7c 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -616,6 +616,9 @@ proc semIs(c: PContext, n: PNode, flags: TExprFlags): PNode = var lhsType = n[1].typ if lhsType.kind != tyTypeDesc: + if c.inGenericContext > 0 and lhsType.containsUnresolvedType: + # `x is T` where `x` is unresolved, cannot evaluate yet + return if liftLhs: n[1] = makeTypeSymNode(c, lhsType, n[1].info) lhsType = n[1].typ diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 6ea2c7bb5781..e3e21b1feaf1 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1299,6 +1299,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, case a.kind of tyOr: # XXX: deal with the current dual meaning of tyGenericParam + if c.c.inGenericContext > 0 and not c.isNoCall: + # a has unresolved type, don't match call in generic context + return isNone c.typedescMatched = true # seq[int|string] vs seq[number] # both int and string must match against number @@ -1339,6 +1342,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, if f.kind == tyAnything: return isGeneric else: return isNone of tyUserTypeClass, tyUserTypeClassInst: + if c.c.inGenericContext > 0 and not c.isNoCall: + # a has unresolved type, don't match call in generic context + return isNone if c.c.matchedConcept != nil and c.c.matchedConcept.depth <= 4: # consider this: 'var g: Node' *within* a concept where 'Node' # is a concept too (tgraph) diff --git a/compiler/types.nim b/compiler/types.nim index a441b0ea2b52..051c89040760 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1500,7 +1500,8 @@ proc containsGenericType*(t: PType): bool = result = iterOverType(t, containsGenericTypeIter, nil) proc containsUnresolvedTypeIter(t: PType, closure: RootRef): bool = - if tfUnresolved in t.flags: return true + if {tfUnresolved, tfGenericTypeParam, tfImplicitTypeParam} * t.flags != {}: + return true case t.kind of tyStatic: return t.n == nil diff --git a/tests/proc/tgenericdefaultparam.nim b/tests/proc/tgenericdefaultparam.nim index 7bce591ce5ee..94e2993d39f6 100644 --- a/tests/proc/tgenericdefaultparam.nim +++ b/tests/proc/tgenericdefaultparam.nim @@ -96,3 +96,39 @@ block: # issue #24121 proc baz[T: FooBar](x: T, y = foo(x)): string = y doAssert baz(Foo(123)) == "b" doAssert baz(Bar(123)) == "c" + +block: # using `or` type + template val(x: int): string = "int" + template val(x: string): string = "string" + proc foo(x: int | string, y = val(x)): string = + y + + doAssert foo(123) == "int" + doAssert foo("abc") == "string" + +block: # using concept type + type Foo = concept x + x is int | string + template val(x: int): string = "int" + template val(x: string): string = "string" + proc foo(x: Foo, y = val(x)): string = + y + + doAssert foo(123) == "int" + doAssert foo("abc") == "string" + +block: # using `or` type with direct `is` + proc foo(x: int | string, y = when x is int: "int" else: "string"): string = + y + + doAssert foo(123) == "int" + doAssert foo("abc") == "string" + +block: # using concept type with direct `is` + type Foo = concept x + x is int | string + proc foo(x: Foo, y = when x is int: "int" else: "string"): string = + y + + doAssert foo(123) == "int" + doAssert foo("abc") == "string" From ef331222c4fc5cc7db8661de9f42f8b9dc89fa33 Mon Sep 17 00:00:00 2001 From: metagn Date: Sun, 6 Oct 2024 01:56:56 +0300 Subject: [PATCH 2/3] fix no typedesc lifting --- compiler/semexprs.nim | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index ca2a488a3d7c..ae142e2fc40b 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -616,16 +616,12 @@ proc semIs(c: PContext, n: PNode, flags: TExprFlags): PNode = var lhsType = n[1].typ if lhsType.kind != tyTypeDesc: - if c.inGenericContext > 0 and lhsType.containsUnresolvedType: - # `x is T` where `x` is unresolved, cannot evaluate yet - return if liftLhs: n[1] = makeTypeSymNode(c, lhsType, n[1].info) lhsType = n[1].typ - else: - if c.inGenericContext > 0 and lhsType.base.containsUnresolvedType: - # BUGFIX: don't evaluate this too early: ``T is void`` - return + if c.inGenericContext > 0 and lhsType.containsUnresolvedType: + # BUGFIX: don't evaluate this too early: ``T is void`` + return result = isOpImpl(c, n, flags) From 4a5c932d7e112eaf922083418666056cdc63febb Mon Sep 17 00:00:00 2001 From: metagn Date: Wed, 9 Oct 2024 11:28:44 +0300 Subject: [PATCH 3/3] remove unnecessary code, covered by #24123 --- compiler/sigmatch.nim | 6 ------ 1 file changed, 6 deletions(-) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index e3e21b1feaf1..6ea2c7bb5781 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1299,9 +1299,6 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, case a.kind of tyOr: # XXX: deal with the current dual meaning of tyGenericParam - if c.c.inGenericContext > 0 and not c.isNoCall: - # a has unresolved type, don't match call in generic context - return isNone c.typedescMatched = true # seq[int|string] vs seq[number] # both int and string must match against number @@ -1342,9 +1339,6 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, if f.kind == tyAnything: return isGeneric else: return isNone of tyUserTypeClass, tyUserTypeClassInst: - if c.c.inGenericContext > 0 and not c.isNoCall: - # a has unresolved type, don't match call in generic context - return isNone if c.c.matchedConcept != nil and c.c.matchedConcept.depth <= 4: # consider this: 'var g: Node' *within* a concept where 'Node' # is a concept too (tgraph)