summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/cgen.nim2
-rw-r--r--compiler/condsyms.nim1
-rw-r--r--compiler/semcall.nim5
-rw-r--r--compiler/semexprs.nim13
-rw-r--r--compiler/semgnrc.nim23
-rw-r--r--compiler/semmagic.nim34
-rw-r--r--compiler/semstmts.nim1
-rw-r--r--compiler/semtempl.nim51
-rw-r--r--compiler/semtypes.nim12
-rw-r--r--compiler/sigmatch.nim6
-rw-r--r--lib/system.nim8
-rw-r--r--todo.txt1
-rw-r--r--web/news.txt3
13 files changed, 153 insertions, 7 deletions
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 3f88e63ee..f63134b66 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -1110,7 +1110,7 @@ proc rawNewModule(module: PSym, filename: string): BModule =
 
 proc nullify[T](arr: var T) =
   for i in low(arr)..high(arr):
-    arr[i] = nil
+    arr[i] = Rope(nil)
 
 proc resetModule*(m: BModule) =
   # between two compilations in CAAS mode, we can throw
diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim
index 31bd85a06..60e8f2826 100644
--- a/compiler/condsyms.nim
+++ b/compiler/condsyms.nim
@@ -92,3 +92,4 @@ proc initDefines*() =
   defineSymbol("nimvarargstyped")
   defineSymbol("nimtypedescfixed")
   defineSymbol("nimKnowsNimvm")
+  defineSymbol("nimArrIdx")
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index 2f181b5f3..6787afe27 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -308,7 +308,10 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
   let gp = finalCallee.ast.sons[genericParamsPos]
   if gp.kind != nkEmpty:
     if x.calleeSym.kind notin {skMacro, skTemplate}:
-      finalCallee = generateInstance(c, x.calleeSym, x.bindings, n.info)
+      if x.calleeSym.magic == mArrPut:
+        finalCallee = x.calleeSym
+      else:
+        finalCallee = generateInstance(c, x.calleeSym, x.bindings, n.info)
     else:
       # For macros and templates, the resolved generic params
       # are added as normal params.
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 3ff04a4fc..20b6775a5 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -1250,7 +1250,7 @@ proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} =
 template resultTypeIsInferrable(typ: PType): expr =
   typ.isMetaType and typ.kind != tyTypeDesc
 
-proc semAsgn(c: PContext, n: PNode): PNode =
+proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
   checkSonsLen(n, 2)
   var a = n.sons[0]
   case a.kind
@@ -1273,12 +1273,15 @@ proc semAsgn(c: PContext, n: PNode): PNode =
     # --> `[]=`(a, i, x)
     let oldBracketExpr = c.p.bracketExpr
     a = semSubscript(c, a, {efLValue})
-    if a == nil:
+    if a == nil and mode != noOverloadedSubscript:
       result = buildOverloadedSubscripts(n.sons[0], getIdent"[]=")
       add(result, n[1])
       result = semExprNoType(c, result)
       c.p.bracketExpr = oldBracketExpr
       return result
+    elif a == nil:
+      localError(n.info, "could not resolve: " & $n[0])
+      return n
     c.p.bracketExpr = oldBracketExpr
   of nkCurlyExpr:
     # a{i} = x -->  `{}=`(a, i, x)
@@ -1323,7 +1326,8 @@ proc semAsgn(c: PContext, n: PNode): PNode =
           typeMismatch(n, lhs.typ, rhs.typ)
 
     n.sons[1] = fitNode(c, le, rhs)
-    if tfHasAsgn in lhs.typ.flags and not lhsIsResult:
+    if tfHasAsgn in lhs.typ.flags and not lhsIsResult and
+        mode != noOverloadedAsgn:
       return overloadedAsgn(c, lhs, n.sons[1])
 
     fixAbstractType(c, n)
@@ -1715,6 +1719,9 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
   of mTypeOf:
     checkSonsLen(n, 2)
     result = semTypeOf(c, n.sons[1])
+  #of mArrGet: result = semArrGet(c, n, flags)
+  #of mArrPut: result = semArrPut(c, n, flags)
+  #of mAsgn: result = semAsgnOpr(c, n)
   of mDefined: result = semDefined(c, setMs(n, s), false)
   of mDefinedInScope: result = semDefined(c, setMs(n, s), true)
   of mCompiles: result = semCompiles(c, setMs(n, s), flags)
diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim
index e3b598919..ed0244b0c 100644
--- a/compiler/semgnrc.nim
+++ b/compiler/semgnrc.nim
@@ -251,6 +251,29 @@ proc semGenericStmt(c: PContext, n: PNode,
     let flags = if mixinContext: flags+{withinMixin} else: flags
     for i in countup(first, sonsLen(result) - 1):
       result.sons[i] = semGenericStmt(c, result.sons[i], flags, ctx)
+  of nkBracketExpr, nkCurlyExpr:
+    result = newNodeI(nkCall, n.info)
+    result.add newIdentNode(getIdent(if n.kind == nkBracketExpr:"[]" else:"{}"),
+                            n.info)
+    for i in 0 ..< n.len: result.add(n[i])
+    result = semGenericStmt(c, result, flags, ctx)
+  of nkAsgn, nkFastAsgn:
+    checkSonsLen(n, 2)
+    let a = n.sons[0]
+    let b = n.sons[1]
+
+    let k = a.kind
+    case k
+    of nkBracketExpr, nkCurlyExpr:
+      result = newNodeI(nkCall, n.info)
+      result.add newIdentNode(getIdent(if k == nkBracketExpr:"[]=" else:"{}="),
+                              n.info)
+      for i in 0 ..< a.len: result.add(a[i])
+      result.add(b)
+      result = semGenericStmt(c, result, flags, ctx)
+    else:
+      for i in countup(0, sonsLen(n) - 1):
+        result.sons[i] = semGenericStmt(c, n.sons[i], flags, ctx)
   of nkIfStmt:
     for i in countup(0, sonsLen(n)-1):
       n.sons[i] = semGenericStmtScope(c, n.sons[i], flags, ctx)
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index 5d16470b0..65185f762 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -26,6 +26,37 @@ proc semTypeOf(c: PContext; n: PNode): PNode =
   result.add typExpr
   result.typ = makeTypeDesc(c, typExpr.typ.skipTypes({tyTypeDesc, tyIter}))
 
+type
+  SemAsgnMode = enum asgnNormal, noOverloadedSubscript, noOverloadedAsgn
+
+proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode
+proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode
+
+proc semArrGet(c: PContext; n: PNode; flags: TExprFlags): PNode =
+  result = newNodeI(nkBracketExpr, n.info)
+  for i in 1..<n.len: result.add(n[i])
+  let oldBracketExpr = c.p.bracketExpr
+  result = semSubscript(c, result, flags)
+  c.p.bracketExpr = oldBracketExpr
+  if result.isNil:
+    localError(n.info, "could not resolve: " & $n)
+    result = n
+
+proc semArrPut(c: PContext; n: PNode; flags: TExprFlags): PNode =
+  # rewrite `[]=`(a, i, x)  back to ``a[i] = x``.
+  let b = newNodeI(nkBracketExpr, n.info)
+  for i in 1..n.len-2: b.add(n[i])
+  result = newNodeI(nkAsgn, n.info, 2)
+  result.sons[0] = b
+  result.sons[1] = n.lastSon
+  result = semAsgn(c, result, noOverloadedSubscript)
+
+proc semAsgnOpr(c: PContext; n: PNode): PNode =
+  result = newNodeI(nkAsgn, n.info, 2)
+  result.sons[0] = n[1]
+  result.sons[1] = n[2]
+  result = semAsgn(c, result, noOverloadedAsgn)
+
 proc semIsPartOf(c: PContext, n: PNode, flags: TExprFlags): PNode =
   var r = isPartOf(n[1], n[2])
   result = newIntNodeT(ord(r), n)
@@ -125,6 +156,9 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
   of mTypeOf:
     checkSonsLen(n, 2)
     result = semTypeOf(c, n.sons[1])
+  of mArrGet: result = semArrGet(c, n, flags)
+  of mArrPut: result = semArrPut(c, n, flags)
+  of mAsgn: result = semAsgnOpr(c, n)
   of mIsPartOf: result = semIsPartOf(c, n, flags)
   of mTypeTrait: result = semTypeTraits(c, n)
   of mAstToStr:
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 4399c0ab0..0bb65dc57 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -1033,6 +1033,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
                  "signature for 'deepCopy' must be proc[T: ptr|ref](x: T): T")
     incl(s.flags, sfUsed)
   of "=":
+    if s.magic == mAsgn: return
     incl(s.flags, sfUsed)
     let t = s.typ
     if t.len == 3 and t.sons[0] == nil and t.sons[1].kind == tyVar:
diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim
index 84ba49e0c..642fcb527 100644
--- a/compiler/semtempl.nim
+++ b/compiler/semtempl.nim
@@ -281,6 +281,35 @@ proc semTemplBodySons(c: var TemplCtx, n: PNode): PNode =
   for i in 0.. < n.len:
     result.sons[i] = semTemplBody(c, n.sons[i])
 
+proc wrapInBind(c: var TemplCtx; n: PNode; opr: string): PNode =
+  let ident = getIdent(opr)
+  if ident.id in c.toInject: return n
+
+  let s = searchInScopes(c.c, ident)
+  if s != nil:
+    var callee: PNode
+    if contains(c.toBind, s.id):
+      callee = symChoice(c.c, n, s, scClosed)
+    elif contains(c.toMixin, s.name.id):
+      callee = symChoice(c.c, n, s, scForceOpen)
+    elif s.owner == c.owner and sfGenSym in s.flags:
+      # template tmp[T](x: var seq[T]) =
+      # var yz: T
+      incl(s.flags, sfUsed)
+      callee = newSymNode(s, n.info)
+      styleCheckUse(n.info, s)
+    else:
+      callee = semTemplSymbol(c.c, n, s)
+
+    let call = newNodeI(nkCall, n.info)
+    call.add(callee)
+    for i in 0 .. n.len-1: call.add(n[i])
+    result = newNodeI(nkBind, n.info, 2)
+    result.sons[0] = n
+    result.sons[1] = call
+  else:
+    result = n
+
 proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
   result = n
   semIdeForTemplateOrGenericCheck(n, c.cursorInBody)
