summary refs log tree commit diff stats
path: root/rod
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2011-02-21 20:06:34 +0100
committerAraq <rumpf_a@web.de>2011-02-21 20:06:34 +0100
commitfdde4d3a9266e8a393f0303b1982a2dc9ca7ca6e (patch)
treea076ec612bb98d6dd1a8eff18505f2b3c90610f7 /rod
parent4e7a22cac31a0a703c080c7fe0d2569f56ab16a0 (diff)
downloadNim-fdde4d3a9266e8a393f0303b1982a2dc9ca7ca6e.tar.gz
refactoring: suggest can import sigmatch for type matching
Diffstat (limited to 'rod')
-rwxr-xr-xrod/astalgo.nim14
-rwxr-xr-xrod/sem.nim8
-rw-r--r--rod/semcall.nim98
-rwxr-xr-xrod/semdata.nim4
-rwxr-xr-xrod/semexprs.nim16
-rwxr-xr-xrod/seminst.nim138
-rwxr-xr-xrod/semtypes.nim2
-rw-r--r--rod/semtypinst.nim147
-rwxr-xr-xrod/sigmatch.nim121
-rw-r--r--rod/suggest.nim74
10 files changed, 356 insertions, 266 deletions
diff --git a/rod/astalgo.nim b/rod/astalgo.nim
index 9c9719b35..bb5a6cf56 100755
--- a/rod/astalgo.nim
+++ b/rod/astalgo.nim
@@ -51,16 +51,18 @@ type
   TTabIter*{.final.} = object # consider all fields here private
     h*: THash                 # current hash
   
-
 proc InitTabIter*(ti: var TTabIter, tab: TStrTable): PSym
 proc NextIter*(ti: var TTabIter, tab: TStrTable): PSym
   # usage:
-  # var i: TTabIter; s: PSym;
-  # s := InitTabIter(i, table);
-  # while s <> nil do begin
+  # var 
+  #   i: TTabIter
+  #   s: PSym
+  # s = InitTabIter(i, table)
+  # while s != nil:
   #   ...
-  #   s := NextIter(i, table);
-  # end;
+  #   s = NextIter(i, table)
+  #
+
 type 
   TIdentIter*{.final.} = object # iterator over all syms with the same identifier
     h*: THash                 # current hash
diff --git a/rod/sem.nim b/rod/sem.nim
index 0518dc423..66fc66cbe 100755
--- a/rod/sem.nim
+++ b/rod/sem.nim
@@ -13,7 +13,7 @@ import
   strutils, nhashes, lists, options, scanner, ast, astalgo, trees, treetab, 
   wordrecg, ropes, msgs, os, condsyms, idents, rnimsyn, types, platform, math, 
   magicsys, pnimsyn, nversion, nimsets, semdata, evals, semfold, importer, 
-  procfind, lookups, rodread, pragmas, passes, suggest
+  procfind, lookups, rodread, pragmas, passes, semtypinst, sigmatch, suggest
 
 proc semPass*(): TPass
 # implementation
@@ -34,10 +34,6 @@ proc isTopLevel(c: PContext): bool =
 proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym = 
   result = newSym(kind, considerAcc(n), getCurrOwner())
   result.info = n.info
-
-proc markUsed(n: PNode, s: PSym) = 
-  incl(s.flags, sfUsed)
-  if sfDeprecated in s.flags: Message(n.info, warnDeprecated, s.name.s)
   
 proc semIdentVis(c: PContext, kind: TSymKind, n: PNode, allowed: TSymFlags): PSym
   # identifier with visability
