summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorZahary Karadjov <zahary@gmail.com>2013-08-15 22:55:11 +0300
committerZahary Karadjov <zahary@gmail.com>2013-08-19 01:48:25 +0300
commitca3a4ce6721c87cfcbb9eb02002ecf8aeb89233c (patch)
tree76a5fd56fc4ae9cd459d4703c3287b9a088aecb2
parent4980ef85e254178747dc8ea9fd59b058d33b2df1 (diff)
downloadNim-ca3a4ce6721c87cfcbb9eb02002ecf8aeb89233c.tar.gz
hacky fix for generic constraints matching
-rw-r--r--compiler/ccgexprs.nim4
-rw-r--r--compiler/cgen.nim4
-rw-r--r--compiler/seminst.nim2
-rw-r--r--compiler/sigmatch.nim23
-rw-r--r--compiler/types.nim10
-rw-r--r--tests/reject/tgenconstraints.nim30
-rw-r--r--tests/run/tfieldindex.nim2
-rw-r--r--tests/run/tfinally.nim10
8 files changed, 68 insertions, 17 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index bb1035ab6..635756220 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -1932,12 +1932,12 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
     nil
   of nkPragma: genPragma(p, n)
   of nkProcDef, nkMethodDef, nkConverterDef: 
-    if (n.sons[genericParamsPos].kind == nkEmpty): 
+    if (n.sons[genericParamsPos].kind == nkEmpty):
       var prc = n.sons[namePos].sym
       # due to a bug/limitation in the lambda lifting, unused inner procs
       # are not transformed correctly. We work around this issue (#411) here
       # by ensuring it's no inner proc (owner is a module):
