summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ast.nim6
-rw-r--r--compiler/idents.nim1
-rw-r--r--compiler/msgs.nim2
-rw-r--r--compiler/pragmas.nim7
-rw-r--r--compiler/semcall.nim113
-rw-r--r--compiler/semexprs.nim31
-rw-r--r--compiler/semmagic.nim1
-rw-r--r--compiler/semstmts.nim9
-rw-r--r--compiler/semtypes.nim2
-rw-r--r--compiler/sigmatch.nim22
-rw-r--r--compiler/types.nim1
-rw-r--r--compiler/wordrecg.nim6
-rw-r--r--tests/reject/topaque.nim24
13 files changed, 131 insertions, 94 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 04ac88c1c..b12d58626 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -216,7 +216,7 @@ type
   TNodeKinds* = set[TNodeKind]
 
 type
-  TSymFlag* = enum    # already 30 flags!
+  TSymFlag* = enum    # already 32 flags!
     sfUsed,           # read access of sym (for warnings) or simply used
     sfExported,       # symbol is exported from module
     sfFromGeneric,    # symbol is instantiation of a generic; this is needed 
@@ -353,6 +353,7 @@ type
                 # efficiency
     nfTransf,   # node has been transformed
     nfSem       # node has been checked for semantics
+    nfDelegate  # the call can use a delegator
 
   TNodeFlags* = set[TNodeFlag]
   TTypeFlag* = enum   # keep below 32 for efficiency reasons (now: 23)
@@ -774,7 +775,8 @@ const
     tyProc, tyString, tyError}
   ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType, skIterator, 
     skMacro, skTemplate, skConverter, skEnumField, skLet, skStub}
-  PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16, nfAllConst}
+  PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16,
+                                      nfAllConst, nfDelegate}
   namePos* = 0
   patternPos* = 1    # empty except for term rewriting macros
   genericParamsPos* = 2
diff --git a/compiler/idents.nim b/compiler/idents.nim
index a50c5269c..f0935c204 100644
--- a/compiler/idents.nim
+++ b/compiler/idents.nim
@@ -103,4 +103,5 @@ proc IdentEq*(id: PIdent, name: string): bool =
   result = id.id == getIdent(name).id
 
 var idAnon* = getIdent":anonymous"
+let idDelegator* = getIdent":delegator"
 
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 3e5304358..47a4d284b 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -89,6 +89,7 @@ type
     errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError, 
     errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile, 
     errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitely,
+    errOnlyACallOpCanBeDelegator,
     
     errXExpectsTwoArguments, 
     errXExpectsObjectTypes, errXcanNeverBeOfThisSubtype, errTooManyIterations, 
@@ -316,6 +317,7 @@ const
     errCannotRenderX: "cannot render reStructuredText element \'$1\'", 
     errVarVarTypeNotAllowed: "type \'var var\' is not allowed",
     errInstantiateXExplicitely: "instantiate '$1' explicitely",
+    errOnlyACallOpCanBeDelegator: "only a call operator can be a delegator",
     errXExpectsTwoArguments: "\'$1\' expects two arguments", 
     errXExpectsObjectTypes: "\'$1\' expects object types",
     errXcanNeverBeOfThisSubtype: "\'$1\' can never be of this subtype", 
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index f185d0f80..aeffcdc4c 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -24,13 +24,14 @@ const
     wCompilerProc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge, 
     wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
     wNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wCodegenDecl,
-    wGenSym, wInject, wRaises, wTags, wOperator}
+    wGenSym, wInject, wRaises, wTags, wOperator, wDelegator}
   converterPragmas* = procPragmas
   methodPragmas* = procPragmas
-  templatePragmas* = {wImmediate, wDeprecated, wError, wGenSym, wInject, wDirty}
+  templatePragmas* = {wImmediate, wDeprecated, wError, wGenSym, wInject, wDirty,
+    wDelegator}
   macroPragmas* = {FirstCallConv..LastCallConv, wImmediate, wImportc, wExportc,
     wNodecl, wMagic, wNosideEffect, wCompilerProc, wDeprecated, wExtern,
-    wImportcpp, wImportobjc, wError, wDiscardable, wGenSym, wInject}
+    wImportcpp, wImportobjc, wError, wDiscardable, wGenSym, wInject, wDelegator}
   iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideEffect, wSideEffect, 
     wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
     wImportcpp, wImportobjc, wError, wDiscardable, wGenSym, wInject, wRaises,
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index 735e6fac8..22ee8c099 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -34,25 +34,18 @@ proc sameMethodDispatcher(a, b: PSym): bool =
   
 proc determineType(c: PContext, s: PSym)
 
-proc resolveOverloads(c: PContext, n, orig: PNode, 
-                      filter: TSymKinds): TCandidate =
-  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
-  
-  var
-    o: TOverloadIter
-    alt, z: TCandidate
-
-  template best: expr = result
-  #Message(n.info, warnUser, renderTree(n))
-  var sym = initOverloadIter(o, c, f)
+proc
+  pickBestCandidate(c: PContext, headSymbol: PNode,
+                    n, orig: PNode,
+                    initialBinding: PNode,
+                    filter: TSymKinds,
+                    best, alt: var TCandidate,
+                    errors: var seq[string]) =
+  var o: TOverloadIter
+  var sym = initOverloadIter(o, c, headSymbol)
   var symScope = o.lastOverloadScope
+
+  var z: TCandidate
   
   if sym == nil: return
   initCandidate(best, sym, initialBinding, symScope)
@@ -64,6 +57,11 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
       initCandidate(z, sym, initialBinding, o.lastOverloadScope)
       z.calleeSym = sym
       matches(c, n, orig, z)
+      if errors != nil:
+        errors.safeAdd(getProcHeader(sym))
+        if z.errors != nil:
+          for err in z.errors:
+            errors[errors.len - 1].add("\n  " & err)
       if z.state == csMatch:
         # little hack so that iterators are preferred over everything else:
         if sym.kind == skIterator: inc(z.exactMatches, 200)
@@ -74,17 +72,71 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
           if cmp < 0: best = z   # x is better than the best so far
           elif cmp == 0: alt = z # x is as good as the best so far
           else: nil
-    sym = nextOverloadIter(o, c, f)
-
-  if best.state == csEmpty:
-    # no overloaded proc found
-    # do not generate an error yet; the semantic checking will check for
-    # an overloaded () operator
-  elif alt.state == csMatch and cmpCandidates(best, alt) == 0 and
-      not sameMethodDispatcher(best.calleeSym, alt.calleeSym):
-    if best.state != csMatch:
-      InternalError(n.info, "x.state is not csMatch")
-    #writeMatches(best)
+    sym = nextOverloadIter(o, c, headSymbol)
+
+proc NotFoundError*(c: PContext, n: PNode, errors: seq[string]) =
+  # Gives a detailed error message; this is separated from semOverloadedCall,
+  # as semOverlodedCall is already pretty slow (and we need this information
+  # only in case of an error).
+  if c.InCompilesContext > 0: 
+    # fail fast:
+    GlobalError(n.info, errTypeMismatch, "")
+  var result = msgKindToString(errTypeMismatch)
+  add(result, describeArgs(c, n, 1 + ord(nfDelegate in n.flags)))
+  add(result, ')')
+  
+  var candidates = ""
+  for err in errors:
+    add(candidates, err)
+    add(candidates, "\n")
+
+  if candidates != "":
+    add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates)
+
+  LocalError(n.Info, errGenerated, result)
+
+proc resolveOverloads(c: PContext, n, orig: PNode,
+                      filter: TSymKinds): TCandidate =
+  var initialBinding: PNode
+  var alt: TCandidate
+  var f = n.sons[0]
+  if f.kind == nkBracketExpr:
+    # fill in the bindings:
+    initialBinding = f
+    f = f.sons[0]
+  else:
+    initialBinding = nil
+
+  var errors: seq[string]
+
+  template pickBest(headSymbol: expr) =
+    pickBestCandidate(c, headSymbol, n, orig, initialBinding,
+                      filter, result, alt, errors)
+
+  pickBest(f)
+
+  if result.state == csEmpty:
+    if nfDelegate in n.flags:
+      InternalAssert f.kind == nkIdent
+      let calleeName = newStrNode(nkStrLit, f.ident.s)
+      calleeName.info = n.info
+
+      let callOp = newIdentNode(idDelegator, n.info)
+      n.sons[0..0] = [callOp, calleeName]
+      orig.sons[0..0] = [callOp, calleeName]
+     
+      pickBest(callOp)
+
+    if result.state == csEmpty:
+      errors = @[]
+      pickBest(f)
+      NotFoundError(c, n, errors)
+      return
+
+  if alt.state == csMatch and cmpCandidates(result, alt) == 0 and
+      not sameMethodDispatcher(result.calleeSym, alt.calleeSym):
+    InternalAssert result.state == csMatch
+    #writeMatches(result)
     #writeMatches(alt)
     if c.inCompilesContext > 0: 
       # quick error message for performance of 'compiles' built-in:
