summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/msgs.nim4
-rw-r--r--compiler/semstmts.nim24
-rw-r--r--compiler/sigmatch.nim53
-rw-r--r--tests/generics/tmetafield.nim18
4 files changed, 74 insertions, 25 deletions
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 61336aa87..268205361 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -88,7 +88,8 @@ type
     errTemplateInstantiationTooNested, errInstantiationFrom, 
     errInvalidIndexValueForTuple, errCommandExpectsFilename,
     errMainModuleMustBeSpecified,
-    errXExpected, 
+    errXExpected,
+    errTIsNotAConcreteType,
     errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError, 
     errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile, 
     errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitely,
@@ -312,6 +313,7 @@ const
     errCommandExpectsFilename: "command expects a filename argument",
     errMainModuleMustBeSpecified: "please, specify a main module in the project configuration file",
     errXExpected: "\'$1\' expected", 
+    errTIsNotAConcreteType: "\'$1\' is not a concrete type.",
     errInvalidSectionStart: "invalid section start",
     errGridTableNotImplemented: "grid table is not implemented", 
     errGeneralParseError: "general parse error",
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 0871b7fb7..e592b1e81 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -764,6 +764,28 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
       s.ast = a
       popOwner()
 
+proc checkForMetaFields(n: PNode) =
+  template checkMeta(t) =
+    if t.isMetaType and tfGenericTypeParam notin t.flags:
+      localError(n.info, errTIsNotAConcreteType, t.typeToString)
+  
+  case n.kind
+  of nkRecList, nkRecCase:
+    for s in n: checkForMetaFields(s)
+  of nkOfBranch, nkElse:
+    checkForMetaFields(n.lastSon)
+  of nkSym:
+    let t = n.sym.typ
+    case t.kind
+    of tySequence, tySet, tyArray, tyOpenArray, tyVar, tyPtr, tyRef,
+       tyProc, tyGenericInvokation, tyGenericInst:
+      for s in t.sons:
+        checkMeta(s)
+    else:
+      checkMeta(t)
+  else:
+    internalAssert false
+
 proc typeSectionFinalPass(c: PContext, n: PNode) = 
   for i in countup(0, sonsLen(n) - 1): 
     var a = n.sons[i]
@@ -780,6 +802,8 @@ proc typeSectionFinalPass(c: PContext, n: PNode) =
           assignType(s.typ, t)
           s.typ.id = t.id     # same id
       checkConstructedType(s.info, s.typ)
+      if s.typ.kind in {tyObject, tyTuple}:
+        checkForMetaFields(s.typ.n)
     let aa = a.sons[2]
     if aa.kind in {nkRefTy, nkPtrTy} and aa.len == 1 and
        aa.sons[0].kind == nkObjectTy:
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index fce0bdf48..8361d4681 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -343,53 +343,57 @@ proc allowsNil(f: PType): TTypeRelation {.inline.} =
 proc inconsistentVarTypes(f, a: PType): bool {.inline.} =
   result = f.kind != a.kind and (f.kind == tyVar or a.kind == tyVar)
 
-proc procParamTypeRel(c: var TCandidate, f, a: PType,
-                      result: var TTypeRelation) =
-  var
-    m: TTypeRelation
-    f = f
-    
+proc procParamTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
+  var f = f
+
   if a.isMetaType:
     if f.isMetaType:
-      # we are matching a generic proc (as proc param)
+      # We are matching a generic proc (as proc param)
       # to another generic type appearing in the proc
-      # sigunature. there is a change that the target
+      # signature. There is a change that the target
       # type is already fully-determined, so we are 
       # going to try resolve it
       f = generateTypeInstance(c.c, c.bindings, c.call.info, f)
       if f == nil or f.isMetaType:
         # no luck resolving the type, so the inference fails
-        result = isNone
-        return
+        return isNone
     let reverseRel = typeRel(c, a, f)
     if reverseRel == isGeneric:
-      m = isInferred
+      result = isInferred
+      inc c.genericMatches
   else:
-    m = typeRel(c, f, a)
+    result = typeRel(c, f, a)
 
-  if m <= isSubtype or inconsistentVarTypes(f, a):
+  if result <= isSubtype or inconsistentVarTypes(f, a):
     result = isNone
-    return
-  else:
-    result = minRel(m, result)
-
+ 
+  if result == isEqual:
+    inc c.exactMatches
+    
 proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
   case a.kind
   of tyProc:
     if sonsLen(f) != sonsLen(a): return
-    # Note: We have to do unification for the parameters before the
-    # return type!
     result = isEqual      # start with maximum; also correct for no
                           # params at all
-    for i in countup(1, sonsLen(f)-1):
-      procParamTypeRel(c, f.sons[i], a.sons[i], result)
+    
+    template checkParam(f, a) =
+      result = minRel(result, procParamTypeRel(c, f, a))
+      if result == isNone: return
+
+    # Note: We have to do unification for the parameters before the
+    # return type!
+    for i in 1 .. <f.sonsLen:
+      checkParam(f.sons[i], a.sons[i])
+    
     if f.sons[0] != nil:
       if a.sons[0] != nil:
-        procParamTypeRel(c, f.sons[0], a.sons[0], result)
+        checkParam(f.sons[0], a.sons[0])
       else:
         return isNone
     elif a.sons[0] != nil:
       return isNone
+
     if tfNoSideEffect in f.flags and tfNoSideEffect notin a.flags:
       return isNone
     elif tfThread in f.flags and a.flags * {tfThread, tfNoSideEffect} == {}:
@@ -1101,6 +1105,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
     # incorrect to simply use the first fitting match. However, to implement
     # this correctly is inefficient. We have to copy `m` here to be able to
     # roll back the side effects of the unification algorithm.
+
     let c = m.c
     var x, y, z: TCandidate
     initCandidate(c, x, m.callee)
@@ -1122,10 +1127,10 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
             x.state = csMatch
           of csMatch: 
             var cmp = cmpCandidates(x, z)
-            if cmp < 0: 
+            if cmp < 0:
               best = i
               x = z
-            elif cmp == 0: 
+            elif cmp == 0:
               y = z           # z is as good as x
     if x.state == csEmpty: 
       result = nil
diff --git a/tests/generics/tmetafield.nim b/tests/generics/tmetafield.nim
new file mode 100644
index 000000000..5d2ec9b33
--- /dev/null
+++ b/tests/generics/tmetafield.nim
@@ -0,0 +1,18 @@
+discard """
+  cmd: "nimrod check $# $#"
+  msg: "'proc' is not a concrete type"
+  msg: "'seq[Foo]' is not a concrete type."
+  msg: "invalid type: 'TBaseMed'"
+"""
+
+type
+  Foo[T] = object
+    x: T
+
+  TBaseMed =  object
+    doSmth: proc
+    data: seq[Foo]
+
+var a: TBaseMed
+
+# issue 188