@@ -115,7 +111,7 @@ proc semMacroExpr(c: PContext, n: PNode, sym: PSym,
   if semCheck: result = semAfterMacroCall(c, result, sym)
   dec(evalTemplateCounter)
 
-include seminst, sigmatch
+include seminst, semcall
 
 proc CheckBool(t: PNode) = 
   if (t.Typ == nil) or
diff --git a/rod/semcall.nim b/rod/semcall.nim
new file mode 100644
index 000000000..1b31558ca
--- /dev/null
+++ b/rod/semcall.nim
@@ -0,0 +1,98 @@
+#
+#
+#           The Nimrod Compiler
+#        (c) Copyright 2011 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements semantic checking for calls. 
+
+proc sameMethodDispatcher(a, b: PSym): bool = 
+  result = false
+  if a.kind == skMethod and b.kind == skMethod: 
+    var aa = lastSon(a.ast)
+    var bb = lastSon(b.ast)
+    if aa.kind == nkSym and bb.kind == nkSym and aa.sym == bb.sym: 
+      result = true
+  
+proc semDirectCallWithBinding(c: PContext, n, f: PNode, filter: TSymKinds,
+                              initialBinding: PNode): PNode = 
+  var
+    o: TOverloadIter
+    x, y, z: TCandidate
+  #Message(n.info, warnUser, renderTree(n))
+  var sym = initOverloadIter(o, c, f)
+  result = nil
+  if sym == nil: return 
+  initCandidate(x, sym, initialBinding)
+  initCandidate(y, sym, initialBinding)
+
+  while sym != nil: 
+    if sym.kind in filter: 
+      initCandidate(z, sym, initialBinding)
+      z.calleeSym = sym
+      matches(c, n, z)
+      if z.state == csMatch: 
+        case x.state
+        of csEmpty, csNoMatch: x = z
+        of csMatch: 
+          var cmp = cmpCandidates(x, z)
+          if cmp < 0: x = z # z is better than x
+          elif cmp == 0: y = z # z is as good as x
+          else: nil
+    sym = nextOverloadIter(o, c, f)
+  if x.state == csEmpty: 
+    # no overloaded proc found
+    # do not generate an error yet; the semantic checking will check for
+    # an overloaded () operator
+  elif y.state == csMatch and cmpCandidates(x, y) == 0 and
+      not sameMethodDispatcher(x.calleeSym, y.calleeSym): 
+    if x.state != csMatch: 
+      InternalError(n.info, "x.state is not csMatch") 
+    LocalError(n.Info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [
+      getProcHeader(x.calleeSym), getProcHeader(y.calleeSym), 
+      x.calleeSym.Name.s])
+  else: 
+    # only one valid interpretation found:
+    markUsed(n, x.calleeSym)
+    if x.calleeSym.ast == nil: 
+      internalError(n.info, "calleeSym.ast is nil") # XXX: remove this check!
+    if x.calleeSym.ast.sons[genericParamsPos].kind != nkEmpty: 
+      # a generic proc!
+      x.calleeSym = generateInstance(c, x.calleeSym, x.bindings, n.info)
+      x.callee = x.calleeSym.typ
+    result = x.call
+    result.sons[0] = newSymNode(x.calleeSym)
+    result.typ = x.callee.sons[0]
+        
+proc semDirectCall(c: PContext, n: PNode, filter: TSymKinds): PNode = 
+  # process the bindings once:
+  var initialBinding: PNode
+  var f = n.sons[0]
+  if f.kind == nkBracketExpr:
+    # fill in the bindings:
+    initialBinding = f
+    f = f.sons[0]
+  else: 
+    initialBinding = nil
+  result = semDirectCallWithBinding(c, n, f, filter, initialBinding)
+
+proc explictGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode = 
+  assert n.kind == nkBracketExpr
+  for i in 1..sonsLen(n)-1:
+    n.sons[i].typ = semTypeNode(c, n.sons[i], nil)
+  # we cannot check for the proper number of type parameters because in
+  # `f[a,b](x, y)` `f` is not resolved yet properly.
+  # XXX: BUG this should be checked somehow!
+  assert n.sons[0].kind == nkSym
+  
+  var x: TCandidate
+  initCandidate(x, s, n)
+  var newInst = generateInstance(c, s, x.bindings, n.info)
+  
+  markUsed(n, s)
+  result = newSymNode(newInst)
+  result.info = n.info
+
diff --git a/rod/semdata.nim b/rod/semdata.nim
index 5b7425a96..702e00059 100755
--- a/rod/semdata.nim
+++ b/rod/semdata.nim
@@ -166,6 +166,10 @@ proc makeRangeType(c: PContext, first, last: biggestInt,
   result.n = n
   addSon(result, getSysType(tyInt)) # basetype of range
   
+proc markUsed*(n: PNode, s: PSym) = 
+  incl(s.flags, sfUsed)
+  if sfDeprecated in s.flags: Message(n.info, warnDeprecated, s.name.s)
+  
 proc illFormedAst*(n: PNode) = 
   GlobalError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
 
diff --git a/rod/semexprs.nim b/rod/semexprs.nim
index 58c358021..b16bf11dc 100755
--- a/rod/semexprs.nim
+++ b/rod/semexprs.nim
@@ -12,8 +12,7 @@ const
   ConstAbstractTypes = {tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128, 
     tyArrayConstr, tyTuple, tySet}
 
-proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
-                     semCheck: bool = true): PNode = 
+proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode = 
   markUsed(n, s)
   pushInfoContext(n.info)
   result = evalTemplate(c, n, s)
@@ -122,9 +121,9 @@ proc checkConvertible(info: TLineInfo, castDest, src: PType) =
 
 proc isCastable(dst, src: PType): bool = 
   #const
-  #  castableTypeKinds = {@set}[tyInt, tyPtr, tyRef, tyCstring, tyString, 
-  #                             tySequence, tyPointer, tyNil, tyOpenArray,
-  #                             tyProc, tySet, tyEnum, tyBool, tyChar];
+  #  castableTypeKinds = {tyInt, tyPtr, tyRef, tyCstring, tyString, 
+  #                       tySequence, tyPointer, tyNil, tyOpenArray,
+  #                       tyProc, tySet, tyEnum, tyBool, tyChar}
   var ds, ss: biggestInt
   # this is very unrestrictive; cast is allowed if castDest.size >= src.size
   ds = computeSize(dst)
@@ -232,7 +231,8 @@ proc overloadedCallOpr(c: PContext, n: PNode): PNode =
 proc changeType(n: PNode, newType: PType) = 
   case n.kind
   of nkCurly, nkBracket: 
-    for i in countup(0, sonsLen(n) - 1): changeType(n.sons[i], elemType(newType))
+    for i in countup(0, sonsLen(n) - 1): 
+      changeType(n.sons[i], elemType(newType))
   of nkPar: 
     if newType.kind != tyTuple: 
       InternalError(n.info, "changeType: no tuple type for constructor")
@@ -350,8 +350,6 @@ proc isAssignable(n: PNode): TAssignableResult =
       result = isAssignable(n.sons[0])
   of nkHiddenStdConv, nkHiddenSubConv, nkConv: 
     # Object and tuple conversions are still addressable, so we skip them
-    #if skipPtrsGeneric(n.sons[1].typ).kind in [tyOpenArray,
-    #                                           tyTuple, tyObject] then
     if skipTypes(n.typ, abstractPtrs).kind in {tyOpenArray, tyTuple, tyObject}: 
       result = isAssignable(n.sons[1])
   of nkHiddenDeref, nkDerefExpr: 
@@ -643,6 +641,8 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
 
   checkSonsLen(n, 2)
   n.sons[0] = semExprWithType(c, n.sons[0], {efAllowType} + flags)
+  if gCmd == cmdSuggest: 
+    suggestFieldAccess(c, n.sons[0])
   var i = considerAcc(n.sons[1])
   var ty = n.sons[0].Typ
   var f: PSym = nil
diff --git a/rod/seminst.nim b/rod/seminst.nim
index f2acdba60..d32aff15e 100755
--- a/rod/seminst.nim
+++ b/rod/seminst.nim
@@ -7,35 +7,11 @@
 #    distribution, for details about the copyright.
 #
 
-# This module does the instantiation of generic procs and types.
+# This module does the instantiation of generic procs.
 
 proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
                       info: TLineInfo): PSym
   # generates an instantiated proc
