implement the 'bind' statement for generics, it was an oversight that this was never implemented (#14584)
This commit is contained in:
parent
51b71e35f2
commit
66c50c2ffc
2 changed files with 28 additions and 4 deletions
|
|
@ -28,7 +28,7 @@ proc getIdentNode(c: PContext; n: PNode): PNode =
|
||||||
|
|
||||||
type
|
type
|
||||||
GenericCtx = object
|
GenericCtx = object
|
||||||
toMixin: IntSet
|
toMixin, toBind: IntSet
|
||||||
cursorInBody: bool # only for nimsuggest
|
cursorInBody: bool # only for nimsuggest
|
||||||
bracketExpr: PNode
|
bracketExpr: PNode
|
||||||
|
|
||||||
|
|
@ -124,7 +124,7 @@ proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||||
if ident.id notin ctx.toMixin and withinMixin notin flags:
|
if ident.id notin ctx.toMixin and withinMixin notin flags:
|
||||||
errorUndeclaredIdentifier(c, n.info, ident.s)
|
errorUndeclaredIdentifier(c, n.info, ident.s)
|
||||||
else:
|
else:
|
||||||
if withinBind in flags:
|
if withinBind in flags or s.id in ctx.toBind:
|
||||||
result = symChoice(c, n, s, scClosed)
|
result = symChoice(c, n, s, scClosed)
|
||||||
elif s.isMixedIn:
|
elif s.isMixedIn:
|
||||||
result = symChoice(c, n, s, scForceOpen)
|
result = symChoice(c, n, s, scForceOpen)
|
||||||
|
|
@ -155,7 +155,7 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||||
var s = searchInScopes(c, ident, routineKinds).skipAlias(n, c.config)
|
var s = searchInScopes(c, ident, routineKinds).skipAlias(n, c.config)
|
||||||
if s != nil:
|
if s != nil:
|
||||||
isMacro = s.kind in {skTemplate, skMacro}
|
isMacro = s.kind in {skTemplate, skMacro}
|
||||||
if withinBind in flags:
|
if withinBind in flags or s.id in ctx.toBind:
|
||||||
result = newDot(result, symChoice(c, n, s, scClosed))
|
result = newDot(result, symChoice(c, n, s, scClosed))
|
||||||
elif s.isMixedIn:
|
elif s.isMixedIn:
|
||||||
result = newDot(result, symChoice(c, n, s, scForceOpen))
|
result = newDot(result, symChoice(c, n, s, scForceOpen))
|
||||||
|
|
@ -211,6 +211,8 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||||
result = semGenericStmt(c, n[0], flags+{withinBind}, ctx)
|
result = semGenericStmt(c, n[0], flags+{withinBind}, ctx)
|
||||||
of nkMixinStmt:
|
of nkMixinStmt:
|
||||||
result = semMixinStmt(c, n, ctx.toMixin)
|
result = semMixinStmt(c, n, ctx.toMixin)
|
||||||
|
of nkBindStmt:
|
||||||
|
result = semBindStmt(c, n, ctx.toBind)
|
||||||
of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkCommand, nkCallStrLit:
|
of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkCommand, nkCallStrLit:
|
||||||
# check if it is an expression macro:
|
# check if it is an expression macro:
|
||||||
checkMinSonsLen(n, 1, c.config)
|
checkMinSonsLen(n, 1, c.config)
|
||||||
|
|
@ -227,7 +229,10 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||||
if s != nil:
|
if s != nil:
|
||||||
incl(s.flags, sfUsed)
|
incl(s.flags, sfUsed)
|
||||||
mixinContext = s.magic in {mDefined, mDefinedInScope, mCompiles, mAstToStr}
|
mixinContext = s.magic in {mDefined, mDefinedInScope, mCompiles, mAstToStr}
|
||||||
let sc = symChoice(c, fn, s, if s.isMixedIn: scForceOpen else: scOpen)
|
let whichChoice = if s.id in ctx.toBind: scClosed
|
||||||
|
elif s.isMixedIn: scForceOpen
|
||||||
|
else: scOpen
|
||||||
|
let sc = symChoice(c, fn, s, whichChoice)
|
||||||
case s.kind
|
case s.kind
|
||||||
of skMacro:
|
of skMacro:
|
||||||
if macroToExpand(s) and sc.safeLen <= 1:
|
if macroToExpand(s) and sc.safeLen <= 1:
|
||||||
|
|
@ -492,12 +497,14 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||||
proc semGenericStmt(c: PContext, n: PNode): PNode =
|
proc semGenericStmt(c: PContext, n: PNode): PNode =
|
||||||
var ctx: GenericCtx
|
var ctx: GenericCtx
|
||||||
ctx.toMixin = initIntSet()
|
ctx.toMixin = initIntSet()
|
||||||
|
ctx.toBind = initIntSet()
|
||||||
result = semGenericStmt(c, n, {}, ctx)
|
result = semGenericStmt(c, n, {}, ctx)
|
||||||
semIdeForTemplateOrGeneric(c, result, ctx.cursorInBody)
|
semIdeForTemplateOrGeneric(c, result, ctx.cursorInBody)
|
||||||
|
|
||||||
proc semConceptBody(c: PContext, n: PNode): PNode =
|
proc semConceptBody(c: PContext, n: PNode): PNode =
|
||||||
var ctx: GenericCtx
|
var ctx: GenericCtx
|
||||||
ctx.toMixin = initIntSet()
|
ctx.toMixin = initIntSet()
|
||||||
|
ctx.toBind = initIntSet()
|
||||||
result = semGenericStmt(c, n, {withinConcept}, ctx)
|
result = semGenericStmt(c, n, {withinConcept}, ctx)
|
||||||
semIdeForTemplateOrGeneric(c, result, ctx.cursorInBody)
|
semIdeForTemplateOrGeneric(c, result, ctx.cursorInBody)
|
||||||
|
|
||||||
|
|
|
||||||
17
tests/lookups/tbind_for_generics.nim
Normal file
17
tests/lookups/tbind_for_generics.nim
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
discard """
|
||||||
|
errormsg: "type mismatch: got <Foo, Foo>"
|
||||||
|
line: 8
|
||||||
|
"""
|
||||||
|
proc g[T](x: T) =
|
||||||
|
bind `+`
|
||||||
|
# because we bind `+` here, we must not find the `+` for 'Foo' below:
|
||||||
|
echo x + x
|
||||||
|
|
||||||
|
type
|
||||||
|
Foo = object
|
||||||
|
a: int
|
||||||
|
|
||||||
|
proc `+`(a, b: Foo): Foo = Foo(a: a.a+b.a)
|
||||||
|
|
||||||
|
g(3)
|
||||||
|
g(Foo(a: 8))
|
||||||
Loading…
Add table
Add a link
Reference in a new issue