Skip to content

Commit

Permalink
cleanups
Browse files Browse the repository at this point in the history
  • Loading branch information
timotheecour committed Mar 22, 2020
1 parent f9df9e1 commit 2c27bc3
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 45 deletions.
1 change: 0 additions & 1 deletion compiler/ast.nim
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,6 @@ type
nfDefaultRefsParam # a default param value references another parameter
# the flag is applied to proc default values and to calls
nfExecuteOnReload # A top-level statement that will be executed during reloads
nfOverloadResolve # return resolved `foo` in `foo(args)`

TNodeFlags* = set[TNodeFlag]
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: ~40)
Expand Down
7 changes: 4 additions & 3 deletions compiler/lookups.nim
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,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}
Expand All @@ -313,7 +313,8 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
result = searchInScopes(c, ident, allExceptModule).skipAlias(n, c.config)
if result == nil and checkPureEnumFields in flags:
result = strTableGet(c.pureEnumFields, ident)
if result == nil and checkUndeclared in flags:
# if result == nil and checkUndeclared in flags:
if result == nil and checkUndeclared in flags and checkOverloadResolve notin flags:
fixSpelling(n, ident, searchInScopes)
errorUndeclaredIdentifier(c, n.info, ident.s)
result = errorSym(c, n)
Expand All @@ -338,7 +339,7 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
result = strTableGet(c.topLevelScope.symbols, ident).skipAlias(n, c.config)
else:
result = strTableGet(m.tab, ident).skipAlias(n, c.config)
if result == nil and checkUndeclared in flags and nfOverloadResolve notin n.flags:
if result == nil and checkUndeclared in flags and checkOverloadResolve notin flags:
fixSpelling(n[1], ident, searchInScopes)
errorUndeclaredIdentifier(c, n[1].info, ident.s)
result = errorSym(c, n[1])
Expand Down
8 changes: 4 additions & 4 deletions compiler/semcall.nim
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,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
localError(c.config, n.info, getMsgDiagnostic(c, flags, n, f))
return
elif result.state != csMatch:
Expand Down Expand Up @@ -488,7 +489,7 @@ proc semResolvedCall(c: PContext, x: TCandidate,
markUsed(c, info, finalCallee)
onUse(info, finalCallee)
assert finalCallee.ast != nil
if nfOverloadResolve in n.flags: return newSymNode(finalCallee, info)
if efOverloadResolve in flags: return newSymNode(finalCallee, info)
if x.hasFauxMatch:
result = x.call
result[0] = newSymNode(finalCallee, getCallLineInfo(result[0]))
Expand Down Expand Up @@ -534,8 +535,7 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
filter: TSymKinds, flags: TExprFlags): PNode =
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 notin flags and nfOverloadResolve notin n.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:
Expand Down
5 changes: 4 additions & 1 deletion compiler/semdata.nim
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,12 @@ type
efWantStmt, efAllowStmt, efDetermineType, efExplain,
efAllowDestructor, efWantValue, efOperand, efNoSemCheck,
efNoEvaluateGeneric, efInCall, efFromHlo,
efNoUndeclared
efNoUndeclared,
# Use this if undeclared identifiers should not raise an error during
# overload resolution.
efOverloadResolve,
# for `mOverloadResolve` evaluation
# return resolved `foo` in `foo(args)`

TExprFlags* = set[TExprFlag]

Expand Down
83 changes: 61 additions & 22 deletions compiler/semexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
# this module does the semantic checking for expressions
# included from sem.nim

import std/wrapnils

const
errExprXHasNoType = "expression '$1' has no type (or is ambiguous)"
errXExpectsTypeOrValue = "'$1' expects a type or value"
Expand Down Expand Up @@ -60,8 +62,11 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result.typ = errorType(c)

proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
echo0b (flags, c.config$n.info)
rejectEmptyNode(n)
echo0b ()
result = semExpr(c, n, flags+{efWantValue})
echo0b ()
if result == nil: return errorNode(c, n)
if result.kind == nkEmpty:
# do not produce another redundant error message:
Expand Down Expand Up @@ -833,7 +838,7 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
{skProc, skFunc, skMethod, skConverter, skMacro, skTemplate}, flags)

if result != nil:
if nfOverloadResolve in n.flags: return
if efOverloadResolve in flags: return
if result[0].kind != nkSym:
internalError(c.config, "semOverloadedCallAnalyseEffects")
return
Expand Down Expand Up @@ -908,11 +913,20 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
else:
n[0] = n0
else:
echo0b (flags, n[0].renderTree, n.renderTree, n.kind, n[0].kind)
var flags2 = {efInCall}
if nfOverloadResolve in n.flags:
flags2.incl {efNoUndeclared}
if efOverloadResolve in flags and efOperand notin flags: flags2.incl efOverloadResolve
n[0] = semExpr(c, n[0], flags2)
if n[0] == nil and nfOverloadResolve in n.flags: return nil
# n[0] = semExpr(c, n[0], {efInCall} + flags * {efOverloadResolve})
# n[0] = semExpr(c, n[0], {efInCall})
if efOverloadResolve in flags:
echo0b (flags, n[0] == nil, )
if n[0] != nil:
echo0b n[0].kind
if n[0] == nil and efOverloadResolve in flags:
echo0b "errorNode"
return errorNode(c, n)
# return nil
let t = n[0].typ
if t != nil and t.kind in {tyVar, tyLent}:
n[0] = newDeref(n[0])
Expand Down Expand Up @@ -986,7 +1000,7 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
let nOrig = n.copyTree
#semLazyOpAux(c, n)
result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
if nfOverloadResolve in n.flags: return
if efOverloadResolve in flags: return
if result != nil: result = afterCallActions(c, result, nOrig, flags)
else: result = errorNode(c, n)

Expand Down Expand Up @@ -1278,8 +1292,11 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
if exactEquals(c.config.m.trackPos, n[1].info): suggestExprNoCheck(c, n)

var flags2 = {checkAmbiguity, checkUndeclared, checkModule}
if efOverloadResolve in flags:
flags2.incl checkOverloadResolve
# flags2.excl checkUndeclared # PRTEMP
var s = qualifiedLookUp(c, n, flags2)
if nfOverloadResolve in n.flags and n.kind == nkDotExpr:
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
Expand Down Expand Up @@ -2117,29 +2134,47 @@ proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =

proc semOverloadResolve(c: PContext, n: PNode, flags: TExprFlags, isTopLevel: bool): PNode =
var n = n
echo0b (c.config$n.info, n.kind, flags, isTopLevel)
if isTopLevel:
if n.len != 2:
localError(c.config, n.info, "semOverloadResolve: got" & $n.len)
return
n = n[1]
n.flags.incl nfOverloadResolve
let nKind = n.kind
if n.kind notin {nkIdent,nkDotExpr,nkAccQuoted} + nkCallKinds - {nkHiddenCallConv}:
localError(c.config, n.info, "expected routine, got " & $n.kind)
else:
# so that it also works for iterators and allows nonexistant fields and procs
let flags = flags + {efWantIterator, efNoUndeclared}
result = semExpr(c, n, flags)
if result != nil:
doAssert result.kind in {nkSym, nkClosedSymChoice}, $result.kind
if result == nil:
return

# PRTEMP: remove efOperand stuff
# let flags = flags + {efWantIterator, efOverloadResolve}
if n.kind == nkDotExpr:
# let flags = flags + {efWantIterator, efOverloadResolve} - {efOperand}
# result = semExpr(c, n[0], flags)
# result = semExpr(c, n[0], flags)
n[0] = semExpr(c, n[0], flags)
let flags = flags + {efWantIterator, efOverloadResolve} - {efOperand}
result = semExpr(c, n, flags)