-proc searchInstTypes(tab: TIdTable, key: PType): PType = 
-  # returns nil if we need to declare this type
-  result = PType(IdTableGet(tab, key))
-  if (result == nil) and (tab.counter > 0): 
-    # we have to do a slow linear search because types may need
-    # to be compared by their structure:
-    for h in countup(0, high(tab.data)): 
-      var t = PType(tab.data[h].key)
-      if t != nil: 
-        if key.containerId == t.containerID: 
-          var match = true
-          for j in countup(0, sonsLen(t) - 1): 
-            # XXX sameType is not really correct for nested generics?
-            if not sameType(t.sons[j], key.sons[j]): 
-              match = false
-              break 
-          if match: 
-            return PType(tab.data[h].val)
-
-proc containsGenericTypeIter(t: PType, closure: PObject): bool = 
-  result = t.kind in GenericTypes
-
-proc containsGenericType(t: PType): bool = 
-  result = iterOverType(t, containsGenericTypeIter, nil)
 
 proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable) = 
   if (n.kind != nkGenericParams): 
@@ -129,106 +105,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
   c.p = oldP                  # restore
   c.module = oldMod
   dec(c.InstCounter)
-
-proc checkConstructedType(info: TLineInfo, t: PType) = 
-  if (tfAcyclic in t.flags) and (skipTypes(t, abstractInst).kind != tyObject): 
-    LocalError(info, errInvalidPragmaX, "acyclic")
-  elif computeSize(t) < 0: 
-    LocalError(info, errIllegalRecursionInTypeX, typeToString(t))
-  elif (t.kind == tyVar) and (t.sons[0].kind == tyVar): 
-    LocalError(info, errVarVarTypeNotAllowed)
-  
-type 
-  TReplTypeVars{.final.} = object 
-    c*: PContext
-    typeMap*: TIdTable        # map PType to PType
-    symMap*: TIdTable         # map PSym to PSym
-    info*: TLineInfo
-
-
-proc ReplaceTypeVarsT(cl: var TReplTypeVars, t: PType): PType
-proc ReplaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym
-proc ReplaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode = 
-  if n != nil: 
-    result = copyNode(n)
-    result.typ = ReplaceTypeVarsT(cl, n.typ)
-    case n.kind
-    of nkNone..pred(nkSym), succ(nkSym)..nkNilLit: 
-      nil
-    of nkSym: 
-      result.sym = ReplaceTypeVarsS(cl, n.sym)
-    else: 
-      var length = sonsLen(n)
-      if length > 0: 
-        newSons(result, length)
-        for i in countup(0, length - 1): 
-          result.sons[i] = ReplaceTypeVarsN(cl, n.sons[i])
-  
-proc ReplaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym = 
-  if s == nil: return nil
-  result = PSym(idTableGet(cl.symMap, s))
-  if result == nil: 
-    result = copySym(s, false)
-    incl(result.flags, sfFromGeneric)
-    idTablePut(cl.symMap, s, result)
-    result.typ = ReplaceTypeVarsT(cl, s.typ)
-    result.owner = s.owner
-    result.ast = ReplaceTypeVarsN(cl, s.ast)
-
-proc lookupTypeVar(cl: TReplTypeVars, t: PType): PType = 
-  result = PType(idTableGet(cl.typeMap, t))
-  if result == nil: 
-    GlobalError(t.sym.info, errCannotInstantiateX, typeToString(t))
-  elif result.kind == tyGenericParam: 
-    InternalError(cl.info, "substitution with generic parameter")
-  
-proc ReplaceTypeVarsT(cl: var TReplTypeVars, t: PType): PType = 
-  var body, newbody, x, header: PType
-  result = t
-  if t == nil: return 
-  case t.kind
-  of tyGenericParam: 
-    result = lookupTypeVar(cl, t)
-  of tyGenericInvokation: 
-    body = t.sons[0]
-    if body.kind != tyGenericBody: InternalError(cl.info, "no generic body")
-    header = nil
-    for i in countup(1, sonsLen(t) - 1): 
-      if t.sons[i].kind == tyGenericParam: 
-        x = lookupTypeVar(cl, t.sons[i])
-        if header == nil: header = copyType(t, t.owner, false)
-        header.sons[i] = x
-      else: 
-        x = t.sons[i]
-      idTablePut(cl.typeMap, body.sons[i - 1], x)
-    if header == nil: header = t
-    result = searchInstTypes(gInstTypes, header)
-    if result != nil: return 
-    result = newType(tyGenericInst, t.sons[0].owner)
-    for i in countup(0, sonsLen(t) - 1): 
-      # if one of the params is not concrete, we cannot do anything
-      # but we already raised an error!
-      addSon(result, header.sons[i])
-    idTablePut(gInstTypes, header, result)
-    newbody = ReplaceTypeVarsT(cl, lastSon(body))
-    newbody.n = ReplaceTypeVarsN(cl, lastSon(body).n)
-    addSon(result, newbody)   
-    #writeln(output, ropeToStr(Typetoyaml(newbody)));
-    checkConstructedType(cl.info, newbody)
-  of tyGenericBody: 
-    InternalError(cl.info, "ReplaceTypeVarsT: tyGenericBody")
-    result = ReplaceTypeVarsT(cl, lastSon(t))
-  else: 
-    if containsGenericType(t): 
-      result = copyType(t, t.owner, false)
-      for i in countup(0, sonsLen(result) - 1): 
-        result.sons[i] = ReplaceTypeVarsT(cl, result.sons[i])
-      result.n = ReplaceTypeVarsN(cl, result.n)
-      if result.Kind in GenericTypes: 
-        LocalError(cl.info, errCannotInstantiateX, TypeToString(t, preferName))
-        #writeln(output, ropeToStr(Typetoyaml(result)))
-        #checkConstructedType(cl.info, result)
-  
+    
 proc instGenericContainer(c: PContext, n: PNode, header: PType): PType = 
   var cl: TReplTypeVars
   InitIdTable(cl.symMap)
