From 465034a15560d8dd089670988e0ac52fabcc6451 Mon Sep 17 00:00:00 2001 From: metagn <10591326+metagn@users.noreply.github.com> Date: Sat, 15 Apr 2023 13:27:00 +0300 Subject: [PATCH 1/9] test early param count check for overloads --- compiler/ast.nim | 5 ++ compiler/semtypes.nim | 12 ++++ compiler/sigmatch.nim | 26 ++++++++- tests/template/toverloadeduntypedparam.nim | 66 ++++++++++++++++++++++ 4 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 tests/template/toverloadeduntypedparam.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index b5306c423ca8c..33360799d9f77 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -521,6 +521,8 @@ type tfInheritable, # is the object inheritable? tfHasOwned, # type contains an 'owned' type and must be moved tfEnumHasHoles, # enum cannot be mapped into a range + # for objects becomes tfObjHasKids + # for routines becomes tfHasVarargsParam tfShallow, # type can be shallow copied on assignment tfThread, # proc type is marked as ``thread``; alias for ``gcsafe`` tfFromGeneric, # type is an instantiation of a generic; this is needed @@ -629,6 +631,7 @@ const tfUnion* = tfNoSideEffect tfGcSafe* = tfThread tfObjHasKids* = tfEnumHasHoles + tfHasVarargsParam* = tfEnumHasHoles ## routine type has varargs parameter tfReturnsNew* = tfInheritable skError* = skUnknown @@ -917,6 +920,8 @@ type # for modules, an unique index corresponding # to the module's fileIdx # for variables a slot index for the evaluator + # for routines the minimum required parameters + # (could be part of the type but no space there) offset*: int # offset of record field loc*: TLoc annex*: PLib # additional fields (seldom used, so we use a diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index d86f5ddb2c6ba..4390539b6afd0 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1281,6 +1281,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, result = newProcType(c, n.info, prev) var check = initIntSet() var counter = 0 + var requiredCounter = 0 # minimum required parameters for i in 1.. 1: m.callee.n[1].sym else: nil # current routine parameter container: PNode = nil # constructed container let firstArgBlock = findFirstArgBlock(m, n) + + # early check for parameter count + block: + let givenCount = n.len - 1 + # routine symbols precalculate minimum argument count in `position` field + # if there is no routine symbol, don't bother calculating + if m.calleeSym != nil and m.calleeSym.kind in skProcKinds: + # if this is unset, it's 0 by default, which matches everything anyway + let minCount = m.calleeSym.position + if givenCount < minCount: + m.firstMismatch.kind = kMissingParam + a = givenCount + noMatch(paramScopeOpen = false) + # no max param count for varargs + if {tfVarargs, tfHasVarargsParam} * m.callee.flags == {}: + let maxCount = formalLen - f + if givenCount > maxCount: + m.firstMismatch.kind = kExtraArg + a = maxCount + noMatch(paramScopeOpen = false) + while a < n.len: c.openShadowScope diff --git a/tests/template/toverloadeduntypedparam.nim b/tests/template/toverloadeduntypedparam.nim new file mode 100644 index 0000000000000..05d72142749b9 --- /dev/null +++ b/tests/template/toverloadeduntypedparam.nim @@ -0,0 +1,66 @@ +block: # adapted tests from PR #18618 for RFC 402, covers issue #19556 + template fails(body: untyped) = + doAssert not compiles(body) + static: doAssert not compiles(body) + block: # test basic template overload with untyped + template t1(x: int, body: untyped) = + block: + var v {.inject.} = x + body + + template t1(body: untyped) = t1(1, body) + + var outputs: seq[string] + t1: outputs.add($v) + t1(2): outputs.add($v) + t1(outputs.add("hello" & $v)) + fails: t1("hello", 10) + fails: t1() + fails: t1(1,2,3) + doAssert outputs == @["1", "2", "hello1"] + + block: # test template with varargs combine untyped + template t1(x: int, vs: varargs[string], body: untyped) = + block: + var v {.inject.} = x + vs.len + body + + template t1(body: untyped) = t1(1, "hello", body) + + var outputs: seq[string] + t1: outputs.add($v) + t1(2, "hello", "hello 2"): outputs.add($v) + fails: + t1(2, 3): discard v + fails: + t1("hello", "world"): discard v + doAssert outputs == @["2", "4"] + + block: # test template with named parameter combine untyped + template t1(x: int, y = 4, body: untyped) = + block: + var v {.inject.} = x + y + body + + template t1(body: untyped) = t1(1, 3, body) + + t1: discard v + t1(x = 1, 3): discard v + fails: + t1(2): discard v + + block: # multiple overloads, covers issue #14827 + template fun(a: bool, body: untyped): untyped = discard + template fun(a: int, body: untyped): untyped = discard + template fun(body: untyped): untyped = discard + fun(true, nonexistant) # ok + fun(1, nonexistant) # ok + fun(nonexistant) # Error: undeclared identifier: 'nonexistant' + +block: # issue #20274, pragma macros + macro a(path: string, fn: untyped): untyped = + result = fn + macro a(fn: untyped): untyped = + result = fn + proc b() {.a: "abc".} = discard + proc c() {.a.} = discard From 8a22c1a16adfb9d2c3f1de20b9fdcc85b33c67ae Mon Sep 17 00:00:00 2001 From: metagn <10591326+metagn@users.noreply.github.com> Date: Sat, 15 Apr 2023 13:39:02 +0300 Subject: [PATCH 2/9] fix issue --- compiler/semtypes.nim | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 4390539b6afd0..d7744a04a5abc 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1281,7 +1281,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, result = newProcType(c, n.info, prev) var check = initIntSet() var counter = 0 - var requiredCounter = 0 # minimum required parameters + var requiredCount = 0 # minimum required parameters for i in 1.. Date: Sat, 15 Apr 2023 14:35:55 +0300 Subject: [PATCH 3/9] fix CI, more tests --- compiler/sigmatch.nim | 8 ++-- tests/concepts/t3330.nim | 46 ++++++++-------------- tests/concepts/texplain.nim | 14 +++---- tests/errmsgs/tsigmatch.nim | 16 ++++---- tests/template/moverloadeduntypedparam.nim | 11 ++++++ tests/template/toverloadeduntypedparam.nim | 26 ++++++++++++ 6 files changed, 74 insertions(+), 47 deletions(-) create mode 100644 tests/template/moverloadeduntypedparam.nim diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 3235921257515..2eca9f62e3a6f 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -2445,19 +2445,21 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var Int let givenCount = n.len - 1 # routine symbols precalculate minimum argument count in `position` field # if there is no routine symbol, don't bother calculating - if m.calleeSym != nil and m.calleeSym.kind in skProcKinds: + if m.callee.kind == tyProc and m.calleeSym != nil and + m.calleeSym.kind in skProcKinds: # if this is unset, it's 0 by default, which matches everything anyway let minCount = m.calleeSym.position if givenCount < minCount: m.firstMismatch.kind = kMissingParam - a = givenCount + a = givenCount + 1 + formal = m.callee.n[a].sym noMatch(paramScopeOpen = false) # no max param count for varargs if {tfVarargs, tfHasVarargsParam} * m.callee.flags == {}: let maxCount = formalLen - f if givenCount > maxCount: m.firstMismatch.kind = kExtraArg - a = maxCount + a = maxCount + 1 noMatch(paramScopeOpen = false) while a < n.len: diff --git a/tests/concepts/t3330.nim b/tests/concepts/t3330.nim index 901f8d2f40d56..9903cbc3e5e83 100644 --- a/tests/concepts/t3330.nim +++ b/tests/concepts/t3330.nim @@ -2,38 +2,33 @@ discard """ matrix: "--mm:refc" errormsg: "type mismatch: got " nimout: ''' -t3330.nim(70, 4) Error: type mismatch: got +t3330.nim(58, 4) Error: type mismatch: got but expected one of: proc test(foo: Foo[int]) first type mismatch at position: 1 required type for foo: Foo[int] but expression 'bar' is of type: Bar[system.int] -t3330.nim(55, 8) Hint: Non-matching candidates for add(k, string, T) +t3330.nim(43, 8) Hint: Non-matching candidates for add(k, string, T) proc add(x: var string; y: char) - first type mismatch at position: 1 - required type for x: var string - but expression 'k' is of type: Alias + first type mismatch at position: 3 + extra argument given proc add(x: var string; y: cstring) - first type mismatch at position: 1 - required type for x: var string - but expression 'k' is of type: Alias + first type mismatch at position: 3 + extra argument given proc add(x: var string; y: string) - first type mismatch at position: 1 - required type for x: var string - but expression 'k' is of type: Alias + first type mismatch at position: 3 + extra argument given proc add[T](x: var seq[T]; y: openArray[T]) - first type mismatch at position: 1 - required type for x: var seq[T] - but expression 'k' is of type: Alias + first type mismatch at position: 3 + extra argument given proc add[T](x: var seq[T]; y: sink T) - first type mismatch at position: 1 - required type for x: var seq[T] - but expression 'k' is of type: Alias + first type mismatch at position: 3 + extra argument given -t3330.nim(55, 8) template/generic instantiation of `add` from here -t3330.nim(62, 6) Foo: 'bar.value' cannot be assigned to -t3330.nim(55, 8) template/generic instantiation of `add` from here -t3330.nim(63, 6) Foo: 'bar.x' cannot be assigned to +t3330.nim(43, 8) template/generic instantiation of `add` from here +t3330.nim(50, 6) Foo: 'bar.value' cannot be assigned to +t3330.nim(43, 8) template/generic instantiation of `add` from here +t3330.nim(51, 6) Foo: 'bar.x' cannot be assigned to expression: test(bar)''' """ @@ -42,14 +37,7 @@ expression: test(bar)''' - - - - - - - -## line 60 +## line 40 type Foo[T] = concept k add(k, string, T) diff --git a/tests/concepts/texplain.nim b/tests/concepts/texplain.nim index 8cf04ae826e7f..feadac3c53523 100644 --- a/tests/concepts/texplain.nim +++ b/tests/concepts/texplain.nim @@ -1,5 +1,5 @@ discard """ - cmd: "nim c --verbosity:0 --colors:off $file" + cmd: "nim c --verbosity:0 --colors:off --showAllMismatches:on $file" nimout: ''' texplain.nim(162, 10) Hint: Non-matching candidates for e(y) proc e(i: int): int @@ -54,9 +54,8 @@ proc r(o: RegularConcept): int texplain.nim(173, 9) template/generic instantiation of `assert` from here texplain.nim(132, 5) RegularConcept: concept predicate failed proc r[T](a: SomeNumber; b: T; c: auto) - first type mismatch at position: 1 - required type for a: SomeNumber - but expression 'n' is of type: NonMatchingType + first type mismatch at position: 2 + missing parameter: b expression: r(n) texplain.nim(174, 20) Hint: Non-matching candidates for r(y) @@ -65,9 +64,8 @@ proc r(i: string): int required type for i: string but expression 'y' is of type: MatchingType proc r[T](a: SomeNumber; b: T; c: auto) - first type mismatch at position: 1 - required type for a: SomeNumber - but expression 'y' is of type: MatchingType + first type mismatch at position: 2 + missing parameter: b texplain.nim(182, 2) Error: type mismatch: got but expected one of: @@ -118,6 +116,8 @@ expression: f(y)''' + + diff --git a/tests/errmsgs/tsigmatch.nim b/tests/errmsgs/tsigmatch.nim index 85ed341694f3d..7b920e4109158 100644 --- a/tests/errmsgs/tsigmatch.nim +++ b/tests/errmsgs/tsigmatch.nim @@ -7,9 +7,8 @@ proc f(a: A) first type mismatch at position: 2 extra argument given proc f(b: B) - first type mismatch at position: 1 - required type for b: B - but expression 'A()' is of type: A + first type mismatch at position: 2 + extra argument given expression: f(A(), "extra") tsigmatch.nim(125, 6) Error: type mismatch: got <(string, proc (){.gcsafe.})> @@ -43,16 +42,15 @@ expression: takesFuncs([proc (x: int) {.gcsafe.} = echo [x]]) tsigmatch.nim(149, 4) Error: type mismatch: got but expected one of: proc f(a0: uint8; b: string) - first type mismatch at position: 2 - named param already provided: a0 + first type mismatch at position: 3 + extra argument given expression: f(10, a0 = 5, "") tsigmatch.nim(156, 4) Error: type mismatch: got but expected one of: proc f(a1: int) - first type mismatch at position: 1 - required type for a1: int - but expression '"asdf"' is of type: string + first type mismatch at position: 2 + extra argument given proc f(a1: string; a2: varargs[string]; a3: float; a4: var string) first type mismatch at position: 7 required type for a4: var string @@ -97,6 +95,8 @@ see also: tests/errmsgs/tdeclaredlocs.nim + + ## line 100 when true: # bug #11061 Type mismatch error "first type mismatch at" points to wrong argument/position diff --git a/tests/template/moverloadeduntypedparam.nim b/tests/template/moverloadeduntypedparam.nim new file mode 100644 index 0000000000000..161da35a13916 --- /dev/null +++ b/tests/template/moverloadeduntypedparam.nim @@ -0,0 +1,11 @@ +template fun2*(a: bool, body: untyped): untyped = discard +template fun2*(a: int, body: untyped): untyped = discard +template fun2*(body: untyped): untyped = discard + +import random + +type RandomVar*[A] = concept x + var rng: Rand + rng.sample(x) is A + +proc abs*(x: RandomVar[float]): float = 123.456 diff --git a/tests/template/toverloadeduntypedparam.nim b/tests/template/toverloadeduntypedparam.nim index 05d72142749b9..01ad1a61c99e3 100644 --- a/tests/template/toverloadeduntypedparam.nim +++ b/tests/template/toverloadeduntypedparam.nim @@ -56,6 +56,11 @@ block: # adapted tests from PR #18618 for RFC 402, covers issue #19556 fun(true, nonexistant) # ok fun(1, nonexistant) # ok fun(nonexistant) # Error: undeclared identifier: 'nonexistant' + template varargsUntypedRedirection(x: varargs[untyped]) = + fun(x) + varargsUntypedRedirection(true, nonexistant) + varargsUntypedRedirection(1, nonexistant) + varargsUntypedRedirection(nonexistant) block: # issue #20274, pragma macros macro a(path: string, fn: untyped): untyped = @@ -64,3 +69,24 @@ block: # issue #20274, pragma macros result = fn proc b() {.a: "abc".} = discard proc c() {.a.} = discard + +import moverloadeduntypedparam, math + +block: + fun2(true, nonexistant) # ok + fun2(1, nonexistant) # ok + fun2(nonexistant) # Error: undeclared identifier: 'nonexistant' + +block: + template fun2(body: untyped): int = 123 + fun2(true, nonexistant) # ok + fun2(1, nonexistant) # ok + discard fun2(nonexistant) # Error: undeclared identifier: 'nonexistant' + template fun2(a: bool, body: untyped): untyped = discard + template fun2(a: int, body: untyped): untyped = discard + fun2(true, nonexistant) # ok + fun2(1, nonexistant) # ok + discard fun2(nonexistant) + +block: # ensure we don't touch generics + doAssert abs(-456.789) == 456.789 From c73d5f27e7e07941120b3435b604ab96a79b5dd6 Mon Sep 17 00:00:00 2001 From: metagn <10591326+metagn@users.noreply.github.com> Date: Sat, 15 Apr 2023 16:16:03 +0300 Subject: [PATCH 4/9] disable on nimsuggest, add legacy and changelog --- changelogs/changelog_2_0_0.md | 19 ++++++++++ compiler/options.nim | 4 +++ compiler/sigmatch.nim | 42 +++++++++++----------- testament/important_packages.nim | 2 +- tests/template/moverloadeduntypedparam.nim | 8 ----- tests/template/toverloadeduntypedparam.nim | 5 +-- 6 files changed, 46 insertions(+), 34 deletions(-) diff --git a/changelogs/changelog_2_0_0.md b/changelogs/changelog_2_0_0.md index 02310eea3d744..4d9ec71a3fbd2 100644 --- a/changelogs/changelog_2_0_0.md +++ b/changelogs/changelog_2_0_0.md @@ -219,6 +219,25 @@ replacement of the `nnkFormalParams` node as well as having child nodes unlike other type class AST. +- Overloaded routine calls will now eagerly check if the parameter counts are + compatible with each overload. This means `untyped` parameters will not be + type checked in some cases where they previously were, i.e.: + + ```nim + template foo(x: int, body: untyped) = + let value {.inject.} = x + body + template foo(body: untyped) = foo(123, body) + + # previously did not compile, now compiles: + foo: + echo value # 123 + ``` + + To fix cases where code depended on this old behavior, change the relevant + `untyped` parameters to `typed`. The switch `--legacy:noEagerParamCountMatch` + is also provided to use the old behavior for the time being. + ## Standard library additions and changes [//]: # "Changes:" diff --git a/compiler/options.nim b/compiler/options.nim index da9c9cbbb9f77..bd6a82fb893fa 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -233,6 +233,10 @@ type laxEffects ## Lax effects system prior to Nim 2.0. verboseTypeMismatch + noEagerParamCountMatch + ## Routine calls will not eagerly fail a match on incompatible + ## parameter counts. This causes some `untyped` parameters to become + ## typed. SymbolFilesOption* = enum disabledSf, writeOnlySf, readOnlySf, v2Sf, stressTest diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 2eca9f62e3a6f..a4e8087fc7f5d 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -2440,27 +2440,27 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var Int container: PNode = nil # constructed container let firstArgBlock = findFirstArgBlock(m, n) - # early check for parameter count - block: - let givenCount = n.len - 1 - # routine symbols precalculate minimum argument count in `position` field - # if there is no routine symbol, don't bother calculating - if m.callee.kind == tyProc and m.calleeSym != nil and - m.calleeSym.kind in skProcKinds: - # if this is unset, it's 0 by default, which matches everything anyway - let minCount = m.calleeSym.position - if givenCount < minCount: - m.firstMismatch.kind = kMissingParam - a = givenCount + 1 - formal = m.callee.n[a].sym - noMatch(paramScopeOpen = false) - # no max param count for varargs - if {tfVarargs, tfHasVarargsParam} * m.callee.flags == {}: - let maxCount = formalLen - f - if givenCount > maxCount: - m.firstMismatch.kind = kExtraArg - a = maxCount + 1 - noMatch(paramScopeOpen = false) + # early check for parameter count (nimsuggest allows partial calls) + when not defined(nimsuggest): + if noEagerParamCountMatch notin c.config.legacyFeatures: + let givenCount = n.len - 1 + # routine symbols precalculate minimum argument count in `position` field + # if there is no routine symbol, don't bother calculating + if m.callee.kind == tyProc and m.calleeSym != nil: + # if this is unset, it's 0 by default, which matches everything anyway + let minCount = m.calleeSym.position + if givenCount < minCount: + m.firstMismatch.kind = kMissingParam + a = givenCount + 1 + formal = m.callee.n[a].sym + noMatch(paramScopeOpen = false) + # no max param count for varargs + if {tfVarargs, tfHasVarargsParam} * m.callee.flags == {}: + let maxCount = formalLen - f + if givenCount > maxCount: + m.firstMismatch.kind = kExtraArg + a = maxCount + 1 + noMatch(paramScopeOpen = false) while a < n.len: c.openShadowScope diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 08cafa0086b12..e08b130a11407 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -33,7 +33,7 @@ var packages*: seq[NimblePackage] proc pkg(name: string; cmd = "nimble test"; url = "", useHead = true, allowFailure = false) = packages.add NimblePackage(name: name, cmd: cmd, url: url, useHead: useHead, allowFailure: allowFailure) -pkg "alea" +pkg "alea", "nimble test --legacy:noEagerParamCountMatch" # pending https://github.com/andreaferretti/alea/pull/9 pkg "argparse" pkg "arraymancer", "nim c tests/tests_cpu.nim" pkg "ast_pattern_matching", "nim c -r tests/test1.nim" diff --git a/tests/template/moverloadeduntypedparam.nim b/tests/template/moverloadeduntypedparam.nim index 161da35a13916..d9e1ec2ebe992 100644 --- a/tests/template/moverloadeduntypedparam.nim +++ b/tests/template/moverloadeduntypedparam.nim @@ -1,11 +1,3 @@ template fun2*(a: bool, body: untyped): untyped = discard template fun2*(a: int, body: untyped): untyped = discard template fun2*(body: untyped): untyped = discard - -import random - -type RandomVar*[A] = concept x - var rng: Rand - rng.sample(x) is A - -proc abs*(x: RandomVar[float]): float = 123.456 diff --git a/tests/template/toverloadeduntypedparam.nim b/tests/template/toverloadeduntypedparam.nim index 01ad1a61c99e3..5e33bcb4a426f 100644 --- a/tests/template/toverloadeduntypedparam.nim +++ b/tests/template/toverloadeduntypedparam.nim @@ -70,7 +70,7 @@ block: # issue #20274, pragma macros proc b() {.a: "abc".} = discard proc c() {.a.} = discard -import moverloadeduntypedparam, math +import moverloadeduntypedparam block: fun2(true, nonexistant) # ok @@ -87,6 +87,3 @@ block: fun2(true, nonexistant) # ok fun2(1, nonexistant) # ok discard fun2(nonexistant) - -block: # ensure we don't touch generics - doAssert abs(-456.789) == 456.789 From a9fb17e7f9c344cbb50a70544e96a06b5cf3c1b8 Mon Sep 17 00:00:00 2001 From: metagn <10591326+metagn@users.noreply.github.com> Date: Sat, 15 Apr 2023 16:55:16 +0300 Subject: [PATCH 5/9] great --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index e08b130a11407..153dcb2e58353 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -33,7 +33,7 @@ var packages*: seq[NimblePackage] proc pkg(name: string; cmd = "nimble test"; url = "", useHead = true, allowFailure = false) = packages.add NimblePackage(name: name, cmd: cmd, url: url, useHead: useHead, allowFailure: allowFailure) -pkg "alea", "nimble test --legacy:noEagerParamCountMatch" # pending https://github.com/andreaferretti/alea/pull/9 +pkg "alea", "nim c --debuginfo --path:. --run --define:reportConceptFailures --legacy:noEagerParamCountMatch tests/test.nim" # pending https://github.com/andreaferretti/alea/pull/9 pkg "argparse" pkg "arraymancer", "nim c tests/tests_cpu.nim" pkg "ast_pattern_matching", "nim c -r tests/test1.nim" From 7132a99803e2d861e4c59f4d3a45a0997b149fb6 Mon Sep 17 00:00:00 2001 From: metagn <10591326+metagn@users.noreply.github.com> Date: Sat, 15 Apr 2023 18:25:26 +0300 Subject: [PATCH 6/9] some safety --- compiler/sigmatch.nim | 15 +++++++++------ tests/template/toverloadeduntypedparam.nim | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index a4e8087fc7f5d..27ce95d052e42 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -2441,13 +2441,17 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var Int let firstArgBlock = findFirstArgBlock(m, n) # early check for parameter count (nimsuggest allows partial calls) + let givenCount = n.len - 1 + let expectedCount = formalLen - f when not defined(nimsuggest): - if noEagerParamCountMatch notin c.config.legacyFeatures: - let givenCount = n.len - 1 + if givenCount != expectedCount and + noEagerParamCountMatch notin c.config.legacyFeatures: # routine symbols precalculate minimum argument count in `position` field # if there is no routine symbol, don't bother calculating if m.callee.kind == tyProc and m.calleeSym != nil: - # if this is unset, it's 0 by default, which matches everything anyway + # if this fails just add it as an `and`: + assert m.calleeSym.kind in skProcKinds + # if this is unset, it's 0 by default, which matches everything anyway: let minCount = m.calleeSym.position if givenCount < minCount: m.firstMismatch.kind = kMissingParam @@ -2456,10 +2460,9 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var Int noMatch(paramScopeOpen = false) # no max param count for varargs if {tfVarargs, tfHasVarargsParam} * m.callee.flags == {}: - let maxCount = formalLen - f - if givenCount > maxCount: + if givenCount > expectedCount: m.firstMismatch.kind = kExtraArg - a = maxCount + 1 + a = expectedCount + 1 noMatch(paramScopeOpen = false) while a < n.len: diff --git a/tests/template/toverloadeduntypedparam.nim b/tests/template/toverloadeduntypedparam.nim index 5e33bcb4a426f..4b147214de482 100644 --- a/tests/template/toverloadeduntypedparam.nim +++ b/tests/template/toverloadeduntypedparam.nim @@ -87,3 +87,21 @@ block: fun2(true, nonexistant) # ok fun2(1, nonexistant) # ok discard fun2(nonexistant) + +block: # make sure using position field is compatible + template code: untyped = + type Foo = object + x, y, z: int + p: proc () + let a = 1 + let b = 2 + let c = 3 + let p = proc() = discard + p() + let foo = Foo(x: a, y: b, z: c, p: p) + foo.p() + proc bar(x, y, z: int, p: proc()) = + p() + bar(a, b, c, p) + static: code() + code() From 620ed5168d74e25f94e976a7ed72756c7e46c6d2 Mon Sep 17 00:00:00 2001 From: metagn <10591326+metagn@users.noreply.github.com> Date: Sat, 15 Apr 2023 18:53:24 +0300 Subject: [PATCH 7/9] try more available check for nimsuggest --- compiler/sigmatch.nim | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 27ce95d052e42..cfb66fe47d7bc 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -2443,27 +2443,27 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var Int # early check for parameter count (nimsuggest allows partial calls) let givenCount = n.len - 1 let expectedCount = formalLen - f - when not defined(nimsuggest): - if givenCount != expectedCount and - noEagerParamCountMatch notin c.config.legacyFeatures: - # routine symbols precalculate minimum argument count in `position` field - # if there is no routine symbol, don't bother calculating - if m.callee.kind == tyProc and m.calleeSym != nil: - # if this fails just add it as an `and`: - assert m.calleeSym.kind in skProcKinds - # if this is unset, it's 0 by default, which matches everything anyway: - let minCount = m.calleeSym.position - if givenCount < minCount: - m.firstMismatch.kind = kMissingParam - a = givenCount + 1 - formal = m.callee.n[a].sym - noMatch(paramScopeOpen = false) - # no max param count for varargs - if {tfVarargs, tfHasVarargsParam} * m.callee.flags == {}: - if givenCount > expectedCount: - m.firstMismatch.kind = kExtraArg - a = expectedCount + 1 - noMatch(paramScopeOpen = false) + if givenCount != expectedCount and + noEagerParamCountMatch notin c.config.legacyFeatures and + (when defined(nimsuggest): c.config.ideCmd notin {ideSug, ideCon} else: true): + # routine symbols precalculate minimum argument count in `position` field + # if there is no routine symbol, don't bother calculating + if m.callee.kind == tyProc and m.calleeSym != nil: + # if this fails just add it as an `and`: + assert m.calleeSym.kind in skProcKinds + # if this is unset, it's 0 by default, which matches everything anyway: + let minCount = m.calleeSym.position + if givenCount < minCount: + m.firstMismatch.kind = kMissingParam + a = givenCount + 1 + formal = m.callee.n[a].sym + noMatch(paramScopeOpen = false) + # no max param count for varargs + if {tfVarargs, tfHasVarargsParam} * m.callee.flags == {}: + if givenCount > expectedCount: + m.firstMismatch.kind = kExtraArg + a = expectedCount + 1 + noMatch(paramScopeOpen = false) while a < n.len: c.openShadowScope From ce184ce891f671ea8a2bd20e99d19496f6699e3d Mon Sep 17 00:00:00 2001 From: metagn <10591326+metagn@users.noreply.github.com> Date: Sat, 15 Apr 2023 19:28:57 +0300 Subject: [PATCH 8/9] hopefully fix tvmmisc? worked for me before --- compiler/sigmatch.nim | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index cfb66fe47d7bc..d3f4a6dca7166 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -2448,9 +2448,8 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var Int (when defined(nimsuggest): c.config.ideCmd notin {ideSug, ideCon} else: true): # routine symbols precalculate minimum argument count in `position` field # if there is no routine symbol, don't bother calculating - if m.callee.kind == tyProc and m.calleeSym != nil: - # if this fails just add it as an `and`: - assert m.calleeSym.kind in skProcKinds + if m.callee.kind == tyProc and m.calleeSym != nil and + m.calleeSym.kind in skProcKinds: # if this is unset, it's 0 by default, which matches everything anyway: let minCount = m.calleeSym.position if givenCount < minCount: From 5146388833dda3ff0e720efa75928abacbe88aba Mon Sep 17 00:00:00 2001 From: metagn <10591326+metagn@users.noreply.github.com> Date: Sat, 15 Apr 2023 23:16:32 +0300 Subject: [PATCH 9/9] dumb VM fix --- compiler/sigmatch.nim | 5 +++-- compiler/vm.nim | 4 +++- compiler/vmgen.nim | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index d3f4a6dca7166..cfb66fe47d7bc 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -2448,8 +2448,9 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var Int (when defined(nimsuggest): c.config.ideCmd notin {ideSug, ideCon} else: true): # routine symbols precalculate minimum argument count in `position` field # if there is no routine symbol, don't bother calculating - if m.callee.kind == tyProc and m.calleeSym != nil and - m.calleeSym.kind in skProcKinds: + if m.callee.kind == tyProc and m.calleeSym != nil: + # if this fails just add it as an `and`: + assert m.calleeSym.kind in skProcKinds # if this is unset, it's 0 by default, which matches everything anyway: let minCount = m.calleeSym.position if givenCount < minCount: diff --git a/compiler/vm.nim b/compiler/vm.nim index e00f0f02e16bc..2ae32d8860466 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1157,7 +1157,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = let nc = rcReg.node if nb.kind != nc.kind: discard elif (nb == nc) or (nb.kind == nkNilLit): ret = true # intentional - elif nb.kind in {nkSym, nkTupleConstr, nkClosure} and nb.typ != nil and nb.typ.kind == tyProc and sameConstant(nb, nc): + elif nb.typ != nil and nb.typ.kind == tyProc and + nb.kind in {nkSym, nkTupleConstr, nkClosure} and + sameConstant(nb, nc): ret = true # this also takes care of procvar's, represented as nkTupleConstr, e.g. (nil, nil) elif nb.kind == nkIntLit and nc.kind == nkIntLit and nb.intVal == nc.intVal: # TODO: nkPtrLit diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index aa4a83900c50c..15879d83ecca8 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -461,8 +461,8 @@ proc sameConstant*(a, b: PNode): bool = # if a.floatVal == 0.0: result = cast[uint64](a.floatVal) == cast[uint64](b.floatVal) # else: result = a.floatVal == b.floatVal of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal - of nkType, nkNilLit: result = a.typ == b.typ - of nkEmpty: result = true + of nkType: result = a.typ == b.typ + of nkEmpty, nkNilLit: result = true else: if a.len == b.len: for i in 0..