first attempt to fix 'a[i]' handling in generics
This commit is contained in:
parent
2a797c362a
commit
8ef66b973d
13 changed files with 153 additions and 7 deletions
|
|
@ -1110,7 +1110,7 @@ proc rawNewModule(module: PSym, filename: string): BModule =
|
||||||
|
|
||||||
proc nullify[T](arr: var T) =
|
proc nullify[T](arr: var T) =
|
||||||
for i in low(arr)..high(arr):
|
for i in low(arr)..high(arr):
|
||||||
arr[i] = nil
|
arr[i] = Rope(nil)
|
||||||
|
|
||||||
proc resetModule*(m: BModule) =
|
proc resetModule*(m: BModule) =
|
||||||
# between two compilations in CAAS mode, we can throw
|
# between two compilations in CAAS mode, we can throw
|
||||||
|
|
|
||||||
|
|
@ -92,3 +92,4 @@ proc initDefines*() =
|
||||||
defineSymbol("nimvarargstyped")
|
defineSymbol("nimvarargstyped")
|
||||||
defineSymbol("nimtypedescfixed")
|
defineSymbol("nimtypedescfixed")
|
||||||
defineSymbol("nimKnowsNimvm")
|
defineSymbol("nimKnowsNimvm")
|
||||||
|
defineSymbol("nimArrIdx")
|
||||||
|
|
|
||||||
|
|
@ -308,7 +308,10 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
|
||||||
let gp = finalCallee.ast.sons[genericParamsPos]
|
let gp = finalCallee.ast.sons[genericParamsPos]
|
||||||
if gp.kind != nkEmpty:
|
if gp.kind != nkEmpty:
|
||||||
if x.calleeSym.kind notin {skMacro, skTemplate}:
|
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:
|
else:
|
||||||
# For macros and templates, the resolved generic params
|
# For macros and templates, the resolved generic params
|
||||||
# are added as normal params.
|
# are added as normal params.
|
||||||
|
|
|
||||||
|
|
@ -1250,7 +1250,7 @@ proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} =
|
||||||
template resultTypeIsInferrable(typ: PType): expr =
|
template resultTypeIsInferrable(typ: PType): expr =
|
||||||
typ.isMetaType and typ.kind != tyTypeDesc
|
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)
|
checkSonsLen(n, 2)
|
||||||
var a = n.sons[0]
|
var a = n.sons[0]
|
||||||
case a.kind
|
case a.kind
|
||||||
|
|
@ -1273,12 +1273,15 @@ proc semAsgn(c: PContext, n: PNode): PNode =
|
||||||
# --> `[]=`(a, i, x)
|
# --> `[]=`(a, i, x)
|
||||||
let oldBracketExpr = c.p.bracketExpr
|
let oldBracketExpr = c.p.bracketExpr
|
||||||
a = semSubscript(c, a, {efLValue})
|
a = semSubscript(c, a, {efLValue})
|
||||||
if a == nil:
|
if a == nil and mode != noOverloadedSubscript:
|
||||||
result = buildOverloadedSubscripts(n.sons[0], getIdent"[]=")
|
result = buildOverloadedSubscripts(n.sons[0], getIdent"[]=")
|
||||||
add(result, n[1])
|
add(result, n[1])
|
||||||
result = semExprNoType(c, result)
|
result = semExprNoType(c, result)
|
||||||
c.p.bracketExpr = oldBracketExpr
|
c.p.bracketExpr = oldBracketExpr
|
||||||
return result
|
return result
|
||||||
|
elif a == nil:
|
||||||
|
localError(n.info, "could not resolve: " & $n[0])
|
||||||
|
return n
|
||||||
c.p.bracketExpr = oldBracketExpr
|
c.p.bracketExpr = oldBracketExpr
|
||||||
of nkCurlyExpr:
|
of nkCurlyExpr:
|
||||||
# a{i} = x --> `{}=`(a, i, x)
|
# a{i} = x --> `{}=`(a, i, x)
|
||||||
|
|
@ -1323,7 +1326,8 @@ proc semAsgn(c: PContext, n: PNode): PNode =
|
||||||
typeMismatch(n, lhs.typ, rhs.typ)
|
typeMismatch(n, lhs.typ, rhs.typ)
|
||||||
|
|
||||||
n.sons[1] = fitNode(c, le, rhs)
|
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])
|
return overloadedAsgn(c, lhs, n.sons[1])
|
||||||
|
|
||||||
fixAbstractType(c, n)
|
fixAbstractType(c, n)
|
||||||
|
|
@ -1715,6 +1719,9 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||||
of mTypeOf:
|
of mTypeOf:
|
||||||
checkSonsLen(n, 2)
|
checkSonsLen(n, 2)
|
||||||
result = semTypeOf(c, n.sons[1])
|
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 mDefined: result = semDefined(c, setMs(n, s), false)
|
||||||
of mDefinedInScope: result = semDefined(c, setMs(n, s), true)
|
of mDefinedInScope: result = semDefined(c, setMs(n, s), true)
|
||||||
of mCompiles: result = semCompiles(c, setMs(n, s), flags)
|
of mCompiles: result = semCompiles(c, setMs(n, s), flags)
|
||||||
|
|
|
||||||
|
|
@ -251,6 +251,29 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||||
let flags = if mixinContext: flags+{withinMixin} else: flags
|
let flags = if mixinContext: flags+{withinMixin} else: flags
|
||||||
for i in countup(first, sonsLen(result) - 1):
|
for i in countup(first, sonsLen(result) - 1):
|
||||||
result.sons[i] = semGenericStmt(c, result.sons[i], flags, ctx)
|
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:
|
of nkIfStmt:
|
||||||
for i in countup(0, sonsLen(n)-1):
|
for i in countup(0, sonsLen(n)-1):
|
||||||
n.sons[i] = semGenericStmtScope(c, n.sons[i], flags, ctx)
|
n.sons[i] = semGenericStmtScope(c, n.sons[i], flags, ctx)
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,37 @@ proc semTypeOf(c: PContext; n: PNode): PNode =
|
||||||
result.add typExpr
|
result.add typExpr
|
||||||
result.typ = makeTypeDesc(c, typExpr.typ.skipTypes({tyTypeDesc, tyIter}))
|
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 =
|
proc semIsPartOf(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
var r = isPartOf(n[1], n[2])
|
var r = isPartOf(n[1], n[2])
|
||||||
result = newIntNodeT(ord(r), n)
|
result = newIntNodeT(ord(r), n)
|
||||||
|
|
@ -125,6 +156,9 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||||
of mTypeOf:
|
of mTypeOf:
|
||||||
checkSonsLen(n, 2)
|
checkSonsLen(n, 2)
|
||||||
result = semTypeOf(c, n.sons[1])
|
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 mIsPartOf: result = semIsPartOf(c, n, flags)
|
||||||
of mTypeTrait: result = semTypeTraits(c, n)
|
of mTypeTrait: result = semTypeTraits(c, n)
|
||||||
of mAstToStr:
|
of mAstToStr:
|
||||||
|
|
|
||||||
|
|
@ -1033,6 +1033,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
|
||||||
"signature for 'deepCopy' must be proc[T: ptr|ref](x: T): T")
|
"signature for 'deepCopy' must be proc[T: ptr|ref](x: T): T")
|
||||||
incl(s.flags, sfUsed)
|
incl(s.flags, sfUsed)
|
||||||
of "=":
|
of "=":
|
||||||
|
if s.magic == mAsgn: return
|
||||||
incl(s.flags, sfUsed)
|
incl(s.flags, sfUsed)
|
||||||
let t = s.typ
|
let t = s.typ
|
||||||
if t.len == 3 and t.sons[0] == nil and t.sons[1].kind == tyVar:
|
if t.len == 3 and t.sons[0] == nil and t.sons[1].kind == tyVar:
|
||||||
|
|
|
||||||
|
|
@ -281,6 +281,35 @@ proc semTemplBodySons(c: var TemplCtx, n: PNode): PNode =
|
||||||
for i in 0.. < n.len:
|
for i in 0.. < n.len:
|
||||||
result.sons[i] = semTemplBody(c, n.sons[i])
|
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 =
|
proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
semIdeForTemplateOrGenericCheck(n, c.cursorInBody)
|
semIdeForTemplateOrGenericCheck(n, c.cursorInBody)
|
||||||
|
|
@ -423,6 +452,28 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
|
||||||
result.sons[1] = semTemplBody(c, n.sons[1])
|
result.sons[1] = semTemplBody(c, n.sons[1])
|
||||||
of nkPragma:
|
of nkPragma:
|
||||||
result = onlyReplaceParams(c, n)
|
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:
|
else:
|
||||||
# dotExpr is ambiguous: note that we explicitly allow 'x.TemplateParam',
|
# dotExpr is ambiguous: note that we explicitly allow 'x.TemplateParam',
|
||||||
# so we use the generic code for nkDotExpr too
|
# so we use the generic code for nkDotExpr too
|
||||||
|
|
|
||||||
|
|
@ -1149,7 +1149,17 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
else:
|
else:
|
||||||
result = semAnonTuple(c, n, prev)
|
result = semAnonTuple(c, n, prev)
|
||||||
of nkCallKinds:
|
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)
|
result = semRangeAux(c, n, prev)
|
||||||
elif n[0].kind notin nkIdentKinds:
|
elif n[0].kind notin nkIdentKinds:
|
||||||
result = semTypeExpr(c, n)
|
result = semTypeExpr(c, n)
|
||||||
|
|
|
||||||
|
|
@ -265,6 +265,9 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1;
|
||||||
|
|
||||||
proc typeRel*(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation
|
proc typeRel*(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation
|
||||||
proc concreteType(c: TCandidate, t: PType): PType =
|
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
|
case t.kind
|
||||||
of tyArrayConstr:
|
of tyArrayConstr:
|
||||||
# make it an array
|
# make it an array
|
||||||
|
|
@ -1691,6 +1694,9 @@ proc partialMatch*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
|
||||||
matchesAux(c, n, nOrig, m, marker)
|
matchesAux(c, n, nOrig, m, marker)
|
||||||
|
|
||||||
proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
|
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()
|
var marker = initIntSet()
|
||||||
matchesAux(c, n, nOrig, m, marker)
|
matchesAux(c, n, nOrig, m, marker)
|
||||||
if m.state == csNoMatch: return
|
if m.state == csNoMatch: return
|
||||||
|
|
|
||||||
|
|
@ -239,6 +239,14 @@ type
|
||||||
seq*{.magic: "Seq".}[T] ## Generic type to construct sequences.
|
seq*{.magic: "Seq".}[T] ## Generic type to construct sequences.
|
||||||
set*{.magic: "Set".}[T] ## Generic type to construct bit sets.
|
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
|
type
|
||||||
Slice*[T] = object ## builtin slice type
|
Slice*[T] = object ## builtin slice type
|
||||||
a*, b*: T ## the bounds
|
a*, b*: T ## the bounds
|
||||||
|
|
|
||||||
1
todo.txt
1
todo.txt
|
|
@ -24,7 +24,6 @@ version 1.0
|
||||||
- The bitwise 'not' operator will be renamed to 'bnot' to
|
- The bitwise 'not' operator will be renamed to 'bnot' to
|
||||||
prevent 'not 4 == 5' from compiling. -> requires 'mixin' annotation for procs!
|
prevent 'not 4 == 5' from compiling. -> requires 'mixin' annotation for procs!
|
||||||
- split docgen into separate tool
|
- split docgen into separate tool
|
||||||
- special rule for ``[]=``, items, pairs
|
|
||||||
- BUG: echo with template `$`*(info: TLineInfo): expr = toFileLineCol(info)
|
- BUG: echo with template `$`*(info: TLineInfo): expr = toFileLineCol(info)
|
||||||
- make 'nil' work for 'add':
|
- make 'nil' work for 'add':
|
||||||
- resizeString
|
- resizeString
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,9 @@ News
|
||||||
|
|
||||||
- The compiler now supports a new configuration system based on
|
- The compiler now supports a new configuration system based on
|
||||||
`NimScript <docs/nims.html>`_.
|
`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
|
Language Additions
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue