From 3e67494a9b77fb47a847c3e6d71898e193686c8f Mon Sep 17 00:00:00 2001 From: metagn <10591326+metagn@users.noreply.github.com> Date: Sat, 23 Sep 2023 05:25:02 +0300 Subject: [PATCH] open syms fixes #11184, fixes #22605, fixes #20000 --- compiler/ast.nim | 3 +- compiler/lookups.nim | 25 +++++- compiler/semexprs.nim | 37 +++++---- compiler/semgnrc.nim | 8 +- compiler/semtempl.nim | 9 ++- compiler/sigmatch.nim | 2 +- tests/lookups/mopensym.nim | 23 ++++++ tests/lookups/topensym.nim | 124 +++++++++++++++++++++++++++++ tests/template/tinnerouterproc.nim | 11 ++- 9 files changed, 220 insertions(+), 22 deletions(-) create mode 100644 tests/lookups/mopensym.nim create mode 100644 tests/lookups/topensym.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index dd7561264a804..7fe1b5a583455 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -518,6 +518,7 @@ type nfFirstWrite # this node is a first write nfHasComment # node has a comment nfSkipFieldChecking # node skips field visable checking + nfOpenSym # node is a captured sym but can be overriden by local symbols TNodeFlags* = set[TNodeFlag] TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 47) @@ -1092,7 +1093,7 @@ const nfIsRef, nfIsPtr, nfPreventCg, nfLL, nfFromTemplate, nfDefaultRefsParam, nfExecuteOnReload, nfLastRead, - nfFirstWrite, nfSkipFieldChecking} + nfFirstWrite, nfSkipFieldChecking, nfOpenSym} namePos* = 0 patternPos* = 1 # empty except for term rewriting macros genericParamsPos* = 2 diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 2bdf3a1e07259..f20a459c2b476 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -315,6 +315,7 @@ type m*: PSym mode*: TOverloadIterMode symChoiceIndex*: int + fallback: PSym currentScope: PScope importIdx: int marked: IntSet @@ -590,6 +591,10 @@ proc lookUp*(c: PContext, n: PNode): PSym = if result == nil: result = errorUndeclaredIdentifierHint(c, n, n.ident) of nkSym: result = n.sym + if nfOpenSym in n.flags: + let alt = searchInScopes(c, result.name, amb) + if alt != nil and alt != result and not amb: + result = alt of nkAccQuoted: var ident = considerQuotedIdent(c, n) result = searchInScopes(c, ident, amb) @@ -639,6 +644,11 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym = c.isAmbiguous = amb of nkSym: result = n.sym + if nfOpenSym in n.flags: + var amb = false + let alt = searchInScopes(c, result.name, amb) + if alt != nil and alt != result and not amb: + result = alt of nkDotExpr: result = nil var m = qualifiedLookUp(c, n[0], (flags * {checkUndeclared}) + {checkModule}) @@ -700,8 +710,16 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = return nil of nkSym: - result = n.sym - o.mode = oimDone + if nfOpenSym notin n.flags: + result = n.sym + o.mode = oimDone + else: + result = initOverloadIter(o, c, newIdentNode(n.sym.name, n.info)) + if result == nil: + result = n.sym + o.mode = oimDone + elif n.sym != result: + o.fallback = n.sym of nkDotExpr: result = nil o.mode = oimOtherModule @@ -798,6 +816,9 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = result = nextOverloadIterImports(o, c, n) else: result = nil + if result == nil and o.fallback != nil and o.fallback.id notin o.marked: + result = o.fallback + o.fallback = nil of oimSelfModule: result = nextIdentIter(o.it, c.topLevelScope.symbols) of oimOtherModule: diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 590d2610be92a..dc7b90d437718 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -55,16 +55,16 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = result = semExpr(c, n, flags + {efOperand, efAllowSymChoice}) if result.typ != nil: # XXX tyGenericInst here? - if result.typ.kind == tyProc and hasUnresolvedParams(result, {efOperand}): - #and tfUnresolved in result.typ.flags: - let owner = result.typ.owner - let err = - # consistent error message with evaltempl/semMacroExpr - if owner != nil and owner.kind in {skTemplate, skMacro}: - errMissingGenericParamsForTemplate % n.renderTree - else: - errProcHasNoConcreteType % n.renderTree - localError(c.config, n.info, err) + #if result.typ.kind == tyProc and hasUnresolvedParams(result, {efOperand}): + # #and tfUnresolved in result.typ.flags: + # let owner = result.typ.owner + # let err = + # # consistent error message with evaltempl/semMacroExpr + # if owner != nil and owner.kind in {skTemplate, skMacro}: + # errMissingGenericParamsForTemplate % n.renderTree + # else: + # errProcHasNoConcreteType % n.renderTree + # localError(c.config, n.info, err) if result.typ.kind in {tyVar, tyLent}: result = newDeref(result) elif {efWantStmt, efAllowStmt} * flags != {}: result.typ = newTypeS(tyVoid, c) @@ -101,8 +101,9 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType elif result.typ.kind == tyError: # associates the type error to the current owner result.typ = errorType(c) - elif efTypeAllowed in flags and result.typ.kind == tyProc and - hasUnresolvedParams(result, {}): + elif {efTypeAllowed, efOperand} * flags != {} and + result.typ.kind == tyProc and + containsGenericType(result.typ): # mirrored with semOperand but only on efTypeAllowed let owner = result.typ.owner let err = @@ -1024,7 +1025,8 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags; expectedTy of skMacro: result = semMacroExpr(c, result, orig, callee, flags, expectedType) of skTemplate: result = semTemplateExpr(c, result, callee, flags, expectedType) else: - semFinishOperands(c, result) + if callee.magic != mArrGet: + semFinishOperands(c, result) activate(c, result) fixAbstractType(c, result) analyseIfAddressTakenInCall(c, result) @@ -1284,6 +1286,12 @@ proc readTypeParameter(c: PContext, typ: PType, proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = result = nil assert n.kind in nkIdentKinds + {nkDotExpr} + if n.kind == nkSym and nfOpenSym in n.flags: + let id = newIdentNode(n.sym.name, n.info) + c.isAmbiguous = false + let s2 = qualifiedLookUp(c, id, {}) + if s2 != nil and s2 != sym and not c.isAmbiguous: + return semSym(c, id, s2, flags) let s = getGenSym(c, sym) case s.kind of skConst: @@ -1542,8 +1550,7 @@ proc builtinFieldAccess(c: PContext; n: PNode; flags: var TExprFlags): PNode = proc dotTransformation(c: PContext, n: PNode): PNode = if isSymChoice(n[1]) or - # generics usually leave field names as symchoices, but not types - (n[1].kind == nkSym and n[1].sym.kind == skType): + (n[1].kind == nkSym and n[1].sym.kind in routineKinds + {skType}): result = newNodeI(nkDotCall, n.info) result.add n[1] result.add copyTree(n[0]) diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index aa05f8d85d701..0e8893c7cae18 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -66,7 +66,9 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, if fromDotExpr: result = symChoice(c, n, s, scForceOpen) if result.kind == nkOpenSymChoice and result.len == 1: - result.transitionSonsKind(nkClosedSymChoice) + result = result[0] + result.flags.incl nfOpenSym + result.typ = nil else: result = symChoice(c, n, s, scOpen) case s.kind @@ -110,6 +112,9 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, else: result = newSymNode(s, n.info) onUse(n.info, s) + if withinMixin in flags and result.kind == nkSym: + result.flags.incl nfOpenSym + result.typ = nil proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags, ctx: var GenericCtx): PNode = @@ -148,6 +153,7 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags, var s = qualifiedLookUp(c, n, luf) if s != nil: + isMacro = s.kind in {skTemplate, skMacro} result = semGenericStmtSymbol(c, n, s, ctx, flags) else: n[0] = semGenericStmt(c, n[0], flags, ctx) diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index 3256b8d85783a..45e668584946f 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -67,6 +67,9 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule; # for instance 'nextTry' is both in tables.nim and astalgo.nim ... if not isField or sfGenSym notin s.flags: result = newSymNode(s, info) + if r in {scOpen, scForceOpen}: + result.flags.incl nfOpenSym + result.typ = nil markUsed(c, info, s) onUse(info, s) else: @@ -255,6 +258,9 @@ proc semTemplSymbol(c: PContext, n: PNode, s: PSym; isField: bool): PNode = # field access (dot expr) will be handled by builtinFieldAccess if not isField: styleCheckUse(c, n.info, s) + if result.kind == nkSym: + result.flags.incl nfOpenSym + result.typ = nil proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode = result = n @@ -568,7 +574,8 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode = inc c.noGenSym result[1] = semTemplBody(c, n[1]) dec c.noGenSym - if result[1].kind == nkSym and result[1].sym.kind in routineKinds: + if false and result[1].kind == nkSym and result[1].sym.kind in routineKinds and + nfOpenSym notin result[1].flags: # prevent `dotTransformation` from rewriting this node to `nkIdent` # by making it a symchoice # in generics this becomes `nkClosedSymChoice` but this breaks code diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 1cf29dcfd465b..cbeadc394a496 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -2644,7 +2644,7 @@ proc semFinishOperands*(c: PContext, n: PNode) = # this needs to be called to ensure that after overloading resolution every # argument has been sem'checked: for i in 1..