@@ -98,7 +150,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
       add(args, ")")
 
       LocalError(n.Info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [
-        getProcHeader(best.calleeSym), getProcHeader(alt.calleeSym),
+        getProcHeader(result.calleeSym), getProcHeader(alt.calleeSym),
         args])
 
 
@@ -155,6 +207,7 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
                        filter: TSymKinds): PNode =
   var r = resolveOverloads(c, n, nOrig, filter)
   if r.state == csMatch: result = semResolvedCall(c, n, r)
+  else: result = errorNode(c, n)
     
 proc explicitGenericInstError(n: PNode): PNode =
   LocalError(n.info, errCannotInstantiateX, renderTree(n))
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index d0b81364e..369b0eb90 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -682,7 +682,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
       result = n.sons[0]
       result.kind = nkCall
       for i in countup(1, sonsLen(n) - 1): addSon(result, n.sons[i])
-      return semExpr(c, result, flags)
+      return semDirectOp(c, result, flags)
   else: 
     n.sons[0] = semExpr(c, n.sons[0])
   let nOrig = n.copyTree
@@ -767,11 +767,6 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
   let nOrig = n.copyTree
   #semLazyOpAux(c, n)
   result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
-  if result == nil:
-    result = overloadedCallOpr(c, n)
-    if result == nil:
-      NotFoundError(c, n)
-      return errorNode(c, n)
   result = afterCallActions(c, result, nOrig, flags)
 
 proc buildStringify(c: PContext, arg: PNode): PNode = 
@@ -979,20 +974,11 @@ proc dotTransformation(c: PContext, n: PNode): PNode =
     addSon(result, copyTree(n[0]))
   else:
     var i = considerAcc(n.sons[1])
-    var f = searchInScopes(c, i)
-    # if f != nil and f.kind == skStub: loadStub(f)
-    # ``loadStub`` is not correct here as we don't care for ``f`` really
-    if f != nil: 
-      # BUGFIX: do not check for (f.kind in {skProc, skMethod, skIterator}) here
-      # This special node kind is to merge with the call handler in `semExpr`.
-      result = newNodeI(nkDotCall, n.info)
-      addSon(result, newIdentNode(i, n[1].info))
-      addSon(result, copyTree(n[0]))
-    else:
-      if not ContainsOrIncl(c.UnknownIdents, i.id):
-        LocalError(n.Info, errUndeclaredFieldX, i.s)
-      result = errorNode(c, n)
-
+    result = newNodeI(nkDotCall, n.info)
+    result.flags.incl nfDelegate
+    addSon(result, newIdentNode(i, n[1].info))
+    addSon(result, copyTree(n[0]))
+  
 proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = 
   # this is difficult, because the '.' is used in many different contexts
   # in Nimrod. We first allow types in the semantic checking.
@@ -1866,7 +1852,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: 
     # check if it is an expression macro:
     checkMinSonsLen(n, 1)
-    var s = qualifiedLookup(c, n.sons[0], {checkUndeclared})
+    let mode = if nfDelegate in n.flags: {} else: {checkUndeclared}
+    var s = qualifiedLookup(c, n.sons[0], mode)
     if s != nil: 
       case s.kind
       of skMacro:
@@ -1900,6 +1887,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     elif isSymChoice(n.sons[0]) or n[0].kind == nkBracketExpr and 
         isSymChoice(n[0][0]):
       result = semDirectOp(c, n, flags)
+    elif nfDelegate in n.flags:
+      result = semDirectOp(c, n, flags)
     else:
       result = semIndirectOp(c, n, flags)
   of nkWhen:
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index b9ef8b008..88567b10a 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -113,6 +113,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
     result.typ = getSysType(tyString)
   of mInstantiationInfo: result = semInstantiationInfo(c, n)
   of mOrd: result = semOrd(c, n)
+  of mHigh: result = semLowHigh(c, n, mHigh)
   of mShallowCopy: result = semShallowCopy(c, n, flags)
   of mNBindSym: result = semBindSym(c, n)
   of mLocals: result = semLocals(c, n)
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 3b83290ea..022d412ce 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -835,7 +835,14 @@ proc semProcAnnotation(c: PContext, prc: PNode): PNode =
     var it = n.sons[i]
     var key = if it.kind == nkExprColonExpr: it.sons[0] else: it
     let m = lookupMacro(c, key)
