summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorzah <zahary@gmail.com>2017-03-12 10:33:49 +0200
committerAndreas Rumpf <rumpf_a@web.de>2017-03-12 09:33:49 +0100
commit1be0022e7c6a8d168918998fd27412901432075d (patch)
tree64be855cb15ffb466098e33b526799a6aa49a9c7
parent6e358e318747ecd6bea66911d6144cb7eff9d172 (diff)
downloadNim-1be0022e7c6a8d168918998fd27412901432075d.tar.gz
Fixes #5167 and related problems (#5475)
This commit returns to a bit less strict checking of the number
of macro arguments, because some old immediate macros rely on a
behavior where even the arity of the macro is not being checked.

It may be better if such macros are just declared to use varargs[expr],
but this remains for another day.
-rw-r--r--compiler/ast.nim2
-rw-r--r--compiler/evaltempl.nim5
-rw-r--r--compiler/msgs.nim6
-rw-r--r--compiler/sem.nim7
-rw-r--r--compiler/semcall.nim1
-rw-r--r--compiler/semexprs.nim2
-rw-r--r--compiler/semstmts.nim2
-rw-r--r--compiler/semtypes.nim5
-rw-r--r--compiler/sigmatch.nim1
-rw-r--r--compiler/types.nim4
-rw-r--r--tests/errmsgs/t5167_1.nim17
-rw-r--r--tests/errmsgs/t5167_2.nim12
-rw-r--r--tests/errmsgs/t5167_3.nim25
-rw-r--r--tests/errmsgs/t5167_4.nim20
-rw-r--r--tests/errmsgs/t5167_5.nim25
-rw-r--r--tests/macros/tmacro4.nim2
-rw-r--r--tests/macros/tquotewords.nim2
17 files changed, 134 insertions, 4 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 66fbe577c..9d79620b2 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -460,6 +460,8 @@ type
                       # proc foo(T: typedesc, list: seq[T]): var T
                       # proc foo(L: static[int]): array[L, int]
                       # can be attached to ranges to indicate that the range
+                      # can be attached to generic procs with free standing
+                      # type parameters: e.g. proc foo[T]()
                       # depends on unresolved static params.
     tfRetType,        # marks return types in proc (used to detect type classes
                       # used as return types for return type inference)
diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim
index 318254a80..5bd274a3e 100644
--- a/compiler/evaltempl.nim
+++ b/compiler/evaltempl.nim
@@ -80,9 +80,14 @@ proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode =
     expectedRegularParams = <s.typ.len
     givenRegularParams = totalParams - genericParams
   if givenRegularParams < 0: givenRegularParams = 0
+
   if totalParams > expectedRegularParams + genericParams:
     globalError(n.info, errWrongNumberOfArguments)
 
+  if totalParams < genericParams:
+    globalError(n.info, errMissingGenericParamsForTemplate,
+                n.renderTree)
+
   result = newNodeI(nkArgList, n.info)
   for i in 1 .. givenRegularParams:
     result.addSon n.sons[i]
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index bf9090089..eaaa0aaf3 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -64,6 +64,8 @@ type
     errVarForOutParamNeeded,
     errPureTypeMismatch, errTypeMismatch, errButExpected, errButExpectedX,
     errAmbiguousCallXYZ, errWrongNumberOfArguments,
+    errWrongNumberOfArgumentsInCall,
+    errMissingGenericParamsForTemplate,
     errXCannotBePassedToProcVar,
     errXCannotBeInParamDecl, errPragmaOnlyInHeaderOfProcX, errImplOfXNotAllowed,
     errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValueX,
@@ -108,6 +110,7 @@ type
     errCannotInferTypeOfTheLiteral,
     errCannotInferReturnType,
     errGenericLambdaNotAllowed,
+    errProcHasNoConcreteType,
     errCompilerDoesntSupportTarget,
     errUser,
     warnCannotOpenFile,
@@ -270,6 +273,8 @@ const
     errButExpectedX: "but expected \'$1\'",
     errAmbiguousCallXYZ: "ambiguous call; both $1 and $2 match for: $3",
     errWrongNumberOfArguments: "wrong number of arguments",
+    errWrongNumberOfArgumentsInCall: "wrong number of arguments in call to '$1'",
+    errMissingGenericParamsForTemplate: "'$1' has unspecified generic parameters",
     errXCannotBePassedToProcVar: "\'$1\' cannot be passed to a procvar",
     errXCannotBeInParamDecl: "$1 cannot be declared in parameter declaration",
     errPragmaOnlyInHeaderOfProcX: "pragmas are only allowed in the header of a proc; redefinition of $1",