@@ -237,14 +114,3 @@ proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
   cl.c = c
   result = ReplaceTypeVarsT(cl, header)
 
-proc generateTypeInstance(p: PContext, pt: TIdTable, arg: PNode, 
-                          t: PType): PType = 
-  var cl: TReplTypeVars
-  InitIdTable(cl.symMap)
-  copyIdTable(cl.typeMap, pt)
-  cl.info = arg.info
-  cl.c = p
-  pushInfoContext(arg.info)
-  result = ReplaceTypeVarsT(cl, t)
-  popInfoContext()
-
diff --git a/rod/semtypes.nim b/rod/semtypes.nim
index 08c64384e..e6aab393b 100755
--- a/rod/semtypes.nim
+++ b/rod/semtypes.nim
@@ -245,7 +245,7 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
       elif (sfMinus in allowed) and (v.id == ord(wMinus)): 
         incl(result.flags, sfMinus)
       else: 
-        GlobalError(n.sons[0].info, errInvalidVisibilityX, v.s)
+        LocalError(n.sons[0].info, errInvalidVisibilityX, v.s)
     else: 
       illFormedAst(n)
   else: 
diff --git a/rod/semtypinst.nim b/rod/semtypinst.nim
new file mode 100644
index 000000000..6427d7858
--- /dev/null
+++ b/rod/semtypinst.nim
@@ -0,0 +1,147 @@
+#
+#
+#           The Nimrod Compiler
+#        (c) Copyright 2011 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This module does the instantiation of generic procs and types.
+
+import ast, astalgo, msgs, types, semdata
+
+proc checkConstructedType*(info: TLineInfo, t: PType) = 
+  if (tfAcyclic in t.flags) and (skipTypes(t, abstractInst).kind != tyObject): 
+    LocalError(info, errInvalidPragmaX, "acyclic")
+  elif computeSize(t) < 0: 
+    LocalError(info, errIllegalRecursionInTypeX, typeToString(t))
+  elif (t.kind == tyVar) and (t.sons[0].kind == tyVar): 
+    LocalError(info, errVarVarTypeNotAllowed)
+
+proc containsGenericTypeIter(t: PType, closure: PObject): bool = 
+  result = t.kind in GenericTypes
+
+proc containsGenericType*(t: PType): bool = 
+  result = iterOverType(t, containsGenericTypeIter, nil)
+
+proc searchInstTypes(tab: TIdTable, key: PType): PType = 
+  # returns nil if we need to declare this type
+  result = PType(IdTableGet(tab, key))
+  if (result == nil) and (tab.counter > 0): 
+    # we have to do a slow linear search because types may need
+    # to be compared by their structure:
+    for h in countup(0, high(tab.data)): 
+      var t = PType(tab.data[h].key)
+      if t != nil: 
+        if key.containerId == t.containerID: 
+          var match = true
+          for j in countup(0, sonsLen(t) - 1): 
+            # XXX sameType is not really correct for nested generics?
+            if not sameType(t.sons[j], key.sons[j]): 
+              match = false
+              break 
+          if match: 
+            return PType(tab.data[h].val)
+
+type
+  TReplTypeVars* {.final.} = object 
+    c*: PContext
+    typeMap*: TIdTable        # map PType to PType
+    symMap*: TIdTable         # map PSym to PSym
+    info*: TLineInfo
+
+proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType
+proc ReplaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym
+proc ReplaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode = 
+  if n != nil: 
+    result = copyNode(n)
+    result.typ = ReplaceTypeVarsT(cl, n.typ)
+    case n.kind
+    of nkNone..pred(nkSym), succ(nkSym)..nkNilLit: 
+      nil
+    of nkSym: 
+      result.sym = ReplaceTypeVarsS(cl, n.sym)
+    else: 
+      var length = sonsLen(n)
+      if length > 0: 
+        newSons(result, length)
+        for i in countup(0, length - 1): 
+          result.sons[i] = ReplaceTypeVarsN(cl, n.sons[i])
+  
+proc ReplaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym = 
+  if s == nil: return nil
+  result = PSym(idTableGet(cl.symMap, s))
+  if result == nil: 
+    result = copySym(s, false)
+    incl(result.flags, sfFromGeneric)
+    idTablePut(cl.symMap, s, result)
+    result.typ = ReplaceTypeVarsT(cl, s.typ)
+    result.owner = s.owner
+    result.ast = ReplaceTypeVarsN(cl, s.ast)
+
+proc lookupTypeVar(cl: TReplTypeVars, t: PType): PType = 
+  result = PType(idTableGet(cl.typeMap, t))
+  if result == nil: 
+    GlobalError(t.sym.info, errCannotInstantiateX, typeToString(t))
+  elif result.kind == tyGenericParam: 
+    InternalError(cl.info, "substitution with generic parameter")
+  
+proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType = 
+  var body, newbody, x, header: PType
+  result = t
+  if t == nil: return 
+  case t.kind
+  of tyGenericParam: 
+    result = lookupTypeVar(cl, t)
+  of tyGenericInvokation: 
+    body = t.sons[0]
+    if body.kind != tyGenericBody: InternalError(cl.info, "no generic body")
+    header = nil
+    for i in countup(1, sonsLen(t) - 1): 
+      if t.sons[i].kind == tyGenericParam: 
+        x = lookupTypeVar(cl, t.sons[i])
+        if header == nil: header = copyType(t, t.owner, false)
+        header.sons[i] = x
+      else: 
+        x = t.sons[i]
+      idTablePut(cl.typeMap, body.sons[i - 1], x)
+    if header == nil: header = t
+    result = searchInstTypes(gInstTypes, header)
+    if result != nil: return 
+    result = newType(tyGenericInst, t.sons[0].owner)
+    for i in countup(0, sonsLen(t) - 1): 
+      # if one of the params is not concrete, we cannot do anything
+      # but we already raised an error!
+      addSon(result, header.sons[i])
+    idTablePut(gInstTypes, header, result)
+    newbody = ReplaceTypeVarsT(cl, lastSon(body))
+    newbody.n = ReplaceTypeVarsN(cl, lastSon(body).n)
+    addSon(result, newbody)   
+    #writeln(output, ropeToStr(Typetoyaml(newbody)));
+    checkConstructedType(cl.info, newbody)
+  of tyGenericBody: 
+    InternalError(cl.info, "ReplaceTypeVarsT: tyGenericBody")
+    result = ReplaceTypeVarsT(cl, lastSon(t))
+  else: 
+    if containsGenericType(t): 
+      result = copyType(t, t.owner, false)
+      for i in countup(0, sonsLen(result) - 1): 
+        result.sons[i] = ReplaceTypeVarsT(cl, result.sons[i])
+      result.n = ReplaceTypeVarsN(cl, result.n)
+      if result.Kind in GenericTypes: 
+        LocalError(cl.info, errCannotInstantiateX, TypeToString(t, preferName))
+        #writeln(output, ropeToStr(Typetoyaml(result)))
+        #checkConstructedType(cl.info, result)
+
+proc generateTypeInstance*(p: PContext, pt: TIdTable, arg: PNode, 
+                           t: PType): PType = 
+  var cl: TReplTypeVars
+  InitIdTable(cl.symMap)
+  copyIdTable(cl.typeMap, pt)
+  cl.info = arg.info
+  cl.c = p
+  pushInfoContext(arg.info)
+  result = ReplaceTypeVarsT(cl, t)
+  popInfoContext()
+
diff --git a/rod/sigmatch.nim b/rod/sigmatch.nim
index cddfc89cb..dc0b1bbc4 100755
--- a/rod/sigmatch.nim
+++ b/rod/sigmatch.nim
@@ -10,24 +10,28 @@
 # This module implements the signature matching for resolving
 # the call to overloaded procs, generic procs and operators.
 