-    if m == nil: continue
+    if m == nil:
+      if key.kind == nkIdent and key.ident.id == ord(wDelegator):
+        if considerAcc(prc.sons[namePos]).s == "()":
+          prc.sons[namePos] = newIdentNode(idDelegator, prc.info)
+          prc.sons[pragmasPos] = copyExcept(n, i)
+        else:
+          LocalError(prc.info, errOnlyACallOpCanBeDelegator)
+      continue
     # we transform ``proc p {.m, rest.}`` into ``m(do: proc p {.rest.})`` and
     # let the semantic checker deal with it:
     var x = newNodeI(nkCall, n.info)
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index e9541997f..d8846d717 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -608,7 +608,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
       if genericParams.sons[i].sym.name.id == finalTypId.id:
         return genericParams.sons[i].typ
 
-    var s = newSym(skType, finalTypId, getCurrOwner(), info)
+    var s = newSym(skType, finalTypId, typeClass.sym, info)
     if typId == nil: s.flags.incl(sfAnon)
     s.linkTo(typeClass)
     s.position = genericParams.len
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 25d0d8004..5411904df 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -202,28 +202,6 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1): string =
     add(result, argTypeToString(arg))
     if i != sonsLen(n) - 1: add(result, ", ")
 
-proc NotFoundError*(c: PContext, n: PNode) =
-  # Gives a detailed error message; this is separated from semOverloadedCall,
-  # as semOverlodedCall is already pretty slow (and we need this information
-  # only in case of an error).
-  if c.InCompilesContext > 0: 
-    # fail fast:
-    GlobalError(n.info, errTypeMismatch, "")
-  var result = msgKindToString(errTypeMismatch)
-  add(result, describeArgs(c, n))
-  add(result, ')')
-  var candidates = ""
-  var o: TOverloadIter
-  var sym = initOverloadIter(o, c, n.sons[0])
-  while sym != nil:
-    if sym.kind in RoutineKinds:
-      add(candidates, getProcHeader(sym))
-      add(candidates, "\n")
-    sym = nextOverloadIter(o, c, n.sons[0])
-  if candidates != "":
-    add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates)
-  LocalError(n.Info, errGenerated, result)
-  
 proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation
 proc concreteType(c: TCandidate, t: PType): PType = 
   case t.kind
diff --git a/compiler/types.nim b/compiler/types.nim
index 2564741d8..99bedfca7 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -442,6 +442,7 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
     if t.len == 0: result = "typedesc"
     else: result = "typedesc[" & constraintsToStr(t) & "]"
   of tyTypeClass:
+    if t.n != nil: return t.sym.owner.name.s
     case t.len
     of 0: result = "typeclass[]"
     of 1: result = "typeclass[" & consToStr(t.sons[0]) & "]"
diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim
index a9540269c..f8a19ae19 100644
--- a/compiler/wordrecg.nim
+++ b/compiler/wordrecg.nim
@@ -39,7 +39,8 @@ type
 
     wDestroy,
     
-    wImmediate, wDestructor, wImportCpp, wImportObjC,
+    wImmediate, wDestructor, wDelegator,
+    wImportCpp, wImportObjC,
     wImportCompilerProc,
     wImportc, wExportc, wIncompleteStruct, wRequiresInit,
     wAlign, wNodecl, wPure, wSideeffect, wHeader,
@@ -120,7 +121,8 @@ const
 
     "destroy",
     
-    "immediate", "destructor", "importcpp", "importobjc",
+    "immediate", "destructor", "delegator",
+    "importcpp", "importobjc",
     "importcompilerproc", "importc", "exportc", "incompletestruct",
     "requiresinit", "align", "nodecl", "pure", "sideeffect",
     "header", "nosideeffect", "noreturn", "merge", "lib", "dynlib", 
diff --git a/tests/reject/topaque.nim b/tests/reject/topaque.nim
index ac390835b..f0587c959 100644
--- a/tests/reject/topaque.nim
+++ b/tests/reject/topaque.nim
@@ -1,18 +1,18 @@
 discard """
   file: "topaque.nim"
   line: 16
-  errormsg: "undeclared field: \'buffer\'"
+  errormsg: "undeclared identifier: \'buffer\'"
 """
-# Test the new opaque types

-

-import 

-  mopaque

-  

-var

-  L: TLexer

-  

-L.filename = "ha"

-L.line = 34

-L.buffer[0] = '\0' #ERROR_MSG undeclared field: 'buffer'

+# Test the new opaque types
+
+import 
+  mopaque
+  
+var
+  L: TLexer
+  
+L.filename = "ha"
+L.line = 34
+L.buffer[0] = '\0' #ERROR_MSG undeclared field: 'buffer'