Skip to content

Commit

Permalink
closed ambiguous enum defaults to first overload (#20457)
Browse files Browse the repository at this point in the history
* closed ambiguous enum defaults to first overload

* add warning

* turn to hint

* work around config
  • Loading branch information
metagn committed Oct 1, 2022
1 parent 24b81e9 commit cfff454
Show file tree
Hide file tree
Showing 8 changed files with 37 additions and 8 deletions.
1 change: 1 addition & 0 deletions compiler/condsyms.nim
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,4 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimHasTopDownInference")
defineSymbol("nimHasTemplateRedefinitionPragma")
defineSymbol("nimHasCstringCase")
defineSymbol("nimHasAmbiguousEnumHint")
2 changes: 2 additions & 0 deletions compiler/lineinfos.nim
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ type
hintPattern = "Pattern", hintExecuting = "Exec", hintLinking = "Link", hintDependency = "Dependency",
hintSource = "Source", hintPerformance = "Performance", hintStackTrace = "StackTrace",
hintGCStats = "GCStats", hintGlobalVar = "GlobalVar", hintExpandMacro = "ExpandMacro",
hintAmbiguousEnum = "AmbiguousEnum",
hintUser = "User", hintUserRaw = "UserRaw", hintExtendedContext = "ExtendedContext",
hintMsgOrigin = "MsgOrigin", # since 1.3.5
hintDeclaredLoc = "DeclaredLoc", # since 1.5.1
Expand Down Expand Up @@ -209,6 +210,7 @@ const
hintGCStats: "$1",
hintGlobalVar: "global variable declared here",
hintExpandMacro: "expanded macro: $1",
hintAmbiguousEnum: "$1",
hintUser: "$1",
hintUserRaw: "$1",
hintExtendedContext: "$1",
Expand Down
8 changes: 8 additions & 0 deletions compiler/semexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,14 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType
result = semExprCheck(c, n, flags, expectedType)
if result.typ == nil and efInTypeof in flags:
result.typ = c.voidType
elif (result.typ == nil or result.typ.kind == tyNone) and
result.kind == nkClosedSymChoice and
result[0].sym.kind == skEnumField:
# if overloaded enum field could not choose a type from a closed list,
# choose the first resolved enum field, i.e. the latest in scope
# to mirror old behavior
msgSymChoiceUseQualifier(c, result, hintAmbiguousEnum)
result = result[0]
elif result.typ == nil or result.typ == c.enforceVoidContext:
localError(c.config, n.info, errExprXHasNoType %
renderTree(result, {renderNoComments}))
Expand Down
14 changes: 9 additions & 5 deletions compiler/semstmts.nim
Original file line number Diff line number Diff line change
Expand Up @@ -574,17 +574,21 @@ proc semVarMacroPragma(c: PContext, a: PNode, n: PNode): PNode =
pragma(c, defs[lhsPos][namePos].sym, defs[lhsPos][pragmaPos], validPragmas)
return result

proc errorSymChoiceUseQualifier(c: PContext; n: PNode) =
proc msgSymChoiceUseQualifier(c: PContext; n: PNode; note = errGenerated) =
assert n.kind in nkSymChoices
var err = "ambiguous identifier: '" & $n[0] & "'"
var err =
if note == hintAmbiguousEnum:
"ambiguous enum field '$1' assumed to be of type $2, this will become an error in the future" % [$n[0], typeToString(n[0].typ)]
else:
"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)
message(c.config, n.info, note, err)

proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
var b: PNode
Expand All @@ -611,8 +615,8 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
if a[^1].kind != nkEmpty:
def = semExprWithType(c, a[^1], {}, typ)

if def.kind in nkSymChoices and def[0].typ.skipTypes(abstractInst).kind == tyEnum:
errorSymChoiceUseQualifier(c, def)
if def.kind in nkSymChoices and def[0].sym.kind == skEnumField:
msgSymChoiceUseQualifier(c, def, errGenerated)
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:
Expand Down
4 changes: 3 additions & 1 deletion compiler/semtypes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -591,7 +591,9 @@ proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
branch[i] = semCaseBranchRange(c, t, b, covered)
else:
# constant sets and arrays are allowed:
var r = semConstExpr(c, b)
# set expected type to selector type for type inference
# even if it can be a different type like a set or array
var r = semConstExpr(c, b, expectedType = t[0].typ)
if r.kind in {nkCurly, nkBracket} and r.len == 0 and branch.len == 2:
# discarding ``{}`` and ``[]`` branches silently
delSon(branch, 0)
Expand Down
4 changes: 4 additions & 0 deletions config/nim.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ cc = gcc
--parallel_build: "0" # 0 to auto-detect number of processors

hint[LineTooLong]=off
@if nimHasAmbiguousEnumHint:
# not needed if hint is a style check
hint[AmbiguousEnum]=off
@end
#hint[XDeclaredButNotUsed]=off

threads:on
Expand Down
7 changes: 5 additions & 2 deletions tests/ambsym/tambsym3.nim
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
discard """
errormsg: "ambiguous identifier"
errormsg: "ambiguous enum field"
file: "tambsym3.nim"
line: 11
line: 14
"""
# Test ambiguous symbols

import mambsym1, times

{.hint[AmbiguousEnum]: on.}
{.hintAsError[AmbiguousEnum]: on.}

var
v = mDec #ERROR_MSG ambiguous identifier

Expand Down
5 changes: 5 additions & 0 deletions tests/enum/tcrossmodule.nim
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,8 @@ template t =
doAssert some(Success)

t()

block: # legacy support for behavior before overloadableEnums
# warning: ambiguous enum field 'Success' assumed to be of type MyEnum
let x = {Success}
doAssert x is set[MyEnum]

0 comments on commit cfff454

Please sign in to comment.