diff options
Diffstat (limited to 'compiler/semexprs.nim')
-rw-r--r-- | compiler/semexprs.nim | 75 |
1 files changed, 53 insertions, 22 deletions
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index f727fcbfd..54a844035 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -157,6 +157,51 @@ proc semSymChoice(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: P if result.kind == nkSym: result = semSym(c, result, result.sym, flags) +proc semOpenSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags, expectedType: PType): PNode = + ## sem a node marked `nfOpenSym`, that is, captured symbols that can be + ## replaced by newly injected symbols in generics. `s` must be the captured + ## symbol if the original node is an `nkSym` node; and `nil` if it is an + ## `nkOpenSymChoice`, in which case only non-overloadable injected symbols + ## will be considered. + result = nil + let ident = n.getPIdent + assert ident != nil + let id = newIdentNode(ident, n.info) + c.isAmbiguous = false + let s2 = qualifiedLookUp(c, id, {}) + # for `nkSym`, the first found symbol being different and unambiguous is + # enough to replace the original + # for `nkOpenSymChoice`, the first found symbol must be non-overloadable, + # since otherwise we have to use regular `nkOpenSymChoice` functionality + if s2 != nil and not c.isAmbiguous and + ((s == nil and s2.kind notin OverloadableSyms) or + (s != nil and s2 != s)): + # only consider symbols defined under current proc: + var o = s2.owner + while o != nil: + if o == c.p.owner: + if genericsOpenSym in c.features: + result = semExpr(c, id, flags, expectedType) + return + else: + var msg = + "a new symbol '" & ident.s & "' has been injected during " & + "instantiation of " & c.p.owner.name.s & ", however " + if s == nil: + msg.add( + "overloads of " & ident.s & " will be used instead; " & + "either enable --experimental:genericsOpenSym to use the " & + "injected symbol or `bind` this symbol explicitly") + else: + msg.add( + getSymRepr(c.config, s) & " captured at " & + "the proc declaration will be used instead; " & + "either enable --experimental:genericsOpenSym to use the " & + "injected symbol or `bind` this captured symbol explicitly") + message(c.config, n.info, warnGenericsIgnoredInjection, msg) + break + o = o.owner + proc inlineConst(c: PContext, n: PNode, s: PSym): PNode {.inline.} = result = copyTree(s.astdef) if result.isNil: @@ -3141,31 +3186,17 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType if isSymChoice(result): result = semSymChoice(c, result, flags, expectedType) of nkClosedSymChoice, nkOpenSymChoice: - result = semSymChoice(c, result, flags, expectedType) + if n.kind == nkOpenSymChoice and nfOpenSym in n.flags: + result = semOpenSym(c, n, nil, flags, expectedType) + if result != nil: + return + result = semSymChoice(c, n, flags, expectedType) of nkSym: let s = n.sym if nfOpenSym in n.flags: - let id = newIdentNode(s.name, n.info) - c.isAmbiguous = false - let s2 = qualifiedLookUp(c, id, {}) - if s2 != nil and s2 != s and not c.isAmbiguous: - # only consider symbols defined under current proc: - var o = s2.owner - while o != nil: - if o == c.p.owner: - if genericsOpenSym in c.features: - result = semExpr(c, id, flags, expectedType) - return - else: - message(c.config, n.info, warnGenericsIgnoredInjection, - "a new symbol '" & s.name.s & "' has been injected during " & - "instantiation of " & c.p.owner.name.s & ", " & - "however " & getSymRepr(c.config, s) & " captured at " & - "the proc declaration will be used instead; " & - "either enable --experimental:genericsOpenSym to use the " & - "injected symbol or `bind` this captured symbol explicitly") - break - o = o.owner + result = semOpenSym(c, n, s, flags, expectedType) + if result != nil: + return # because of the changed symbol binding, this does not mean that we # don't have to check the symbol for semantics here again! result = semSym(c, n, s, flags) |