summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorZahary Karadjov <zahary@gmail.com>2012-09-29 16:49:04 +0300
committerZahary Karadjov <zahary@gmail.com>2012-10-03 01:59:49 +0300
commit7e44015491d4002be3c80cb7d6797e4c63651fbe (patch)
tree6650bd361de96a9e70b75c089bf7c4521e755d9a /compiler
parentb28fcdfa93ccf132b878e7dcd26e36d48f107212 (diff)
downloadNim-7e44015491d4002be3c80cb7d6797e4c63651fbe.tar.gz
implemented return type inference
Other fixes:
* bind once is now the default for type classes as documented in the manual
* fixes an issue in template overloading (erroneous  ambiguity when different typedesc params were used)
Diffstat (limited to 'compiler')
-rwxr-xr-xcompiler/ast.nim2
-rwxr-xr-xcompiler/semexprs.nim16
-rwxr-xr-xcompiler/seminst.nim11
-rwxr-xr-xcompiler/semtypes.nim19
-rwxr-xr-xcompiler/sigmatch.nim7
-rwxr-xr-xcompiler/types.nim4
6 files changed, 41 insertions, 18 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 814784029..c6e4d8318 100755
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -350,6 +350,8 @@ type
                       # pass of semProcTypeNode performed after instantiation.
                       # this won't be needed if we don't perform this redundant
                       # second pass (stay tuned).
+    tfRetType         # marks return types in proc (used to detect type classes 
+                      # used as return types for return type inference)
     tfAll,            # type class requires all constraints to be met (default)
     tfAny,            # type class requires any constraint to be met
     tfCapturesEnv,    # whether proc really captures some environment
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 7c147e778..4608d38ef 100755
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -1048,8 +1048,20 @@ proc semAsgn(c: PContext, n: PNode): PNode =
     localError(a.info, errXCannotBeAssignedTo, 
                renderTree(a, {renderNoComments}))
   else:
-    n.sons[1] = semExprWithType(c, n.sons[1])
-    n.sons[1] = fitNode(c, le, n.sons[1])
+    var 
+      rhs = semExprWithType(c, n.sons[1])
+      lhs = n.sons[0]
+    if lhs.kind == nkSym and lhs.sym.kind == skResult and
+       lhs.sym.typ.kind == tyGenericParam:
+      if matchTypeClass(lhs.typ, rhs.typ):
+        InternalAssert c.p.resultSym != nil
+        lhs.typ = rhs.typ
+        c.p.resultSym.typ = rhs.typ
+        c.p.owner.typ.sons[0] = rhs.typ
+      else:
+        typeMismatch(n, lhs.typ, rhs.typ)
+
+    n.sons[1] = fitNode(c, le, rhs)
     fixAbstractType(c, n)
     asgnToResultVar(c, n, n.sons[0], n.sons[1])
   result = n
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index 61210c0f8..8e164531a 100755
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -25,8 +25,13 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
     s.flags = s.flags + {sfUsed, sfFromGeneric}
     var t = PType(IdTableGet(pt, q.typ))
     if t == nil:
-      LocalError(a.info, errCannotInstantiateX, s.name.s)
-      t = errorType(c)
+      if tfRetType in q.typ.flags:
+        # keep the generic type and allow the return type to be bound 
+        # later by semAsgn in return type inference scenario
+        t = q.typ
+      else:
+        LocalError(a.info, errCannotInstantiateX, s.name.s)
+        t = errorType(c)
     elif t.kind == tyGenericParam: 
       InternalError(a.info, "instantiateGenericParamList: " & q.name.s)
     elif t.kind == tyGenericInvokation:
@@ -163,7 +168,6 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
     result.typ = newTypeS(tyProc, c)
     rawAddSon(result.typ, nil)
   result.typ.callConv = fn.typ.callConv
-  ParamsTypeCheck(c, result.typ)
   var oldPrc = GenericCacheGet(c, entry)
   if oldPrc == nil:
     c.generics.generics.add(entry)
