mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-05 04:27:44 +00:00
implements overloadable enum values; WIP (#18470)
* implements overloadable enum values * simpler code
This commit is contained in:
@@ -993,7 +993,7 @@ type
|
||||
|
||||
const
|
||||
OverloadableSyms* = {skProc, skFunc, skMethod, skIterator,
|
||||
skConverter, skModule, skTemplate, skMacro}
|
||||
skConverter, skModule, skTemplate, skMacro, skEnumField}
|
||||
|
||||
GenericTypes*: TTypeKinds = {tyGenericInvocation, tyGenericBody,
|
||||
tyGenericParam}
|
||||
|
||||
@@ -177,13 +177,16 @@ iterator allSyms*(c: PContext): (PSym, int, bool) =
|
||||
|
||||
proc someSymFromImportTable*(c: PContext; name: PIdent; ambiguous: var bool): PSym =
|
||||
var marked = initIntSet()
|
||||
var symSet = OverloadableSyms
|
||||
if overloadableEnums notin c.features:
|
||||
symSet.excl skEnumField
|
||||
result = nil
|
||||
for im in c.imports.mitems:
|
||||
for s in symbols(im, marked, name, c.graph):
|
||||
if result == nil:
|
||||
result = s
|
||||
else:
|
||||
if s.kind notin OverloadableSyms or result.kind notin OverloadableSyms:
|
||||
if s.kind notin symSet or result.kind notin symSet:
|
||||
ambiguous = true
|
||||
|
||||
proc searchInScopes*(c: PContext, s: PIdent; ambiguous: var bool): PSym =
|
||||
@@ -384,7 +387,7 @@ proc mergeShadowScope*(c: PContext) =
|
||||
##
|
||||
## Merges:
|
||||
## shadow -> shadow: add symbols to the parent but check for redefinitions etc
|
||||
## shadow -> non-shadow: the above, but also handle exports and all that
|
||||
## shadow -> non-shadow: the above, but also handle exports and all that
|
||||
let shadowScope = c.currentScope
|
||||
c.rawCloseScope
|
||||
for sym in shadowScope.symbols:
|
||||
|
||||
@@ -203,7 +203,8 @@ type
|
||||
vmopsDanger,
|
||||
strictFuncs,
|
||||
views,
|
||||
strictNotNil
|
||||
strictNotNil,
|
||||
overloadableEnums
|
||||
|
||||
LegacyFeature* = enum
|
||||
allowSemcheckedAstModification,
|
||||
|
||||
@@ -90,6 +90,12 @@ proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode =
|
||||
# error correction:
|
||||
result = copyTree(arg)
|
||||
result.typ = formal
|
||||
elif arg.kind in nkSymChoices and formal.skipTypes(abstractInst).kind == tyEnum:
|
||||
# Pick the right 'sym' from the sym choice by looking at 'formal' type:
|
||||
for ch in arg:
|
||||
if sameType(ch.typ, formal):
|
||||
return getConstExpr(c.module, ch, c.idgen, c.graph)
|
||||
typeMismatch(c.config, info, formal, arg.typ, arg)
|
||||
else:
|
||||
result = indexTypesMatch(c, formal, arg.typ, arg)
|
||||
if result == nil:
|
||||
@@ -356,6 +362,8 @@ proc semConstExpr(c: PContext, n: PNode): PNode =
|
||||
if e == nil:
|
||||
localError(c.config, n.info, errConstExprExpected)
|
||||
return n
|
||||
if e.kind in nkSymChoices and e[0].typ.skipTypes(abstractInst).kind == tyEnum:
|
||||
return e
|
||||
result = getConstExpr(c.module, e, c.idgen, c.graph)
|
||||
if result == nil:
|
||||
#if e.kind == nkEmpty: globalError(n.info, errConstExprExpected)
|
||||
|
||||
@@ -2707,6 +2707,34 @@ proc getNilType(c: PContext): PType =
|
||||
result.align = c.config.target.ptrSize.int16
|
||||
c.nilTypeCache = result
|
||||
|
||||
proc enumFieldSymChoice(c: PContext, n: PNode, s: PSym): PNode =
|
||||
var o: TOverloadIter
|
||||
var i = 0
|
||||
var a = initOverloadIter(o, c, n)
|
||||
while a != nil:
|
||||
if a.kind in OverloadableSyms-{skModule}:
|
||||
inc(i)
|
||||
if i > 1: break
|
||||
a = nextOverloadIter(o, c, n)
|
||||
let info = getCallLineInfo(n)
|
||||
if i <= 1:
|
||||
if sfGenSym notin s.flags:
|
||||
result = newSymNode(s, info)
|
||||
markUsed(c, info, s)
|
||||
onUse(info, s)
|
||||
else:
|
||||
result = n
|
||||
else:
|
||||
result = newNodeIT(nkClosedSymChoice, info, newTypeS(tyNone, c))
|
||||
a = initOverloadIter(o, c, n)
|
||||
while a != nil:
|
||||
if a.kind in OverloadableSyms-{skModule}:
|
||||
incl(a.flags, sfUsed)
|
||||
markOwnerModuleAsUsed(c, a)
|
||||
result.add newSymNode(a, info)
|
||||
onUse(info, a)
|
||||
a = nextOverloadIter(o, c, n)
|
||||
|
||||
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
when defined(nimCompilerStacktraceHints):
|
||||
setFrameMsg c.config$n.info & " " & $n.kind
|
||||
@@ -2730,7 +2758,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
{checkUndeclared, checkModule, checkAmbiguity, checkPureEnumFields}
|
||||
var s = qualifiedLookUp(c, n, checks)
|
||||
if c.matchedConcept == nil: semCaptureSym(s, c.p.owner)
|
||||
if s.kind in {skProc, skFunc, skMethod, skConverter, skIterator}:
|
||||
case s.kind
|
||||
of skProc, skFunc, skMethod, skConverter, skIterator:
|
||||
#performProcvarCheck(c, n, s)
|
||||
result = symChoice(c, n, s, scClosed)
|
||||
if result.kind == nkSym:
|
||||
@@ -2740,6 +2769,11 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
# "procs literals" are 'owned'
|
||||
if optOwnedRefs in c.config.globalOptions:
|
||||
result.typ = makeVarType(c, result.typ, tyOwned)
|
||||
of skEnumField:
|
||||
if overloadableEnums in c.features:
|
||||
result = enumFieldSymChoice(c, n, s)
|
||||
else:
|
||||
result = semSym(c, n, s, flags)
|
||||
else:
|
||||
result = semSym(c, n, s, flags)
|
||||
of nkSym:
|
||||
|
||||
@@ -490,6 +490,18 @@ proc semLowerLetVarCustomPragma(c: PContext, a: PNode, n: PNode): PNode =
|
||||
ret.add result
|
||||
result = semExprNoType(c, ret)
|
||||
|
||||
proc errorSymChoiceUseQualifier(c: PContext; n: PNode) =
|
||||
assert n.kind in nkSymChoices
|
||||
var err = "ambiguous identifier: '" & $n[0] & "'"
|
||||
var i = 0
|
||||
for child in n:
|
||||
let candidate = child.sym
|
||||
if i == 0: err.add " -- use one of the following:\n"
|
||||
else: err.add "\n"
|
||||
err.add " " & candidate.owner.name.s & "." & candidate.name.s
|
||||
inc i
|
||||
localError(c.config, n.info, errGenerated, err)
|
||||
|
||||
proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||
if n.len == 1:
|
||||
result = semLowerLetVarCustomPragma(c, n[0], n)
|
||||
@@ -514,7 +526,9 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||
if a[^1].kind != nkEmpty:
|
||||
def = semExprWithType(c, a[^1], {})
|
||||
|
||||
if def.kind == nkSym and def.sym.kind in {skTemplate, skMacro}:
|
||||
if def.kind in nkSymChoices and def[0].typ.skipTypes(abstractInst).kind == tyEnum:
|
||||
errorSymChoiceUseQualifier(c, def)
|
||||
elif def.kind == nkSym and def.sym.kind in {skTemplate, skMacro}:
|
||||
typFlags.incl taIsTemplateOrMacro
|
||||
elif def.typ.kind == tyTypeDesc and c.p.owner.kind != skMacro:
|
||||
typFlags.incl taProcContextIsNotMacro
|
||||
|
||||
@@ -144,8 +144,13 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
|
||||
styleCheckDef(c.config, e)
|
||||
onDef(e.info, e)
|
||||
if sfGenSym notin e.flags:
|
||||
if not isPure: addInterfaceDecl(c, e)
|
||||
else: declarePureEnumField(c, e)
|
||||
if not isPure:
|
||||
if overloadableEnums in c.features:
|
||||
addInterfaceOverloadableSymAt(c, c.currentScope, e)
|
||||
else:
|
||||
addInterfaceDecl(c, e)
|
||||
else:
|
||||
declarePureEnumField(c, e)
|
||||
if isPure and (let conflict = strTableInclReportConflict(symbols, e); conflict != nil):
|
||||
wrongRedefinition(c, e.info, e.name.s, conflict.info)
|
||||
inc(counter)
|
||||
@@ -240,7 +245,8 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
|
||||
|
||||
if not hasUnknownTypes:
|
||||
if not sameType(rangeT[0].skipTypes({tyRange}), rangeT[1].skipTypes({tyRange})):
|
||||
localError(c.config, n.info, "type mismatch")
|
||||
typeMismatch(c.config, n.info, rangeT[0], rangeT[1], n)
|
||||
|
||||
elif not isOrdinalType(rangeT[0]) and rangeT[0].kind notin {tyFloat..tyFloat128} or
|
||||
rangeT[0].kind == tyBool:
|
||||
localError(c.config, n.info, "ordinal or float type expected")
|
||||
|
||||
@@ -2197,7 +2197,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
|
||||
var best = -1
|
||||
for i in 0..<arg.len:
|
||||
if arg[i].sym.kind in {skProc, skFunc, skMethod, skConverter,
|
||||
skIterator, skMacro, skTemplate}:
|
||||
skIterator, skMacro, skTemplate, skEnumField}:
|
||||
copyCandidate(z, m)
|
||||
z.callee = arg[i].typ
|
||||
if tfUnresolved in z.callee.flags: continue
|
||||
|
||||
48
tests/enum/toverloadable_enums.nim
Normal file
48
tests/enum/toverloadable_enums.nim
Normal file
@@ -0,0 +1,48 @@
|
||||
discard """
|
||||
output: '''B
|
||||
0'''
|
||||
joinable: false
|
||||
"""
|
||||
|
||||
{.experimental: "overloadableEnums".}
|
||||
|
||||
type
|
||||
E1 = enum
|
||||
value1,
|
||||
value2
|
||||
E2 = enum
|
||||
value1,
|
||||
value2 = 4
|
||||
|
||||
const
|
||||
Lookuptable = [
|
||||
E1.value1: "1",
|
||||
value2: "2"
|
||||
]
|
||||
|
||||
when false:
|
||||
const
|
||||
Lookuptable: array[E1, string] = [
|
||||
value1: "1",
|
||||
value2: "2"
|
||||
]
|
||||
|
||||
|
||||
proc p(e: E1): int =
|
||||
# test that the 'case' statement is smart enough:
|
||||
case e
|
||||
of value1: echo "A"
|
||||
of value2: echo "B"
|
||||
|
||||
|
||||
let v = p value2 # ERROR: ambiguous!
|
||||
# (value2|value2) nkClosedSymChoice -> nkSym
|
||||
|
||||
proc x(p: int) = discard
|
||||
proc x(p: string) = discard
|
||||
|
||||
proc takeCallback(param: proc(p: int)) = discard
|
||||
|
||||
takeCallback x
|
||||
|
||||
echo ord v
|
||||
@@ -2,7 +2,6 @@ discard """
|
||||
action:reject
|
||||
cmd: "nim check $options $file"
|
||||
nimout: '''
|
||||
t10251.nim(15, 5) Error: redefinition of 'foo'; previous declaration here: t10251.nim(13, 5)
|
||||
t10251.nim(19, 23) Error: redefinition of 'goo1'; previous declaration here: t10251.nim(19, 11)
|
||||
'''
|
||||
"""
|
||||
@@ -14,6 +13,7 @@ type
|
||||
Enum2 = enum
|
||||
foo, bar, baz
|
||||
|
||||
|
||||
type
|
||||
Enum3 {.pure.} = enum # fixed (by accident?) in https://github.com/nim-lang/Nim/pull/18263
|
||||
goo0, goo1, goo2, goo1
|
||||
|
||||
Reference in New Issue
Block a user