diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2021-07-28 12:46:28 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-07-28 12:46:28 +0200 |
commit | a273ea70e8817e3509014a1b3dcd16a360ed400b (patch) | |
tree | 3a3d26701cf7bc84240426cde277d44e6194e4a4 /compiler | |
parent | 4c1202972abdfe99232e5d15a6169c7b2e0f5d75 (diff) | |
download | Nim-a273ea70e8817e3509014a1b3dcd16a360ed400b.tar.gz |
implements overloadable enum values; WIP (#18470)
* implements overloadable enum values * simpler code
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ast.nim | 2 | ||||
-rw-r--r-- | compiler/lookups.nim | 7 | ||||
-rw-r--r-- | compiler/options.nim | 3 | ||||
-rw-r--r-- | compiler/sem.nim | 8 | ||||
-rw-r--r-- | compiler/semexprs.nim | 36 | ||||
-rw-r--r-- | compiler/semstmts.nim | 16 | ||||
-rw-r--r-- | compiler/semtypes.nim | 12 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 2 |
8 files changed, 76 insertions, 10 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 0eeaa8133..5b54dd8ef 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -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} diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 44a30eefa..331eef525 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -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: diff --git a/compiler/options.nim b/compiler/options.nim index f02f02256..e37dea1b6 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -203,7 +203,8 @@ type vmopsDanger, strictFuncs, views, - strictNotNil + strictNotNil, + overloadableEnums LegacyFeature* = enum allowSemcheckedAstModification, diff --git a/compiler/sem.nim b/compiler/sem.nim index 879f6efc9..804325e56 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -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) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 42c6b465e..f2fe54fad 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -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: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 75323a95e..cc09291c5 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -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 diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 484997e3a..db895cab6 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -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") diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 6bc641bd6..674dd7e2e 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -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 |