+import 
+  ast, astalgo, semdata, types, msgs, rnimsyn, lookups, semtypinst, 
+  magicsys
+
 type 
-  TCandidateState = enum 
+  TCandidateState* = enum 
     csEmpty, csMatch, csNoMatch
-  TCandidate{.final.} = object 
+  TCandidate* {.final.} = object 
     exactMatches: int
     subtypeMatches: int
     intConvMatches: int      # conversions to int are not as expensive
     convMatches: int
     genericMatches: int
-    state: TCandidateState
-    callee: PType            # may not be nil!
-    calleeSym: PSym          # may be nil
-    call: PNode              # modified call
-    bindings: TIdTable       # maps sym-ids to types
+    state*: TCandidateState
+    callee*: PType           # may not be nil!
+    calleeSym*: PSym         # may be nil
+    call*: PNode             # modified call
+    bindings*: TIdTable      # maps sym-ids to types
     baseTypeMatch: bool      # needed for conversions from T to openarray[T]
                              # for example
   
-  TTypeRelation = enum       # order is important!
+  TTypeRelation* = enum      # order is important!
     isNone, isConvertible, isIntConv, isSubtype, isGeneric, isEqual
 
 proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} = 
@@ -41,12 +45,12 @@ proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} =
   c.call = nil
   c.baseTypeMatch = false
 