@@ -371,6 +376,7 @@ const
     errGenericLambdaNotAllowed: "A nested proc can have generic parameters only when " &
                                 "it is used as an operand to another routine and the types " &
                                 "of the generic paramers can be inferred from the expected signature.",
+    errProcHasNoConcreteType: "'$1' doesn't have a concrete type, due to unspecified generic parameters.",
     errCompilerDoesntSupportTarget: "The current compiler \'$1\' doesn't support the requested compilation target",
     errUser: "$1",
     warnCannotOpenFile: "cannot open \'$1\'",
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 21a5c435a..e1d18e61f 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -381,6 +381,13 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
   if sym == c.p.owner:
     globalError(n.info, errRecursiveDependencyX, sym.name.s)
 
+  let genericParams = if sfImmediate in sym.flags: 0
+                      else: sym.ast[genericParamsPos].len
+  let suppliedParams = max(n.safeLen - 1, 0)
+
+  if suppliedParams < genericParams:
+    globalError(n.info, errMissingGenericParamsForTemplate, n.renderTree)
+
   #if c.evalContext == nil:
   #  c.evalContext = c.createEvalContext(emStatic)
   result = evalMacroCall(c.module, c.cache, n, nOrig, sym)
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index 98667b085..3a43c63b2 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -411,6 +411,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
     let tm = typeRel(m, formal, arg, true)
     if tm in {isNone, isConvertible}: return nil
   var newInst = generateInstance(c, s, m.bindings, n.info)
+  newInst.typ.flags.excl tfUnresolved
   markUsed(n.info, s, c.graph.usageSym)
   styleCheckUse(n.info, s)
   result = newSymNode(newInst, n.info)
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 755d44448..f1bf5d864 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -30,6 +30,8 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   #  result = errorNode(c, n)
   if result.typ != nil:
     # XXX tyGenericInst here?
+    if result.typ.kind == tyProc and tfUnresolved in result.typ.flags:
+      localError(n.info, errProcHasNoConcreteType, n.renderTree)
     if result.typ.kind == tyVar: result = newDeref(result)
   elif {efWantStmt, efAllowStmt} * flags != {}:
     result.typ = newTypeS(tyVoid, c)
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 7c6e3af6d..45b75cb3e 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -499,6 +499,8 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
         if hasEmpty(typ):
           localError(def.info, errCannotInferTypeOfTheLiteral,
                      ($typ.kind).substr(2).toLowerAscii)
+        elif typ.kind == tyProc and tfUnresolved in typ.flags:
+          localError(def.info, errProcHasNoConcreteType, def.renderTree)
     else:
       if symkind == skLet: localError(a.info, errLetNeedsInit)
 
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 83d0c83b2..7877a26a9 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -1009,8 +1009,11 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
       result.sons[0] = r
       result.n.typ = r
 
-  if genericParams != nil:
+  if genericParams != nil and genericParams.len > 0:
     for n in genericParams:
+      if {sfUsed, sfAnon} * n.sym.flags == {}:
+        result.flags.incl tfUnresolved
+
       if tfWildcard in n.sym.typ.flags:
         n.sym.kind = skType
         n.sym.typ.flags.excl tfWildcard
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index f2caab41f..587598d3e 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -1514,6 +1514,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
       if arg.sons[i].sym.kind in {skProc, skMethod, skConverter, skIterator}:
         copyCandidate(z, m)
         z.callee = arg.sons[i].typ
+        if tfUnresolved in z.callee.flags: continue
         z.calleeSym = arg.sons[i].sym
         #if arg.sons[i].sym.name.s == "cmp":
         #  ggDebug = true
diff --git a/compiler/types.nim b/compiler/types.nim
index 80fb6612d..f4ef75094 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -548,7 +548,9 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
     if prefer != preferExported:
       result.add("(" & typeToString(t.sons[0]) & ")")
   of tyProc:
-    result = if tfIterator in t.flags: "iterator (" else: "proc ("
+    result = if tfIterator in t.flags: "iterator " else: "proc "
+    if tfUnresolved in t.flags: result.add "[*missing parameters*]"
+    result.add "("
     for i in countup(1, sonsLen(t) - 1):
       if t.n != nil and i < t.n.len and t.n[i].kind == nkSym:
         add(result, t.n[i].sym.name.s)