@@ -423,6 +452,28 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
     result.sons[1] = semTemplBody(c, n.sons[1])
   of nkPragma:
     result = onlyReplaceParams(c, n)
+  of nkBracketExpr, nkCurlyExpr:
+    result = newNodeI(nkCall, n.info)
+    result.add newIdentNode(getIdent(if n.kind == nkBracketExpr:"[]" else:"{}"),
+                            n.info)
+    for i in 0 ..< n.len: result.add(n[i])
+    result = semTemplBodySons(c, result)
+  of nkAsgn, nkFastAsgn:
+    checkSonsLen(n, 2)
+    let a = n.sons[0]
+    let b = n.sons[1]
+
+    let k = a.kind
+    case k
+    of nkBracketExpr, nkCurlyExpr:
+      result = newNodeI(nkCall, n.info)
+      result.add newIdentNode(getIdent(if k == nkBracketExpr:"[]=" else:"{}="),
+                              n.info)
+      for i in 0 ..< a.len: result.add(a[i])
+      result.add(b)
+    else:
+      result = n
+    result = semTemplBodySons(c, result)
   else:
     # dotExpr is ambiguous: note that we explicitly allow 'x.TemplateParam',
     # so we use the generic code for nkDotExpr too
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 2ee17fcaf..17e642226 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -1149,7 +1149,17 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
     else:
       result = semAnonTuple(c, n, prev)
   of nkCallKinds:
-    if isRange(n):
+    let x = n[0]
+    let ident = case x.kind
+                of nkIdent: x.ident
+                of nkSym: x.sym.name
+                of nkClosedSymChoice, nkOpenSymChoice: x[0].sym.name
+                else: nil
+    if ident != nil and ident.s == "[]":
+      let b = newNodeI(nkBracketExpr, n.info)
+      for i in 1..<n.len: b.add(n[i])
+      result = semTypeNode(c, b, prev)
+    elif ident != nil and ident.id == ord(wDotDot):
       result = semRangeAux(c, n, prev)
     elif n[0].kind notin nkIdentKinds:
       result = semTypeExpr(c, n)
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 61f1a7444..5b111d8bc 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -265,6 +265,9 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1;
 
 proc typeRel*(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation
 proc concreteType(c: TCandidate, t: PType): PType =
+  # currently `[]=` is defined rather sloppily in system.nim, so we have
+  # a special type matching rule for it:
+  if c.calleeSym != nil and c.calleeSym.magic == mArrPut: return t
   case t.kind
   of tyArrayConstr:
     # make it an array
@@ -1691,6 +1694,9 @@ 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 == mArrGet:
+    m.state = csMatch
+    return
   var marker = initIntSet()
   matchesAux(c, n, nOrig, m, marker)
   if m.state == csNoMatch: return
diff --git a/lib/system.nim b/lib/system.nim
index 1890ce5be..cd94cfeaf 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -239,6 +239,14 @@ type
   seq*{.magic: "Seq".}[T]  ## Generic type to construct sequences.
   set*{.magic: "Set".}[T]  ## Generic type to construct bit sets.
 
+when defined(nimArrIdx):
+  # :array|openarray|string|seq|cstring|tuple
+  proc `[]`*[I: Ordinal;T](a: T; i: I): T {.
+    noSideEffect, magic: "ArrGet".}
+  proc `[]=`*[I: Ordinal;T,S](a: var T; i: I;
+    x: S) {.noSideEffect, magic: "ArrPut".}
+  proc `=`*[T](dest: var T; src: T) {.noSideEffect, magic: "Asgn".}
+
 type
   Slice*[T] = object ## builtin slice type
     a*, b*: T        ## the bounds
diff --git a/todo.txt b/todo.txt
index 91c6f1625..306b7008e 100644
--- a/todo.txt
+++ b/todo.txt
@@ -24,7 +24,6 @@ version 1.0
 - The bitwise 'not' operator will be renamed to 'bnot' to
   prevent 'not 4 == 5' from compiling. -> requires 'mixin' annotation for procs!
 - split docgen into separate tool
-- special rule for ``[]=``, items, pairs
 - BUG: echo with template `$`*(info: TLineInfo): expr = toFileLineCol(info)
 - make 'nil' work for 'add':
   - resizeString
diff --git a/web/news.txt b/web/news.txt
index c786d7d5a..fd0cf8d8a 100644
--- a/web/news.txt
+++ b/web/news.txt
@@ -95,6 +95,9 @@ News
 
   - The compiler now supports a new configuration system based on
     `NimScript <docs/nims.html>`_.
+  - The compiler finally considers symbol binding rules in templates and
+    generics for overloaded ``[]``, ``[]=``, ``{}``, ``{}=`` operators
+    (issue `#2599 <https://github.com/nim-lang/Nim/issues/2599>`_).
 
 
   Language Additions