-proc initCandidate(c: var TCandidate, callee: PType) = 
+proc initCandidate*(c: var TCandidate, callee: PType) = 
   initCandidateAux(c, callee)
   c.calleeSym = nil
   initIdTable(c.bindings)
 
-proc initCandidate(c: var TCandidate, callee: PSym, binding: PNode) = 
+proc initCandidate*(c: var TCandidate, callee: PSym, binding: PNode) = 
   initCandidateAux(c, callee.typ)
   c.calleeSym = callee
   initIdTable(c.bindings)
@@ -70,7 +74,7 @@ proc copyCandidate(a: var TCandidate, b: TCandidate) =
   a.baseTypeMatch = b.baseTypeMatch
   copyIdTable(a.bindings, b.bindings)
 
-proc cmpCandidates(a, b: TCandidate): int = 
+proc cmpCandidates*(a, b: TCandidate): int = 
   result = a.exactMatches - b.exactMatches
   if result != 0: return 
   result = a.genericMatches - b.genericMatches
@@ -88,7 +92,7 @@ proc writeMatches(c: TCandidate) =
   Writeln(stdout, "intconv matches: " & $c.intConvMatches)
   Writeln(stdout, "generic matches: " & $c.genericMatches)
 
-proc getNotFoundError(c: PContext, n: PNode): string = 
+proc getNotFoundError*(c: PContext, n: PNode): string = 
   # Gives a detailed error message; this is separated from semDirectCall,
   # as semDirectCall is already pretty slow (and we need this information only
   # in case of an error).