@@ -174,6 +178,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
     if fn.kind != skTemplate:
       instantiateBody(c, n, result)
       sideEffectsCheck(c, result)
+    ParamsTypeCheck(c, result.typ)
   else:
     result = oldPrc
   popInfoContext()
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 5362d6d4a..eeb48a647 100755
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -584,22 +584,20 @@ proc paramTypeClass(c: PContext, paramType: PType, procKind: TSymKind):
       result.typ = newTypeS(tyTypeDesc, c)
       result.typ.sons = paramType.sons
   of tyDistinct:
-    # type T1 = distinct expr
-    # type S1 = distinct Sortable
-    # proc x(a, b: T1, c, d: S1)
-    # This forces bindOnce behavior for the type class, equivalent to
-    # proc x[T, S](a, b: T, c, d: S)
     result = paramTypeClass(c, paramType.lastSon, procKind)
-    result.id = paramType.sym.name
+    # disable the bindOnce behavior for the type class
+    result.id = nil
+    return
   of tyGenericBody:
     # type Foo[T] = object
     # proc x(a: Foo, b: Foo) 
     result.typ = newTypeS(tyTypeClass, c)
     result.typ.addSonSkipIntLit(paramType)
-    result.id = paramType.sym.name # bindOnce by default
   of tyTypeClass:
     result.typ = copyType(paramType, getCurrOwner(), false)
   else: nil
+  # bindOnce by default
+  if paramType.sym != nil: result.id = paramType.sym.name
 
 proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
                    paramType: PType, paramName: string,
@@ -619,7 +617,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
       let s = SymtabGet(c.tab, paramTypId)
       # tests/run/tinterf triggers this:
       if s != nil: result = s.typ
-      else: 
+      else:
         LocalError(info, errCannotInstantiateX, paramName)
         result = errorType(c)
     else:
@@ -684,8 +682,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
     if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue
     for j in countup(0, length-3): 
       var arg = newSymG(skParam, a.sons[j], c)
-      var finalType = liftParamType(c, kind, genericParams, typ, arg.name.s,
-                                    arg.info).skipIntLit
+      var finalType = liftParamType(c, kind, genericParams, typ,
+                                    arg.name.s, arg.info).skipIntLit
       arg.typ = finalType
       arg.position = counter
       inc(counter)
@@ -703,6 +701,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
     if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
       if r.sym == nil or sfAnon notin r.sym.flags:
         r = liftParamType(c, kind, genericParams, r, "result", n.sons[0].info)
+        r.flags.incl tfRetType
       result.sons[0] = skipIntLit(r)
       res.typ = result.sons[0]
 
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 7e482b3d2..82a8c9399 100755
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -282,7 +282,12 @@ proc matchTypeClass(c: var TCandidate, typeClass, t: PType): TTypeRelation =
   # if the loop finished without returning, either all constraints matched
   # or none of them matched.
   result = if tfAny in typeClass.flags: isNone else: isGeneric
-  
+
+proc matchTypeClass*(typeClass, typ: PType): bool =
+  var c: TCandidate
+  InitCandidate(c, typeClass)
+  result = matchTypeClass(c, typeClass, typ) == isGeneric
+
 proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
   proc inconsistentVarTypes(f, a: PType): bool {.inline.} =
     result = f.kind != a.kind and (f.kind == tyVar or a.kind == tyVar)
diff --git a/compiler/types.nim b/compiler/types.nim
index d8879f1b4..b650b49b8 100755
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -626,9 +626,9 @@ proc SameTypeOrNil*(a, b: PType, flags: TTypeCmpFlags = {}): bool =
       var c = initSameTypeClosure()
       c.flags = flags
       result = SameTypeAux(a, b, c)
-  
+
 proc equalParam(a, b: PSym): TParamsEquality = 
-  if SameTypeOrNil(a.typ, b.typ): 
+  if SameTypeOrNil(a.typ, b.typ, {TypeDescExactMatch}): 
     if a.ast == b.ast: 
       result = paramsEqual
     elif a.ast != nil and b.ast != nil: