summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2016-02-28 03:17:20 +0100
committerAndreas Rumpf <rumpf_a@web.de>2016-02-28 03:17:20 +0100
commit1afdefcbe930b042e5f81b30b960c67bed1e859b (patch)
tree79ef15191d0c821585ddcc15903dd953a01a15f5 /compiler
parent6d2fd0c9f17016ee9ae5f8c337445ff958cba2f0 (diff)
downloadNim-1afdefcbe930b042e5f81b30b960c67bed1e859b.tar.gz
added experimental .this pragma
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ast.nim1
-rw-r--r--compiler/astalgo.nim5
-rw-r--r--compiler/pragmas.nim7
-rw-r--r--compiler/semcall.nim40
-rw-r--r--compiler/semdata.nim13
-rw-r--r--compiler/semexprs.nim192
-rw-r--r--compiler/seminst.nim44
-rw-r--r--compiler/semstmts.nim5
-rw-r--r--compiler/sigmatch.nim4
9 files changed, 193 insertions, 118 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 2ce0afcc3..a7fb7c7e9 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -298,6 +298,7 @@ const
   sfWrittenTo* = sfBorrow             # param is assigned to
   sfEscapes* = sfProcvar              # param escapes
   sfBase* = sfDiscriminant
+  sfIsSelf* = sfOverriden             # param is 'self'
 
 const
   # getting ready for the future expr/stmt merge
diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim
index 1a70875d4..4772009b4 100644
--- a/compiler/astalgo.nim
+++ b/compiler/astalgo.nim
@@ -635,7 +635,7 @@ proc reallySameIdent(a, b: string): bool {.inline.} =
   else:
     result = true
 
-proc strTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} =
+proc strTableIncl*(t: var TStrTable, n: PSym; onConflictKeepOld=false): bool {.discardable.} =
   # returns true if n is already in the string table:
   # It is essential that `n` is written nevertheless!
   # This way the newest redefinition is picked by the semantic analyses!
@@ -654,7 +654,8 @@ proc strTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} =
       replaceSlot = h
     h = nextTry(h, high(t.data))
   if replaceSlot >= 0:
-    t.data[replaceSlot] = n # overwrite it with newer definition!
+    if not onConflictKeepOld:
+      t.data[replaceSlot] = n # overwrite it with newer definition!
     return true             # found it
   elif mustRehash(len(t.data), t.counter):
     strTableEnlarge(t)
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index f10d552a1..d4996981d 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -46,7 +46,7 @@ const
     wBreakpoint, wWatchPoint, wPassl, wPassc, wDeadCodeElim, wDeprecated,
     wFloatchecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
     wLinearScanEnd, wPatterns, wEffects, wNoForward, wComputedGoto,
-    wInjectStmt, wDeprecated, wExperimental}
+    wInjectStmt, wDeprecated, wExperimental, wThis}
   lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
     wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
     wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame,
@@ -875,6 +875,11 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
           c.module.flags.incl sfExperimental
         else:
           localError(it.info, "'experimental' pragma only valid as toplevel statement")
+      of wThis:
+        if it.kind == nkExprColonExpr:
+          c.selfName = considerQuotedIdent(it[1])
+        else:
+          c.selfName = getIdent("self")
       of wNoRewrite:
         noVal(it)
       of wBase:
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index eba1059ef..51cc8bfb0 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -39,7 +39,8 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
                        initialBinding: PNode,
                        filter: TSymKinds,
                        best, alt: var TCandidate,
-                       errors: var CandidateErrors) =
+                       errors: var CandidateErrors;
+                       fromUsingStmt: bool) =
   var o: TOverloadIter
   # thanks to the lazy semchecking for operands, we need to iterate over the
   # symbol table *before* any call to 'initCandidate' which might invoke
@@ -50,7 +51,12 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
 
   var syms: seq[tuple[a: PSym, b: int]] = @[]
   while symx != nil:
-    if symx.kind in filter: syms.add((symx, o.lastOverloadScope))
+    if symx.kind in filter:
+      if fromUsingStmt and (symx.typ.n.len <= 1 or
+          sfIsSelf notin symx.typ.n[1].sym.flags):
+        discard "only consider procs that have a 'self' too"
+      else:
+        syms.add((symx, o.lastOverloadScope))
     symx = nextOverloadIter(o, c, headSymbol)
   if syms.len == 0: return
 
@@ -63,7 +69,6 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
     let sym = syms[i][0]
     determineType(c, sym)
     initCandidate(c, z, sym, initialBinding, syms[i][1])
-    z.calleeSym = sym
 
     #if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140:
     #  gDebug = true
@@ -156,28 +161,27 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
   else:
     initialBinding = nil
 
-  var usedSyms: seq[PNode]
-
-  template pickBest(headSymbol: expr) =
+  template pickBest(headSymbol, fromUsingStmt) =
     pickBestCandidate(c, headSymbol, n, orig, initialBinding,
-                      filter, result, alt, errors)
-
-  gatherUsedSyms(c, usedSyms)
-  if usedSyms != nil:
-    var hiddenArg = if usedSyms.len > 1: newNode(nkClosedSymChoice, n.info, usedSyms)
-                    else: usedSyms[0]
-
+                      filter, result, alt, errors, fromUsingStmt)
+
+  #gatherUsedSyms(c, usedSyms)
+  if c.p != nil and c.p.selfSym != nil:
+    # we need to enforce semchecking of selfSym again because it
+    # might need auto-deref:
+    var hiddenArg = newSymNode(c.p.selfSym)
+    hiddenArg.typ = nil
     n.sons.insert(hiddenArg, 1)
     orig.sons.insert(hiddenArg, 1)
 
-    pickBest(f)
+    pickBest(f, true)
 
     if result.state != csMatch:
       n.sons.delete(1)
       orig.sons.delete(1)
     else: return
 
-  pickBest(f)
+  pickBest(f, false)
 
   let overloadsState = result.state
   if overloadsState != csMatch:
@@ -194,7 +198,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
         let op = newIdentNode(getIdent(x), n.info)
         n.sons[0] = op
         orig.sons[0] = op
-        pickBest(op)
+        pickBest(op, false)
 
       if nfExplicitCall in n.flags:
         tryOp ".()"
@@ -209,7 +213,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
       let callOp = newIdentNode(getIdent".=", n.info)
       n.sons[0..1] = [callOp, n[1], calleeName]
       orig.sons[0..1] = [callOp, orig[1], calleeName]
-      pickBest(callOp)
+      pickBest(callOp, false)
 
     if overloadsState == csEmpty and result.state == csEmpty:
       if nfDotField in n.flags and nfExplicitCall notin n.flags:
@@ -228,7 +232,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
           n.sons[0] = f
 
         errors = @[]
-        pickBest(f)
+        pickBest(f, false)
         #notFoundError(c, n, errors)
 
       return
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index 656bfc449..48d1a1a74 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -30,6 +30,7 @@ type
                               # statements
     owner*: PSym              # the symbol this context belongs to
     resultSym*: PSym          # the result symbol (if we are in a proc)
+    selfSym*: PSym            # the 'self' symbol (if available)
     nestedLoopCounter*: int   # whether we are in a loop or not
     nestedBlockCounter*: int  # whether we are in a block or not
     inTryStmt*: int           # whether we are in a try statement; works also
@@ -103,7 +104,7 @@ type
     inParallelStmt*: int
     instTypeBoundOp*: proc (c: PContext; dc: PSym; t: PType; info: TLineInfo;
                             op: TTypeAttachedOp): PSym {.nimcall.}
-
+    selfName*: PIdent
 
 proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
   result.genericSym = s
@@ -154,16 +155,6 @@ proc popOwner() =
 proc lastOptionEntry(c: PContext): POptionEntry =
   result = POptionEntry(c.optionStack.tail)
 
-proc pushProcCon*(c: PContext, owner: PSym) {.inline.} =
-  if owner == nil:
-    internalError("owner is nil")
-    return
-  var x: PProcCon
-  new(x)
-  x.owner = owner
-  x.next = c.p
-  c.p = x
-
 proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next
 
 proc newOptionEntry(): POptionEntry =
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 87d7764a2..6009644fa 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -77,88 +77,6 @@ proc inlineConst(n: PNode, s: PSym): PNode {.inline.} =
   result.typ = s.typ
   result.info = n.info
 
-proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
-  case s.kind
-  of skConst:
-    markUsed(n.info, s)
-    styleCheckUse(n.info, s)
-    case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind
-    of  tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
-        tyTuple, tySet, tyUInt..tyUInt64:
-      if s.magic == mNone: result = inlineConst(n, s)
-      else: result = newSymNode(s, n.info)
-    of tyArrayConstr, tySequence:
-      # Consider::
-      #     const x = []
-      #     proc p(a: openarray[int])
-      #     proc q(a: openarray[char])
-      #     p(x)
-      #     q(x)
-      #
-      # It is clear that ``[]`` means two totally different things. Thus, we
-      # copy `x`'s AST into each context, so that the type fixup phase can
-      # deal with two different ``[]``.
-      if s.ast.len == 0: result = inlineConst(n, s)
-      else: result = newSymNode(s, n.info)
-    else:
-      result = newSymNode(s, n.info)
-  of skMacro: result = semMacroExpr(c, n, n, s, flags)
-  of skTemplate: result = semTemplateExpr(c, n, s, flags)
-  of skParam:
-    markUsed(n.info, s)
-    styleCheckUse(n.info, s)
-    if s.typ.kind == tyStatic and s.typ.n != nil:
-      # XXX see the hack in sigmatch.nim ...
-      return s.typ.n
-    elif sfGenSym in s.flags:
-      if c.p.wasForwarded:
-        # gensym'ed parameters that nevertheless have been forward declared
-        # need a special fixup:
-        let realParam = c.p.owner.typ.n[s.position+1]
-        internalAssert realParam.kind == nkSym and realParam.sym.kind == skParam
-        return newSymNode(c.p.owner.typ.n[s.position+1].sym, n.info)
-      elif c.p.owner.kind == skMacro:
-        # gensym'ed macro parameters need a similar hack (see bug #1944):
-        var u = searchInScopes(c, s.name)
-        internalAssert u != nil and u.kind == skParam and u.owner == s.owner
-        return newSymNode(u, n.info)
-    result = newSymNode(s, n.info)
-  of skVar, skLet, skResult, skForVar:
-    if s.magic == mNimvm:
-      localError(n.info, "illegal context for 'nimvm' magic")
-
-    markUsed(n.info, s)
-    styleCheckUse(n.info, s)
-    # if a proc accesses a global variable, it is not side effect free:
-    if sfGlobal in s.flags:
-      incl(c.p.owner.flags, sfSideEffect)
-    result = newSymNode(s, n.info)
-    # We cannot check for access to outer vars for example because it's still
-    # not sure the symbol really ends up being used:
-    # var len = 0 # but won't be called
-    # genericThatUsesLen(x) # marked as taking a closure?
-  of skGenericParam:
-    styleCheckUse(n.info, s)
-    if s.typ.kind == tyStatic:
-      result = newSymNode(s, n.info)
-      result.typ = s.typ
-    elif s.ast != nil:
-      result = semExpr(c, s.ast)
-    else:
-      n.typ = s.typ
-      return n
-  of skType:
-    markUsed(n.info, s)
-    styleCheckUse(n.info, s)
-    if s.typ.kind == tyStatic and s.typ.n != nil:
-      return s.typ.n
-    result = newSymNode(s, n.info)
-    result.typ = makeTypeDesc(c, s.typ)
-  else:
-    markUsed(n.info, s)
-    styleCheckUse(n.info, s)
-    result = newSymNode(s, n.info)
-
 type
   TConvStatus = enum
     convOK,
@@ -1015,6 +933,116 @@ proc readTypeParameter(c: PContext, typ: PType,
         return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info)
   #echo "came here: returned nil"
 
+proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
+  case s.kind
+  of skConst:
+    markUsed(n.info, s)
+    styleCheckUse(n.info, s)
+    case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind
+    of  tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
+        tyTuple, tySet, tyUInt..tyUInt64:
+      if s.magic == mNone: result = inlineConst(n, s)
+      else: result = newSymNode(s, n.info)
+    of tyArrayConstr, tySequence:
+      # Consider::
+      #     const x = []
+      #     proc p(a: openarray[int])
+      #     proc q(a: openarray[char])
+      #     p(x)
+      #     q(x)
+      #
+      # It is clear that ``[]`` means two totally different things. Thus, we
+      # copy `x`'s AST into each context, so that the type fixup phase can
+      # deal with two different ``[]``.
+      if s.ast.len == 0: result = inlineConst(n, s)
+      else: result = newSymNode(s, n.info)
+    else:
+      result = newSymNode(s, n.info)
+  of skMacro: result = semMacroExpr(c, n, n, s, flags)
+  of skTemplate: result = semTemplateExpr(c, n, s, flags)
+  of skParam:
+    markUsed(n.info, s)
+    styleCheckUse(n.info, s)
+    if s.typ.kind == tyStatic and s.typ.n != nil:
+      # XXX see the hack in sigmatch.nim ...
+      return s.typ.n
+    elif sfGenSym in s.flags:
+      if c.p.wasForwarded:
+        # gensym'ed parameters that nevertheless have been forward declared
+        # need a special fixup:
+        let realParam = c.p.owner.typ.n[s.position+1]
+        internalAssert realParam.kind == nkSym and realParam.sym.kind == skParam
+        return newSymNode(c.p.owner.typ.n[s.position+1].sym, n.info)
+      elif c.p.owner.kind == skMacro:
+        # gensym'ed macro parameters need a similar hack (see bug #1944):
+        var u = searchInScopes(c, s.name)
+        internalAssert u != nil and u.kind == skParam and u.owner == s.owner
+        return newSymNode(u, n.info)
+    result = newSymNode(s, n.info)
+  of skVar, skLet, skResult, skForVar:
+    if s.magic == mNimvm:
+      localError(n.info, "illegal context for 'nimvm' magic")
+
+    markUsed(n.info, s)
+    styleCheckUse(n.info, s)
+    # if a proc accesses a global variable, it is not side effect free:
+    if sfGlobal in s.flags:
+      incl(c.p.owner.flags, sfSideEffect)
+    result = newSymNode(s, n.info)
+    # We cannot check for access to outer vars for example because it's still
+    # not sure the symbol really ends up being used:
+    # var len = 0 # but won't be called
+    # genericThatUsesLen(x) # marked as taking a closure?
+  of skGenericParam:
+    styleCheckUse(n.info, s)
+    if s.typ.kind == tyStatic:
+      result = newSymNode(s, n.info)
+      result.typ = s.typ
+    elif s.ast != nil:
+      result = semExpr(c, s.ast)
+    else:
+      n.typ = s.typ
+      return n
+  of skType:
+    markUsed(n.info, s)
+    styleCheckUse(n.info, s)
+    if s.typ.kind == tyStatic and s.typ.n != nil:
+      return s.typ.n
+    result = newSymNode(s, n.info)
+    result.typ = makeTypeDesc(c, s.typ)
+  of skField:
+    if c.p != nil and c.p.selfSym != nil:
+      var ty = skipTypes(c.p.selfSym.typ, {tyGenericInst, tyVar, tyPtr, tyRef})
+      while tfBorrowDot in ty.flags: ty = ty.skipTypes({tyDistinct})
+      var check: PNode = nil
+      if ty.kind == tyObject:
+        while true:
+          check = nil
+          let f = lookupInRecordAndBuildCheck(c, n, ty.n, s.name, check)
+          if f != nil and fieldVisible(c, f):
+            # is the access to a public field or in the same module or in a friend?
+            doAssert f == s
+            markUsed(n.info, f)
+            styleCheckUse(n.info, f)
+            result = newNodeIT(nkDotExpr, n.info, f.typ)
+            result.add makeDeref(newSymNode(c.p.selfSym))
+            result.add newSymNode(f) # we now have the correct field
+            if check != nil:
+              check.sons[0] = result
+              check.typ = result.typ
+              result = check
+            return result
+          if ty.sons[0] == nil: break
+          ty = skipTypes(ty.sons[0], {tyGenericInst})
+    # old code, not sure if it's live code:
+    markUsed(n.info, s)
+    styleCheckUse(n.info, s)
+    result = newSymNode(s, n.info)
+  else:
+    markUsed(n.info, s)
+    styleCheckUse(n.info, s)
+    result = newSymNode(s, n.info)
+
 proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
   ## returns nil if it's not a built-in field access
   checkSonsLen(n, 2)
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index 2c767ffc6..4a45dee9d 100644
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -10,6 +10,47 @@
 # This module implements the instantiation of generic procs.
 # included from sem.nim
 
+proc addObjFieldsToLocalScope(c: PContext; n: PNode) =
+  template rec(n) = addObjFieldsToLocalScope(c, n)
+  case n.kind
+  of nkRecList:
+    for i in countup(0, len(n)-1):
+      rec n[i]
+  of nkRecCase:
+    if n.len > 0: rec n.sons[0]
+    for i in countup(1, len(n)-1):
+      if n[i].kind in {nkOfBranch, nkElse}: rec lastSon(n[i])
+  of nkSym:
+    let f = n.sym
+    if f.kind == skField and fieldVisible(c, f):
+      c.currentScope.symbols.strTableIncl(f, onConflictKeepOld=true)
+      incl(f.flags, sfUsed)
+      # it is not an error to shadow fields via parameters
+  else: discard
+
+proc rawPushProcCon(c: PContext, owner: PSym) =
+  var x: PProcCon
+  new(x)
+  x.owner = owner
+  x.next = c.p
+  c.p = x
+
+proc rawHandleSelf(c: PContext; owner: PSym) =
+  if c.selfName != nil and owner.kind in {skProc, skMethod, skConverter, skIterator, skMacro} and owner.typ != nil:
+    let params = owner.typ.n
+    if params.len > 1:
+      let arg = params[1].sym
+      if arg.name.id == c.selfName.id:
+        c.p.selfSym = arg
+        arg.flags.incl sfIsSelf
+        let t = c.p.selfSym.typ.skipTypes(abstractPtrs)
+        if t.kind == tyObject:
+          addObjFieldsToLocalScope(c, t.n)
+
+proc pushProcCon*(c: PContext; owner: PSym) =
+  rawPushProcCon(c, owner)
+  rawHandleSelf(c, owner)
+
 iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable): PSym =
   internalAssert n.kind == nkGenericParams
   for i, a in n.pairs:
@@ -248,7 +289,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
     addDecl(c, s)
     entry.concreteTypes[i] = s.typ
     inc i
-  pushProcCon(c, result)
+  rawPushProcCon(c, result)
   instantiateProcType(c, pt, result, info)
   for j in 1 .. result.typ.len-1:
     entry.concreteTypes[i] = result.typ.sons[j]
@@ -263,6 +304,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
     # a ``compiles`` context but this is the lesser evil. See
     # bug #1055 (tevilcompiles).
     #if c.compilesContextId == 0:
+    rawHandleSelf(c, result)
     entry.compilesId = c.compilesContextId
     fn.procInstCache.safeAdd(entry)
     c.generics.add(makeInstPair(fn, entry))
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index edcf079fa..d1c088d73 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -1206,9 +1206,10 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
     # Macros and Templates can have generic parameters, but they are
     # only used for overload resolution (there is no instantiation of
     # the symbol, so we must process the body now)
+    pushProcCon(c, s)
     if n.sons[genericParamsPos].kind == nkEmpty or usePseudoGenerics:
       if not usePseudoGenerics: paramsTypeCheck(c, s.typ)
-      pushProcCon(c, s)
+
       c.p.wasForwarded = proto != nil
       maybeAddResult(c, s, n)
       if sfImportc notin s.flags:
@@ -1217,7 +1218,6 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
         # unfortunately we cannot skip this step when in 'system.compiles'
         # context as it may even be evaluated in 'system.compiles':
         n.sons[bodyPos] = transformBody(c.module, semBody, s)
-      popProcCon(c)
     else:
       if s.typ.sons[0] != nil and kind != skIterator:
         addDecl(c, newSym(skUnknown, getIdent"result", nil, n.info))
@@ -1228,6 +1228,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
     if sfImportc in s.flags:
       # so we just ignore the body after semantic checking for importc:
       n.sons[bodyPos] = ast.emptyNode
+    popProcCon(c)
   else:
     if proto != nil: localError(n.info, errImplOfXexpected, proto.name.s)
     if {sfImportc, sfBorrow} * s.flags == {} and s.magic == mNone:
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 96df0c5c6..ceadc2fea 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -37,6 +37,7 @@ type
                              # is this a top-level symbol or a nested proc?
     call*: PNode             # modified call
     bindings*: TIdTable      # maps types to types
+    magic*: TMagic           # magic of operation
     baseTypeMatch: bool      # needed for conversions from T to openarray[T]
                              # for example
     fauxMatch*: TTypeKind    # the match was successful only due to the use
@@ -114,6 +115,7 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
       c.calleeScope = 1
   else:
     c.calleeScope = calleeScope
+  c.magic = c.calleeSym.magic
   initIdTable(c.bindings)
   c.errors = nil
   if binding != nil and callee.kind in routineKinds:
@@ -1691,7 +1693,7 @@ proc partialMatch*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
   matchesAux(c, n, nOrig, m, marker)
 
 proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
-  if m.calleeSym != nil and m.calleeSym.magic in {mArrGet, mArrPut}:
+  if m.magic in {mArrGet, mArrPut}:
     m.state = csMatch
     m.call = n
     return