@@ -425,7 +429,7 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
       else: nil
   else: internalError("typeRel(" & $f.kind & ')')
   
-proc cmpTypes(f, a: PType): TTypeRelation = 
+proc cmpTypes*(f, a: PType): TTypeRelation = 
   var mapping: TIdTable
   InitIdTable(mapping)
   result = typeRel(mapping, f, a)
@@ -552,7 +556,7 @@ proc ParamTypesMatch(c: PContext, m: var TCandidate, f, a: PType,
       markUsed(arg, arg.sons[best].sym)
       result = ParamTypesMatchAux(c, m, f, arg.sons[best].typ, arg.sons[best])
 
-proc IndexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode = 
+proc IndexTypesMatch*(c: PContext, f, a: PType, arg: PNode): PNode = 
   var m: TCandidate
   initCandidate(m, f)
   result = paramTypesMatch(c, m, f, a, arg)
@@ -561,7 +565,7 @@ proc setSon(father: PNode, at: int, son: PNode) =
   if sonsLen(father) <= at: setlen(father.sons, at + 1)
   father.sons[at] = son
 
-proc matches(c: PContext, n: PNode, m: var TCandidate) = 
+proc matches*(c: PContext, n: PNode, m: var TCandidate) = 
   var f = 1 # iterates over formal parameters
   var a = 1 # iterates over the actual given arguments
   m.state = csMatch           # until proven otherwise
@@ -670,90 +674,3 @@ proc matches(c: PContext, n: PNode, m: var TCandidate) =
         setSon(m.call, formal.position + 1, copyTree(formal.ast))
     inc(f)
 
-proc sameMethodDispatcher(a, b: PSym): bool = 
-  result = false
-  if a.kind == skMethod and b.kind == skMethod: 
-    var aa = lastSon(a.ast)
-    var bb = lastSon(b.ast)
-    if aa.kind == nkSym and bb.kind == nkSym and aa.sym == bb.sym: 
-      result = true
-  
-proc semDirectCallWithBinding(c: PContext, n, f: PNode, filter: TSymKinds,
-                              initialBinding: PNode): PNode = 
-  var
-    o: TOverloadIter
-    x, y, z: TCandidate
-  #Message(n.info, warnUser, renderTree(n))
-  var sym = initOverloadIter(o, c, f)
-  result = nil
-  if sym == nil: return 
-  initCandidate(x, sym, initialBinding)
-  initCandidate(y, sym, initialBinding)
-
-  while sym != nil: 
-    if sym.kind in filter: 
-      initCandidate(z, sym, initialBinding)
-      z.calleeSym = sym
-      matches(c, n, z)
-      if z.state == csMatch: 
-        case x.state
-        of csEmpty, csNoMatch: x = z
-        of csMatch: 
-          var cmp = cmpCandidates(x, z)
-          if cmp < 0: x = z # z is better than x
-          elif cmp == 0: y = z # z is as good as x
-          else: nil
-    sym = nextOverloadIter(o, c, f)
-  if x.state == csEmpty: 
-    # no overloaded proc found
-    # do not generate an error yet; the semantic checking will check for
-    # an overloaded () operator
-  elif y.state == csMatch and cmpCandidates(x, y) == 0 and
-      not sameMethodDispatcher(x.calleeSym, y.calleeSym): 
-    if x.state != csMatch: 
-      InternalError(n.info, "x.state is not csMatch") 
-    LocalError(n.Info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [
-      getProcHeader(x.calleeSym), getProcHeader(y.calleeSym), 
-      x.calleeSym.Name.s])
-  else: 
-    # only one valid interpretation found:
-    markUsed(n, x.calleeSym)
-    if x.calleeSym.ast == nil: 
-      internalError(n.info, "calleeSym.ast is nil") # XXX: remove this check!
-    if x.calleeSym.ast.sons[genericParamsPos].kind != nkEmpty: 
-      # a generic proc!
-      x.calleeSym = generateInstance(c, x.calleeSym, x.bindings, n.info)
-      x.callee = x.calleeSym.typ
-    result = x.call
-    result.sons[0] = newSymNode(x.calleeSym)
-    result.typ = x.callee.sons[0]
-        
-proc semDirectCall(c: PContext, n: PNode, filter: TSymKinds): PNode = 
-  # process the bindings once:
-  var initialBinding: PNode
-  var f = n.sons[0]
-  if f.kind == nkBracketExpr:
-    # fill in the bindings:
-    initialBinding = f
-    f = f.sons[0]
-  else: 
-    initialBinding = nil
-  result = semDirectCallWithBinding(c, n, f, filter, initialBinding)
-
-proc explictGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode = 
-  assert n.kind == nkBracketExpr
-  for i in 1..sonsLen(n)-1:
-    n.sons[i].typ = semTypeNode(c, n.sons[i], nil)
-  # we cannot check for the proper number of type parameters because in
-  # `f[a,b](x, y)` `f` is not resolved yet properly.
-  # XXX: BUG this should be checked somehow!
-  assert n.sons[0].kind == nkSym
-  
-  var x: TCandidate
-  initCandidate(x, s, n)
-  var newInst = generateInstance(c, s, x.bindings, n.info)
-  
-  markUsed(n, s)
-  result = newSymNode(newInst)
-  result.info = n.info
-
diff --git a/rod/suggest.nim b/rod/suggest.nim
index 377c988bd..5eaa2bd9e 100644
--- a/rod/suggest.nim
+++ b/rod/suggest.nim
@@ -9,7 +9,7 @@
 
 ## This file implements features required for IDE support.
 
-import scanner, ast, astalgo, semdata, msgs, types
+import scanner, ast, astalgo, semdata, msgs, types, sigmatch
 
 const
   sep = '\t'
@@ -33,23 +33,83 @@ proc SymToStr(s: PSym, isLocal: bool): string =
   result.add(sep)
   result.add($ToColumn(s.info))
 
-proc suggestSym(s: PSym): bool {.inline.} = 
+proc filterSym(s: PSym): bool {.inline.} = 
   result = s.name.s[0] in scanner.SymChars
 
+proc suggestField(s: PSym) = 
+  if filterSym(s):
+    MessageOut(SymToStr(s, isLocal=true))
+
 proc suggestExpr*(c: PContext, n: PNode) = 
   if not msgs.inCheckpoint(n.info): return
 
   for i in countdown(c.tab.tos-1, 0): 
     for it in items(c.tab.stack[i]): 
-      if suggestSym(it):
-        MessageOut(SymToStr(it, i > ModuleTablePos))
+      if filterSym(it):
+        MessageOut(SymToStr(it, isLocal = i > ModuleTablePos))
   quit(0)
 
 proc suggestStmt*(c: PContext, n: PNode) = 
-  suggestExpr(c, n) 
+  suggestExpr(c, n)
+
+proc suggestSymList(list: PNode) = 
+  for i in countup(0, sonsLen(list) - 1): 
+    if list.sons[i].kind != nkSym: InternalError(list.info, "getSymFromList")
+    suggestField(list.sons[i].sym)
+
+proc suggestObject(n: PNode) = 
+  case n.kind
+  of nkRecList: 
+    for i in countup(0, sonsLen(n) - 1): suggestObject(n.sons[i])
+  of nkRecCase: 
+    var L = sonsLen(n)
+    if L > 0:
+      suggestObject(n.sons[0])
+      for i in countup(1, L-1): 
+        suggestObject(lastSon(n.sons[i]))
+  of nkSym: suggestField(n.sym)
+  else: nil
 
+proc suggestOperations(c: PContext, n: PNode, typ: PType) =
+  nil
 
 proc suggestFieldAccess*(c: PContext, n: PNode) =
-  suggestExpr(c, n) 
-  # XXX provide a better implementation based on n[0].typ
+  # special code that deals with ``myObj.``. `n` is NOT the nkDotExpr-node, but
+  # ``myObj``.
+  var typ = n.Typ
+  if typ == nil:
+    # a module symbol has no type for example:
+    if n.kind == nkSym and n.sym.kind == skModule: 
+      if n.sym == c.module: 
+        # all symbols accessible, because we are in the current module:
+        for it in items(c.tab.stack[ModuleTablePos]): 
+          if filterSym(it): MessageOut(SymToStr(it, isLocal=false))
+      else: 
+        for it in items(n.sym.tab): 
+          if filterSym(it): MessageOut(SymToStr(it, isLocal=false))
+    else:
+      # fallback:
+      suggestExpr(c, n)
+  elif typ.kind == tyEnum: 
+    # look up if the identifier belongs to the enum:
+    var t = typ
+    while t != nil: 
+      suggestSymList(t.n)
+      t = t.sons[0]
+    suggestOperations(c, n, typ)
+  else:
+    typ = skipTypes(typ, {tyGenericInst, tyVar, tyPtr, tyRef})
+    if typ.kind == tyObject: 
+      var t = typ
+      while true: 
+        suggestObject(t.n)
+        if t.sons[0] == nil: break 
+        t = skipTypes(t.sons[0], {tyGenericInst})
+      suggestOperations(c, n, typ)
+    elif typ.kind == tyTuple and typ.n != nil: 
+      suggestSymList(typ.n)
+      suggestOperations(c, n, typ)
+    else:
+      # fallback: 
+      suggestExpr(c, n)