echo0b (result == nil, ?.result.kind, nKind, flags)
# if result != nil and result.kind == nkEmpty and nKind == nkDotExpr:
when false:
if (result == nil or result.kind == nkEmpty) and nKind == nkDotExpr:
# localError()
# localError(c.config, n.info, "invalid expression for OverloadResolve: " & $n.renderTree)
localError(c.config, n.info, "invalid expression for OverloadResolve")
return result # PRTEMP
if result == nil or result.kind == nkEmpty:
# doAssert isTopLevel # PRTEMP
if isTopLevel:
result = newNodeIT(nkNilLit, n.info, getSysType(c.graph, n.info, tyNil))
elif result.kind != nkSym:
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:
Expand Down Expand Up @@ -2607,11 +2642,16 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
{checkUndeclared, checkModule, checkPureEnumFields}
else:
{checkUndeclared, checkModule, checkAmbiguity, checkPureEnumFields}
if efNoUndeclared in flags: checks.excl checkUndeclared
# if efOverloadResolve in flags and efInCall notin flags:
if efOverloadResolve in flags and efInCall in flags:
# PRTEMP efOverloadResolve checkOverloadResolve
# checks.excl checkUndeclared
checks.incl checkOverloadResolve
echo0b (checks, flags)
var s = qualifiedLookUp(c, n, checks)
if efNoUndeclared in flags and s == nil: return nil
if efOverloadResolve in flags and s == nil: return nil
if c.matchedConcept == nil: semCaptureSym(s, c.p.owner)
if nfOverloadResolve in n.flags: result = symChoice(c, n, s, scClosed)
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)
Expand Down Expand Up @@ -2665,15 +2705,14 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
of nkCharLit:
if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyChar)
of nkDotExpr:
let hasOverloadResolve = nfOverloadResolve in n.flags
result = semFieldAccess(c, n, flags)
if result.kind == nkDotCall:
result.transitionSonsKind(nkCall)
if hasOverloadResolve:
if efOverloadResolve in flags:
result = semOverloadResolve(c, result, flags, isTopLevel = false)
else:
result = semExpr(c, result, flags)
elif result.kind == nkDotExpr and hasOverloadResolve:
elif result.kind == nkDotExpr and efOverloadResolve in flags:
result = result[1]
of nkBind:
message(c.config, n.info, warnDeprecated, "bind is deprecated")
Expand All @@ -2692,7 +2731,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, nfOverloadResolve} * n.flags != {}: {} else: {checkUndeclared}
let mode = if nfDotField in n.flags or efOverloadResolve in flags: {} else: {checkUndeclared}
var s = qualifiedLookUp(c, n[0], mode)
if s != nil:
#if c.config.cmd == cmdPretty and n[0].kind == nkDotExpr:
Expand Down
2 changes: 1 addition & 1 deletion compiler/vm.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1112,7 +1112,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
var a = regs[rb].node
if a.kind == nkVarTy: a = a[0]
if a.kind == nkSym:
regs[ra].node = if a.sym.ast.isNil: newNodeI(nkNilLit, a.sym.info) # preserve `info`, eg for module symbols
regs[ra].node = if a.sym.ast.isNil: newNode(nkNilLit)
else: copyTree(a.sym.ast)
regs[ra].node.flags.incl nfIsRef
else:
Expand Down
6 changes: 3 additions & 3 deletions tests/magics/mresolve_overloads.nim
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
let foo1* = [1,2] ## c1
var foo2* = "asdf" ## c2
const foo3* = 'a' ## c3
let mfoo1* = [1,2] ## c1
var mfoo2* = "asdf" ## c2
const mfoo3* = 'a' ## c3

proc `@@@`*(a: int) = discard
proc `@@@`*(a: float) = discard
Expand Down
30 changes: 20 additions & 10 deletions tests/magics/tresolve_overloads.nim
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ proc main()=
doAssert overloadExists(fun4(1))
doAssert overloadExists(fun4(1.2))
doAssert not overloadExists(fun4())
# doAssert not overloadExists(nonexistant(1)) # should we error with `Error: undeclared identifier: 'nonexistant'` ? A: probly should just return false, eg: imagine for: ` 1 @ 2`
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))
Expand Down Expand Up @@ -92,12 +94,14 @@ proc main()=
template bar5(a: Foo) = discard

doAssert not declared(mresolve_overloads.nonexistant)
doAssert declared(mresolve_overloads.foo3)
doAssert declared(mresolve_overloads.mfoo3)
doAssert not declared(foo.bar1)
doAssert not overloadExists(mresolve_overloads.nonexistant)
doAssert overloadExists(mresolve_overloads.foo3)
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)
Expand All @@ -116,8 +120,14 @@ proc main()=
doAssert overloadExists(Foo().bar1)

doAssert not compiles(nonexistant.bar1)
doAssert not compiles(overloadExists(nonexistant.bar1))
doAssert not compiles(overloadExists(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 not overloadExists(nonexistant) # PRTEMP

block: # resolveSymbol
doAssert resolveSymbol(fun8(1))(3) == fun8(3)
Expand Down Expand Up @@ -186,7 +196,7 @@ proc main2()=
doAssert compiles resolveSymbol(system.compiles)
inspect resolveSymbol(system.compiles)
doAssert resolveSymbol(system.nonexistant) == nil
doAssert resolveSymbol(nonexistant) == nil
# doAssert resolveSymbol(nonexistant) == nil

block:
template bar1(): untyped = 12
Expand All @@ -199,10 +209,10 @@ proc main2()=
inspect resolveSymbol(cint)
inspect resolveSymbol(system.off)
inspect resolveSymbol(newLit(true))
inspect resolveSymbol(foo1)
inspect resolveSymbol(foo2)
inspect resolveSymbol(foo3)
inspect resolveSymbol(mresolve_overloads.foo3)
inspect resolveSymbol(mfoo1)
inspect resolveSymbol(mfoo2)
inspect resolveSymbol(mfoo3)
inspect resolveSymbol(mresolve_overloads.mfoo3)
inspect resolveSymbol(macros.nnkCallKinds)

## module
Expand Down

0 comments on commit 2c27bc3

Please sign in to comment.