diff --git a/compiler/ast.nim b/compiler/ast.nim index 155af637580a..e8d3d697efa5 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -691,8 +691,7 @@ type mInstantiationInfo, mGetTypeInfo, mGetTypeInfoV2, mNimvm, mIntDefine, mStrDefine, mBoolDefine, mRunnableExamples, mException, mBuiltinType, mSymOwner, mUncheckedArray, mGetImplTransf, - mSymIsInstantiationOf, mNodeId - + mSymIsInstantiationOf, mNodeId, mOverloadResolve, # things that we can evaluate safely at compile time, even if not asked for it: const diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index bdecd7e532ec..e8fcbf916768 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -133,3 +133,4 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasCustomLiterals") defineSymbol("nimHasUnifiedTuple") defineSymbol("nimHasIterable") + defineSymbol("himHasOverloadResolve") diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 15a22c77875b..ed096b0f06fa 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -495,7 +495,7 @@ proc lookUp*(c: PContext, n: PNode): PSym = type TLookupFlag* = enum - checkAmbiguity, checkUndeclared, checkModule, checkPureEnumFields + checkAmbiguity, checkUndeclared, checkModule, checkPureEnumFields, checkOverloadResolve proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym = const allExceptModule = {low(TSymKind)..high(TSymKind)} - {skModule, skPackage} @@ -520,7 +520,7 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym = if amb and checkAmbiguity in flags: errorUseQualifier(c, n.info, candidates) - if result == nil and checkUndeclared in flags: + if result == nil and checkUndeclared in flags and checkOverloadResolve notin flags: result = errorUndeclaredIdentifierHint(c, n, ident) elif checkAmbiguity in flags and result != nil and amb: result = errorUseQualifier(c, n.info, result, amb) @@ -541,7 +541,7 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym = result = strTableGet(c.topLevelScope.symbols, ident).skipAlias(n, c.config) else: result = someSym(c.graph, m, ident).skipAlias(n, c.config) - if result == nil and checkUndeclared in flags: + if result == nil and checkUndeclared in flags and checkOverloadResolve notin flags: result = errorUndeclaredIdentifierHint(c, n[1], ident) elif n[1].kind == nkSym: result = n[1].sym diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 8f29bdf328f8..e329570552b8 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -410,7 +410,8 @@ proc resolveOverloads(c: PContext, n, orig: PNode, pickBest(callOp) if overloadsState == csEmpty and result.state == csEmpty: - if efNoUndeclared notin flags: # for tests/pragmas/tcustom_pragma.nim + if {efNoUndeclared, efOverloadResolve} * flags == {}: + # for tests/pragmas/tcustom_pragma.nim # xxx adapt/use errorUndeclaredIdentifierHint(c, n, f.ident) localError(c.config, n.info, getMsgDiagnostic(c, flags, n, f)) return @@ -520,6 +521,7 @@ proc semResolvedCall(c: PContext, x: TCandidate, markUsed(c, info, finalCallee) onUse(info, finalCallee) assert finalCallee.ast != nil + if efOverloadResolve in flags: return newSymNode(finalCallee, info) if x.hasFauxMatch: result = x.call result[0] = newSymNode(finalCallee, getCallLineInfo(result[0])) @@ -568,6 +570,7 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode, filter: TSymKinds, flags: TExprFlags): PNode {.nosinks.} = var errors: CandidateErrors = @[] # if efExplain in flags: @[] else: nil var r = resolveOverloads(c, n, nOrig, filter, flags, errors, efExplain in flags) + template canError(): bool = {efNoUndeclared, efOverloadResolve} * flags == {} if r.state == csMatch: # this may be triggered, when the explain pragma is used if errors.len > 0: @@ -595,14 +598,14 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode, # repeat the overload resolution, # this time enabling all the diagnostic output (this should fail again) discard semOverloadedCall(c, n, nOrig, filter, flags + {efExplain}) - elif efNoUndeclared notin flags: + elif canError(): notFoundError(c, n, errors) else: if efExplain notin flags: # repeat the overload resolution, # this time enabling all the diagnostic output (this should fail again) discard semOverloadedCall(c, n, nOrig, filter, flags + {efExplain}) - elif efNoUndeclared notin flags: + elif canError(): notFoundError(c, n, errors) proc explicitGenericInstError(c: PContext; n: PNode): PNode = diff --git a/compiler/semdata.nim b/compiler/semdata.nim index daf1265e8744..a2470832aa62 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -69,9 +69,11 @@ type efWantStmt, efAllowStmt, efDetermineType, efExplain, efAllowDestructor, efWantValue, efOperand, efNoSemCheck, efNoEvaluateGeneric, efInCall, efFromHlo, efNoSem2Check, - efNoUndeclared + efNoUndeclared, # Use this if undeclared identifiers should not raise an error during # overload resolution. + efOverloadResolve, + # for `mOverloadResolve` evaluation, resolves `foo` in `foo(args)` TExprFlags* = set[TExprFlag] diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 256c008c9313..23ff47489d0b 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -66,6 +66,7 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = proc semExprCheck(c: PContext, n: PNode, flags: TExprFlags): PNode = rejectEmptyNode(n) result = semExpr(c, n, flags+{efWantValue}) + if result == nil: return errorNode(c, n) let isEmpty = result.kind == nkEmpty @@ -865,6 +866,7 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode, {skProc, skFunc, skMethod, skConverter, skMacro, skTemplate}, flags) if result != nil: + if efOverloadResolve in flags: return if result[0].kind != nkSym: internalError(c.config, "semOverloadedCallAnalyseEffects") return @@ -947,7 +949,8 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = else: n[0] = n0 else: - n[0] = semExpr(c, n[0], {efInCall}) + n[0] = semExpr(c, n[0], {efInCall} + flags * {efOverloadResolve}) + if n[0] == nil and efOverloadResolve in flags: return errorNode(c, n) let t = n[0].typ if t != nil and t.kind in {tyVar, tyLent}: n[0] = newDeref(n[0]) @@ -1031,6 +1034,7 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = let nOrig = n.copyTree #semLazyOpAux(c, n) result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags) + if efOverloadResolve in flags: return if result != nil: result = afterCallActions(c, result, nOrig, flags) else: result = errorNode(c, n) @@ -1358,7 +1362,14 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = suggestExpr(c, n) if exactEquals(c.config.m.trackPos, n[1].info): suggestExprNoCheck(c, n) - var s = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared, checkModule}) + var flags2 = {checkAmbiguity, checkUndeclared, checkModule} + if efOverloadResolve in flags: flags2.incl checkOverloadResolve + var s = qualifiedLookUp(c, n, flags2) + if efOverloadResolve in flags and n.kind == nkDotExpr: + var m = qualifiedLookUp(c, n[0], (flags2*{checkUndeclared})+{checkModule}) + if m != nil and m.kind == skModule: # got `mymodule.someident` + if s == nil: return nil + else: return symChoice(c, n, s, scClosed) if s != nil: if s.kind in OverloadableSyms: result = symChoice(c, n, s, scClosed) @@ -2174,11 +2185,37 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode = # we replace this node by a 'true' or 'false' node: if n.len != 2: return semDirectOp(c, n, flags) - result = newIntNode(nkIntLit, ord(tryExpr(c, n[1], flags) != nil)) result.info = n.info result.typ = getSysType(c.graph, n.info, tyBool) +proc semOverloadResolve(c: PContext, n: PNode, flags: TExprFlags, isTopLevel: bool): PNode = + var n = n + if isTopLevel: + if n.len != 2: + localError(c.config, n.info, "semOverloadResolve: got" & $n.len) + return + n = n[1] + if n.kind notin {nkIdent,nkDotExpr,nkAccQuoted} + nkCallKinds - {nkHiddenCallConv}: + localError(c.config, n.info, "expected routine, got " & $n.kind) + return errorNode(c, n) + if n.kind == nkDotExpr: + # so that this doesn't compile: `overloadExists(nonexistant().foo)` + n[0] = semExpr(c, n[0], flags) + let flags = flags + {efWantIterator, efOverloadResolve} + result = semExpr(c, n, flags) + if result == nil or result.kind == nkEmpty: + if isTopLevel: + result = newNodeIT(nkNilLit, n.info, getSysType(c.graph, n.info, tyNil)) + elif result.kind == nkClosedSymChoice: + # avoids degenerating symchoice to a sym + let typ = newTypeS(tyTuple, c) + let result0 = result + result = newNodeIT(nkTupleConstr, n.info, typ) + result.add result0 + else: + doAssert result.kind == nkSym, $result.kind + proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode = if n.len == 3: # XXX ugh this is really a hack: shallowCopy() can be overloaded only @@ -2250,6 +2287,9 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = of mCompiles: markUsed(c, n.info, s) result = semCompiles(c, setMs(n, s), flags) + of mOverloadResolve: + markUsed(c, n.info, s) + result = semOverloadResolve(c, setMs(n, s), flags, isTopLevel = true) of mIs: markUsed(c, n.info, s) result = semIs(c, setMs(n, s), flags) @@ -2694,15 +2734,18 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = if nfSem in n.flags: return case n.kind of nkIdent, nkAccQuoted: - let checks = if efNoEvaluateGeneric in flags: + var checks = if efNoEvaluateGeneric in flags: {checkUndeclared, checkPureEnumFields} elif efInCall in flags: {checkUndeclared, checkModule, checkPureEnumFields} else: {checkUndeclared, checkModule, checkAmbiguity, checkPureEnumFields} + if efOverloadResolve in flags: checks.incl checkOverloadResolve var s = qualifiedLookUp(c, n, checks) + if efOverloadResolve in flags and s == nil: return nil if c.matchedConcept == nil: semCaptureSym(s, c.p.owner) - if s.kind in {skProc, skFunc, skMethod, skConverter, skIterator}: + if efOverloadResolve in flags: result = symChoice(c, n, s, scClosed) + elif s.kind in {skProc, skFunc, skMethod, skConverter, skIterator}: #performProcvarCheck(c, n, s) result = symChoice(c, n, s, scClosed) if result.kind == nkSym: @@ -2758,7 +2801,12 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = result = semFieldAccess(c, n, flags) if result.kind == nkDotCall: result.transitionSonsKind(nkCall) - result = semExpr(c, result, flags) + if efOverloadResolve in flags: + result = semOverloadResolve(c, result, flags, isTopLevel = false) + else: + result = semExpr(c, result, flags) + elif result.kind == nkDotExpr and efOverloadResolve in flags: + result = result[1] of nkBind: message(c.config, n.info, warnDeprecated, "bind is deprecated") result = semExpr(c, n[0], flags) @@ -2779,7 +2827,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = checkMinSonsLen(n, 1, c.config) #when defined(nimsuggest): # if gIdeCmd == ideCon and c.config.m.trackPos == n.info: suggestExprNoCheck(c, n) - let mode = if nfDotField in n.flags: {} else: {checkUndeclared} + let mode = if nfDotField in n.flags or efOverloadResolve in flags: {} else: {checkUndeclared} c.isAmbiguous = false var s = qualifiedLookUp(c, n[0], mode) if s != nil: @@ -2815,8 +2863,11 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = result = semDirectOp(c, n, flags) else: result = semIndirectOp(c, n, flags) - - if nfDefaultRefsParam in result.flags: + if result == nil: + # dbg "D20210413T120912" # PRTEMP + discard + elif nfDefaultRefsParam in result.flags: + # if nfDefaultRefsParam in result.flags: result = result.copyTree #XXX: Figure out what causes default param nodes to be shared.. (sigmatch bug?) # We've found a default value that references another param. # See the notes in `hoistParamsUsedInDefault` for more details. diff --git a/lib/system.nim b/lib/system.nim index 6e84aca667b4..7ab942ee8f39 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2793,6 +2793,14 @@ type NimNode* {.magic: "PNimrodNode".} = ref NimNodeObj ## Represents a Nim AST node. Macros operate on this type. +when defined(himHasOverloadResolve): + proc resolveSymbol*(x: untyped): NimNode {.magic: "OverloadResolve", noSideEffect, compileTime.} = + ## resolves a symbol given an expression, eg: in `resolveSymbol(foo(args))` + ## it will find the symbol that would be called after overload resolution, + ## without calling it. Unlike `compiles(foo(args))`, the body is not analyzed. + ## Also works with `compiles(mymod.mysym)` to return the symChoice overload + ## set. + when defined(nimV2): import system/repr_v2 export repr_v2 diff --git a/tests/magics/mresolve_overloads.nim b/tests/magics/mresolve_overloads.nim new file mode 100644 index 000000000000..a05a736ca4e6 --- /dev/null +++ b/tests/magics/mresolve_overloads.nim @@ -0,0 +1,8 @@ +let mfoo1* = [1,2] ## c1 +var mfoo2* = "asdf" ## c2 +const mfoo3* = 'a' ## c3 + +proc `@@@`*(a: int) = discard +proc `@@@`*(a: float) = discard +proc `@@@`*[T: Ordinal](a: T) = discard + diff --git a/tests/magics/mresolves.nim b/tests/magics/mresolves.nim new file mode 100644 index 000000000000..849edbbdd27c --- /dev/null +++ b/tests/magics/mresolves.nim @@ -0,0 +1,103 @@ +import std/macros + +macro overloadExistsImpl(x: typed): bool = + newLit(x != nil) + +template overloadExists*(a: untyped): bool = + overloadExistsImpl(resolveSymbol(a)) + +type InstantiationInfo = type(instantiationInfo()) + +proc toStr(info: InstantiationInfo | LineInfo): string = + const offset = 1 + result = info.filename & ":" & $info.line & ":" & $(info.column + offset) + +proc inspectImpl*(s: var string, a: NimNode, resolveLet: bool) = + var a = a + if resolveLet: + a = a.getImpl + a = a[2] + case a.kind + of nnkClosedSymChoice: + s.add "closedSymChoice:" + for ai in a: + s.add "\n " + inspectImpl(s, ai, false) + of nnkSym: + var a2 = a.getImpl + const callables = {nnkProcDef, nnkMethodDef, nnkConverterDef, nnkMacroDef, nnkTemplateDef, nnkIteratorDef} + if a2.kind in callables: + let a20=a2 + a2 = newTree(a20.kind) + for i, ai in a20: + a2.add if i notin [6]: ai else: newEmptyNode() + s.add a2.lineInfoObj.toStr & " " & a2.repr + else: error($a.kind, a) # Error: nnkNilLit when couldn't resolve + +macro inspect*(a: typed, resolveLet: static bool = false): untyped = + var a = a + if a.kind == nnkTupleConstr: + a = a[0] + var s: string + s.add a.lineInfoObj.toStr & ": " + s.add a.repr & " = " + inspectImpl(s, a, resolveLet) + when defined(nimTestsResolvesDebug): + echo s + +template inspect2*(a: untyped): untyped = inspect(resolveSymbol(a)) + +macro fieldExistsImpl(a: typed): bool = + newLit(a.symKind == nskField) + +template fieldExists*(a: untyped): untyped = fieldExistsImpl(resolveSymbol(a)) + +macro canImportImpl(a: typed): bool = + newLit(a.symKind == nskModule) + +# can't work like that... +template canImport*(a: untyped): untyped = canImportImpl(resolveSymbol(a)) + +macro inspect3*(a: typed): untyped = + echo (a.repr, a.kind, a.typeKind) + echo a.symKind + var a2 = a.getImpl + echo a2.kind + # echo a.sym.kind + +# macro getSymImpl(a: typed): NimSym = +type SymWrap = object + s: NimSym +type SymWrap2 = object + s: int +type SymWrap3[T] = object + s: NimSym +# macro getSymImpl(a: typed): NimSym = + +type SymWrap4*[sym] = object + +# type SymWrap4b*[sym] = object +# sym2: sym + +type SymWrap4b* = object + # sym2: T + sym2: NimSym + +macro getSymImpl(a: typed): untyped = + # NimSym + let x = a.symbol + result = quote do: + SymWrap4[`x`] + +template getSym*(a: untyped): untyped = getSymImpl(resolveSymbol(a)) + +type SymInt* = distinct int +macro getSymImpl2(a: typed): untyped = + # NimSym + let x = cast[int](a.symbol) + result = quote do: + # SymWrap4b[`x`](sym2: `x`) + # SymWrap4b(sym2: `x`) + `x`.SymInt + +template getSym2*(a: untyped): untyped = getSymImpl2(resolveSymbol(a)) diff --git a/tests/magics/tresolve_overloads.nim b/tests/magics/tresolve_overloads.nim new file mode 100644 index 000000000000..abe44dbd0684 --- /dev/null +++ b/tests/magics/tresolve_overloads.nim @@ -0,0 +1,261 @@ +#[ +use -d:nimTestsResolvesDebug to make the `inspect` macro print debug info showing +resolved symbol locations, for example: + +`inspect resolveSymbol(`$`)` would print: + +Nim/tests/magics/tresolve_overloads.nim:133:28: $ = closedSymChoice: + Nim/lib/system/dollars.nim:124:1 proc `$`[T](x: set[T]): string + Nim/lib/system/dollars.nim:140:1 proc `$`[T; U](x: HSlice[T, U]): string + Nim/lib/system/dollars.nim:14:1 proc `$`(x: bool): string {.magic: "BoolToStr", noSideEffect.} +]# + +import ./mresolves +import ./mresolve_overloads + +template bail() = static: doAssert false + +proc funDecl1(a: int) {.importc.} +proc funDecl2(a: int) + +proc fun(a: int) = discard + +template fun2(a = 0) = bail() +template fun3() = bail() + +proc fun4(a: float) = discard + +proc fun4[T](a: T) = + static: echo "in fun4" + bail() + +macro fun5(a: typed): untyped = discard +macro fun6(a: untyped): untyped = discard +iterator fun7(a: int): auto = yield 1 + +proc fun8(a: int): auto = (a, "int") +proc fun8(a: float): tuple = (a,"float") +template fun8(a: string) = discard +template fun8(a: char = 'x') = discard +template fun8() = discard +macro fun8(b = 1'u8): untyped = discard +macro fun8(c: static bool): untyped = discard + +proc fun8(d: var int) = d.inc + +proc fun10[T: seq](a: T): auto = (a,) +proc fun10[T: int|float](a: T): auto = (a,) +template fun11(a: untyped): auto = (a,) + +proc main()= + block: # overloadExists with nkCall + doAssert overloadExists(fun4(1)) + doAssert not compiles(fun4(1)) + doAssert overloadExists(fun4(1)) + doAssert overloadExists(fun4(1.2)) + doAssert not overloadExists(fun4()) + doAssert not overloadExists(1 @@@ 2) + doAssert overloadExists(1 + 2) + doAssert not overloadExists('a' + 2.0) + + doAssert overloadExists(funDecl1(1)) + doAssert not overloadExists(funDecl1(1.0)) + doAssert overloadExists(funDecl2(1)) + + doAssert overloadExists(fun(1)) + doAssert overloadExists(1+1) + doAssert not overloadExists('a'+1.2) + + doAssert not overloadExists(fun(1.1)) + doAssert not overloadExists(fun(1, 2)) + doAssert overloadExists(fun2()) + doAssert overloadExists(fun2(1)) + doAssert overloadExists(fun3()) + doAssert not overloadExists(fun3(1)) + + # subtlety: if arguments for a `typed` formal param are not well typed, + # we error instead of return false + doAssert not compiles overloadExists(fun5(1 + 'a')) + + doAssert overloadExists(fun5(1 + 1)) + doAssert not overloadExists(fun5(1 + 1, 2)) + doAssert overloadExists(fun6(1 + 'a')) + doAssert not overloadExists(fun6(1 + 'a', 2)) + doAssert overloadExists(fun7(1)) + doAssert not overloadExists(fun7()) + + # generics + doAssert overloadExists(fun10(@[1])) + doAssert overloadExists(fun10(1.2)) + doAssert not overloadExists(fun10("foo")) + doAssert not overloadExists(fun10('a')) + template fun10(a: char): auto = (a,) + doAssert overloadExists(fun10('a')) + doAssert not overloadExists(fun11()) + doAssert overloadExists(fun11(1 + 'a')) + + # $ + doAssert overloadExists($12) + doAssert not overloadExists($main) + # echo + doAssert overloadExists(echo 12) + doAssert overloadExists(echo ()) + doAssert overloadExists(echo()) + doAssert not overloadExists(echo main) + doAssert not overloadExists(echo(main)) + + block: # overloadExists with nkCall dot accesors + type Foo = object + bar1: int + var foo: Foo + + template bar2(a: Foo) = discard + template bar3[T](a: T): int = 0 + + proc bar4(a: int) = discard + + template bar5(a: int) = discard + template bar5(a: Foo) = discard + + doAssert not declared(mresolve_overloads.nonexistant) + doAssert declared(mresolve_overloads.mfoo3) + doAssert not declared(foo.bar1) + doAssert not overloadExists(mresolve_overloads.nonexistant) + doAssert overloadExists(mresolve_overloads.mfoo3) + + doAssert not overloadExists(nonexistant(foo)) + doAssert not overloadExists(nonexistant()) + + doAssert not overloadExists(foo.nonexistant) + doAssert compiles(Foo().bar1) + doAssert compiles(Foo().bar1) + doAssert overloadExists(foo.bar2) + doAssert overloadExists(foo.bar3) + + doAssert not overloadExists(bar4(foo)) + doAssert not overloadExists(foo.bar4) + + proc bar4(a: Foo) = discard + + doAssert overloadExists(foo.bar4) + doAssert overloadExists(foo.bar5) + + doAssert overloadExists(foo.bar1) + doAssert overloadExists(Foo().bar1) + + doAssert not compiles(nonexistant.bar1) + doAssert not compiles overloadExists(nonexistant.bar1) + doAssert not compiles overloadExists(nonexistant().mfoo1) + doAssert not compiles overloadExists(nonexistant1().nonexistant2) + doAssert not compiles overloadExists(nonexistant().bar2) + doAssert not compiles overloadExists(nonexistant().bar1) + + doAssert declared(mresolve_overloads) + doAssert declared(fun7) + doAssert declared(foo) + doAssert declared(`bar5`) + doAssert declared(bar5) + doAssert declared(`system`) + doAssert not declared(nonexistant) + doAssert not overloadExists(nonexistant) + doAssert not overloadExists(`nonexistant`) + doAssert overloadExists(system) + doAssert overloadExists(`system`) + doAssert overloadExists(`bar5`) + doAssert overloadExists(bar5) + + block: # resolveSymbol + doAssert resolveSymbol(fun8(1))(3) == fun8(3) + inspect resolveSymbol(fun8) + + inspect resolveSymbol(fun7) + inspect resolveSymbol(fun8(1)) + inspect resolveSymbol(fun8(1.2)) + inspect resolveSymbol(fun8("asdf")) + inspect resolveSymbol(fun8('a')) + doAssert compiles(resolveSymbol(fun8('a'))) + doAssert not compiles(resolveSymbol(fun8())) # correctly would give ambiguous error + inspect resolveSymbol(fun8(b = 1)) + inspect resolveSymbol(fun8(c = false)) + inspect resolveSymbol(1.1 / 2.0) + + block: + var c1 = false + doAssert not overloadExists(fun8(c = c1)) + const c2 = false + doAssert overloadExists(fun8(c = c2)) + var c3 = 10 + doAssert overloadExists(fun8(d = c3)) + doAssert c3 == 10 + resolveSymbol(fun8(d = c3))(d = c3) + doAssert c3 == 11 + let t = resolveSymbol(fun8(d = c3)) + doAssert type(t) is proc + t(d = c3) + doAssert c3 == 12 + + block: + var z = 10 + proc fun9(z0: int) = z+=z0 + proc fun9(z0: float) = doAssert false + let t = resolveSymbol(fun9(12)) + # can't work with `const t = fun9`: invalid type for const + doAssert type(t) is proc + t(3) + doAssert z == 10+3 + inspect resolveSymbol(fun9(12)) + inspect(resolveSymbol(t), resolveLet=true) + +import std/strutils +import std/macros +import std/macros as macrosAlias + +proc main2()= + block: + inspect resolveSymbol(`@@@`) + + let t = resolveSymbol toUpper("asdf") + inspect resolveSymbol(t), resolveLet=true + doAssert t("asdf") == "ASDF" + let t2 = resolveSymbol strutils.toUpper("asdf") + inspect resolveSymbol(t2), resolveLet=true + doAssert t2("asdf") == "ASDF" + + inspect resolveSymbol(strutils.toUpper) + inspect resolveSymbol(strutils.`toUpper`) + inspect resolveSymbol(`toUpper`) + # overloaded + inspect resolveSymbol(`$`) + inspect resolveSymbol(system.`$`) + + doAssert compiles resolveSymbol(system.compiles) + inspect resolveSymbol(system.compiles) + doAssert resolveSymbol(system.nonexistant) == nil + doAssert resolveSymbol(nonexistant) == nil + + block: + template bar1(): untyped = 12 + inspect resolveSymbol(bar1) + inspect resolveSymbol(currentSourcePath) + inspect resolveSymbol(system.currentSourcePath) + doAssert resolveSymbol(system.currentSourcePath)() == currentSourcePath() + inspect resolveSymbol(system.uint16) + inspect resolveSymbol(system.cint) + inspect resolveSymbol(cint) + inspect resolveSymbol(system.off) + inspect resolveSymbol(newLit(true)) + inspect resolveSymbol(mfoo1) + inspect resolveSymbol(mfoo2) + inspect resolveSymbol(mfoo3) + inspect resolveSymbol(mresolve_overloads.mfoo3) + inspect resolveSymbol(macros.nnkCallKinds) + + ## module + inspect resolveSymbol(macros) + inspect resolveSymbol(macrosAlias) + +proc funDecl2(a: int) = discard + +main() +static: main() +main2()