-      if prc.owner.kind == skModule:
+      if prc.skipGenericOwner.kind == skModule:
         if (optDeadCodeElim notin gGlobalOptions and
             sfDeadCodeElim notin getModule(prc).flags) or
             ({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 787a2143f..0c3f2da84 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -861,8 +861,8 @@ proc isActivated(prc: PSym): bool = prc.typ != nil
 proc genProc(m: BModule, prc: PSym) = 
   if sfBorrow in prc.flags or not isActivated(prc): return
   fillProcLoc(prc)
-  if {sfForward, sfFromGeneric} * prc.flags != {}: addForwardedProc(m, prc)
-  else: 
+  if sfForward in prc.flags: addForwardedProc(m, prc)
+  else:
     genProcNoForward(m, prc)
     if {sfExportc, sfCompilerProc} * prc.flags == {sfExportc} and
         generatedHeader != nil and lfNoDecl notin prc.loc.Flags:
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index 47d889a60..601072833 100644
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -87,6 +87,7 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind)
 
 proc instantiateBody(c: PContext, n: PNode, result: PSym) =
   if n.sons[bodyPos].kind != nkEmpty:
+    inc c.InGenericInst
     # add it here, so that recursive generic procs are possible:
     addDecl(c, result)
     pushProcCon(c, result)
@@ -107,6 +108,7 @@ proc instantiateBody(c: PContext, n: PNode, result: PSym) =
     #echo "code instantiated ", result.name.s
     excl(result.flags, sfForward)
     popProcCon(c)
+    dec c.InGenericInst
 
 proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
   for i in countup(0, c.generics.len - 1):
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 41268d6d0..626d16d64 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -38,6 +38,7 @@ type
     proxyMatch*: bool        # to prevent instantiations
     genericConverter*: bool  # true if a generic converter needs to
                              # be instantiated
+    typedescMatched: bool
     inheritancePenalty: int  # to prefer closest father object type
   
   TTypeRelation* = enum      # order is important!
@@ -499,8 +500,11 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
   of tyOrdinal:
     if isOrdinalType(a):
       var x = if a.kind == tyOrdinal: a.sons[0] else: a
+      
       result = typeRel(c, f.sons[0], x)
       if result < isGeneric: result = isNone
+    elif a.kind == tyGenericParam:
+      result = isGeneric
   of tyForward: InternalError("forward type in typeRel()")
   of tyNil:
     if a.kind == f.kind: result = isEqual
@@ -618,7 +622,24 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
   of tyGenericParam, tyTypeClass:
     var x = PType(idTableGet(c.bindings, f))
     if x == nil:
-      result = matchTypeClass(c, f, a)
+      if c.calleeSym.kind == skType and f.kind == tyGenericParam and not c.typedescMatched:
+        # XXX: The fact that generic types currently use tyGenericParam for 
+        # their parameters is really a misnomer. tyGenericParam means "match
+        # any value" and what we need is "match any type", which can be encoded
+        # by a tyTypeDesc params. Unfortunately, this requires more substantial
+        # changes in semtypinst and elsewhere.
+        if a.kind == tyTypeDesc:
+          if f.sons == nil or f.sons.len == 0:
+            result = isGeneric
+          else:
+            InternalAssert a.sons != nil and a.sons.len > 0
+            c.typedescMatched = true
+            result = typeRel(c, f.sons[0], a.sons[0])
+        else:
+          result = isNone
+      else:
+        result = matchTypeClass(c, f, a)
+        
       if result == isGeneric:
         var concrete = concreteType(c, a)
         if concrete == nil:
diff --git a/compiler/types.nim b/compiler/types.nim
index b8aaed45e..2564741d8 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -969,8 +969,8 @@ proc skipGenericAlias*(t: PType): PType =
 proc matchTypeClass*(bindings: var TIdTable, typeClass, t: PType): bool =
   for i in countup(0, typeClass.sonsLen - 1):
     let req = typeClass.sons[i]
-    var match = req.kind == skipTypes(t, {tyGenericInst, tyRange}).kind or
-                req.kind == skipTypes(t, {tyGenericInst}).kind
+    var match = req.kind == skipTypes(t, {tyRange, tyGenericInst}).kind
+
     if not match:
       case req.kind
       of tyGenericBody:
@@ -979,7 +979,9 @@ proc matchTypeClass*(bindings: var TIdTable, typeClass, t: PType): bool =
           IdTablePut(bindings, typeClass, t)
       of tyTypeClass:
         match = matchTypeClass(bindings, req, t)
-      else: nil
+      elif t.kind == tyTypeClass:
+        match = matchTypeClass(bindings, t, req)
+          
     elif t.kind in {tyObject} and req.len != 0:
       # empty 'object' is fine as constraint in a type class
       match = sameType(t, req)
@@ -1046,7 +1048,7 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind,
     result = typeAllowedAux(marker, lastSon(t), kind, flags)
   of tyRange: 
     result = skipTypes(t.sons[0], abstractInst-{tyTypeDesc}).kind in
-        {tyChar, tyEnum, tyInt..tyUInt64}
+        {tyChar, tyEnum, tyInt..tyFloat128}
   of tyOpenArray, tyVarargs: 
     result = (kind == skParam) and typeAllowedAux(marker, t.sons[0], skVar, flags)
   of tySequence: 
diff --git a/tests/reject/tgenconstraints.nim b/tests/reject/tgenconstraints.nim
new file mode 100644
index 000000000..e32aa877b
--- /dev/null
+++ b/tests/reject/tgenconstraints.nim
@@ -0,0 +1,30 @@
+discard """
+  file: "tgenconstraints.nim"
+  line: 25
+  errormsg: "cannot instantiate T2"
+"""
+
+type
+  T1[T: int|string] = object
+    x: T
+
+  T2[T: Ordinal] = object
+    x: T
+
+var x1: T1[int]
+var x2: T1[string]
+var x3: T2[int]
+
+proc foo[T](x: T): T2[T] {.discardable.} =
+  var o: T1[T]
+
+foo(10)
+
+proc bar(x: string|TNumber): T1[type(x)] {.discardable.} =
+  when type(x) is TNumber:
+    var o: T2[type(x)]
+
+bar "test"
+bar 100
+bar 1.1
+
diff --git a/tests/run/tfieldindex.nim b/tests/run/tfieldindex.nim
index 3ffa65e58..f0674af54 100644
--- a/tests/run/tfieldindex.nim
+++ b/tests/run/tfieldindex.nim
@@ -5,7 +5,7 @@ discard """
 type
   TMyTuple = tuple[a, b: int]
 
-proc indexOf*(t: typedesc, name: string): int {.compiletime.} =
+proc indexOf*(t: typedesc, name: string): int =
   ## takes a tuple and looks for the field by name.
   ## returs index of that field.
   var
diff --git a/tests/run/tfinally.nim b/tests/run/tfinally.nim
index 273aac72b..16fb3e7da 100644
--- a/tests/run/tfinally.nim
+++ b/tests/run/tfinally.nim
@@ -1,8 +1,6 @@
 discard """
   file: "tfinally.nim"
-  output: '''came
-here
-3'''
+  output: "came\nhere\n3"
 """
 # Test return in try statement:
 
@@ -14,10 +12,8 @@ proc main: int =
       echo("came")
       return 2
   finally: 
-    echo("here ")
+    echo("here")
     return 3
-    
-echo main() #OUT came here 3
-
 
+echo main() #OUT came here 3