diff --git a/tests/errmsgs/t5167_1.nim b/tests/errmsgs/t5167_1.nim
new file mode 100644
index 000000000..9f4f208a4
--- /dev/null
+++ b/tests/errmsgs/t5167_1.nim
@@ -0,0 +1,17 @@
+discard """
+errormsg: "'bar' doesn't have a concrete type, due to unspecified generic parameters."
+line: 16
+"""
+
+proc foo[T]() =
+  var y1 = foo[string]
+  var y2 = foo[T]
+
+proc bar[T]() =
+  let x = 0
+
+let good1 = foo[int]
+let good2 = bar[int]
+
+let err = bar
+
diff --git a/tests/errmsgs/t5167_2.nim b/tests/errmsgs/t5167_2.nim
new file mode 100644
index 000000000..17d96ef47
--- /dev/null
+++ b/tests/errmsgs/t5167_2.nim
@@ -0,0 +1,12 @@
+discard """
+cmd: "nim c --threads:on $file"
+errormsg: "'threadFunc' doesn't have a concrete type, due to unspecified generic parameters."
+line: 11
+"""
+
+proc threadFunc[T]() {.thread.} =
+  let x = 0
+
+var thr: Thread[void]
+thr.createThread(threadFunc)
+
diff --git a/tests/errmsgs/t5167_3.nim b/tests/errmsgs/t5167_3.nim
new file mode 100644
index 000000000..2781d3943
--- /dev/null
+++ b/tests/errmsgs/t5167_3.nim
@@ -0,0 +1,25 @@
+discard """
+cmd: "nim c --threads:on $file"
+errormsg: "type mismatch"
+line: 24
+"""
+
+type
+  TGeneric[T] = object
+    x: int
+
+proc foo1[A, B, C, D](x: proc (a: A, b: B, c: C, d: D)) =
+  echo "foo1"
+
+proc foo2(x: proc(x: int)) =
+  echo "foo2"
+
+# The goal of this test is to verify that none of the generic parameters of the
+# proc will be marked as unused. The error message should be "type mismatch" instead
+# of "'bar' doesn't have a concrete type, due to unspecified generic parameters".
+proc bar[A, B, C, D](x: A, y: seq[B], z: array[4, TGeneric[C]], r: TGeneric[D]) =
+  echo "bar"
+
+foo1[int, seq[int], array[4, TGeneric[float]], TGeneric[string]] bar
+foo2 bar
+
diff --git a/tests/errmsgs/t5167_4.nim b/tests/errmsgs/t5167_4.nim
new file mode 100644
index 000000000..3d77fae02
--- /dev/null
+++ b/tests/errmsgs/t5167_4.nim
@@ -0,0 +1,20 @@
+discard """
+errormsg: "type mismatch: got (proc [*missing parameters*](x: int) | proc (x: string){.gcsafe, locks: 0.})"
+line: 19
+"""
+
+type
+  TGeneric[T] = object
+    x: int
+
+proc foo[B](x: int) =
+  echo "foo1"
+
+proc foo(x: string) =
+  echo "foo2"
+
+proc bar(x: proc (x: int)) =
+  echo "bar"
+
+bar foo
+
diff --git a/tests/errmsgs/t5167_5.nim b/tests/errmsgs/t5167_5.nim
new file mode 100644
index 000000000..ab02f29f6
--- /dev/null
+++ b/tests/errmsgs/t5167_5.nim
@@ -0,0 +1,25 @@
+discard """
+cmd: "nim check $file"
+errormsg: "'m' has unspecified generic parameters"
+nimout: '''
+t5167_5.nim(20, 9) Error: 't' has unspecified generic parameters
+t5167_5.nim(21, 5) Error: 't' has unspecified generic parameters
+t5167_5.nim(23, 9) Error: 'm' has unspecified generic parameters
+t5167_5.nim(24, 5) Error: 'm' has unspecified generic parameters
+'''
+"""
+
+template t[B]() =
+  echo "foo1"
+
+macro m[T]: stmt = nil
+
+proc bar(x: proc (x: int)) =
+  echo "bar"
+
+let x = t
+bar t
+
+let y = m
+bar m
+
diff --git a/tests/macros/tmacro4.nim b/tests/macros/tmacro4.nim
index a56369369..fb07941a9 100644
--- a/tests/macros/tmacro4.nim
+++ b/tests/macros/tmacro4.nim
@@ -5,7 +5,7 @@ discard """
 import
   macros, strutils
 
-macro test_macro*(n: stmt): stmt {.immediate.} =
+macro test_macro*(s: string, n: stmt): stmt {.immediate.} =
   result = newNimNode(nnkStmtList)
   var ass : NimNode = newNimNode(nnkAsgn)
   add(ass, newIdentNode("str"))
diff --git a/tests/macros/tquotewords.nim b/tests/macros/tquotewords.nim
index 7a575f541..48fcafd62 100644
--- a/tests/macros/tquotewords.nim
+++ b/tests/macros/tquotewords.nim
@@ -6,7 +6,7 @@ discard """
 
 import macros
 
-macro quoteWords(n: expr): expr {.immediate.} =
+macro quoteWords(n: varargs[expr]): expr {.immediate.} =
   let n = callsite()
   result = newNimNode(nnkBracket, n)
   for i in 1..n.len-1: