closed ambiguous enum defaults to first overload (#20457)
* closed ambiguous enum defaults to first overload * add warning * turn to hint * work around config
This commit is contained in:
parent
24b81e9df6
commit
cfff454cf9
8 changed files with 37 additions and 8 deletions
|
|
@ -143,3 +143,4 @@ proc initDefines*(symbols: StringTableRef) =
|
||||||
defineSymbol("nimHasTopDownInference")
|
defineSymbol("nimHasTopDownInference")
|
||||||
defineSymbol("nimHasTemplateRedefinitionPragma")
|
defineSymbol("nimHasTemplateRedefinitionPragma")
|
||||||
defineSymbol("nimHasCstringCase")
|
defineSymbol("nimHasCstringCase")
|
||||||
|
defineSymbol("nimHasAmbiguousEnumHint")
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,7 @@ type
|
||||||
hintPattern = "Pattern", hintExecuting = "Exec", hintLinking = "Link", hintDependency = "Dependency",
|
hintPattern = "Pattern", hintExecuting = "Exec", hintLinking = "Link", hintDependency = "Dependency",
|
||||||
hintSource = "Source", hintPerformance = "Performance", hintStackTrace = "StackTrace",
|
hintSource = "Source", hintPerformance = "Performance", hintStackTrace = "StackTrace",
|
||||||
hintGCStats = "GCStats", hintGlobalVar = "GlobalVar", hintExpandMacro = "ExpandMacro",
|
hintGCStats = "GCStats", hintGlobalVar = "GlobalVar", hintExpandMacro = "ExpandMacro",
|
||||||
|
hintAmbiguousEnum = "AmbiguousEnum",
|
||||||
hintUser = "User", hintUserRaw = "UserRaw", hintExtendedContext = "ExtendedContext",
|
hintUser = "User", hintUserRaw = "UserRaw", hintExtendedContext = "ExtendedContext",
|
||||||
hintMsgOrigin = "MsgOrigin", # since 1.3.5
|
hintMsgOrigin = "MsgOrigin", # since 1.3.5
|
||||||
hintDeclaredLoc = "DeclaredLoc", # since 1.5.1
|
hintDeclaredLoc = "DeclaredLoc", # since 1.5.1
|
||||||
|
|
@ -209,6 +210,7 @@ const
|
||||||
hintGCStats: "$1",
|
hintGCStats: "$1",
|
||||||
hintGlobalVar: "global variable declared here",
|
hintGlobalVar: "global variable declared here",
|
||||||
hintExpandMacro: "expanded macro: $1",
|
hintExpandMacro: "expanded macro: $1",
|
||||||
|
hintAmbiguousEnum: "$1",
|
||||||
hintUser: "$1",
|
hintUser: "$1",
|
||||||
hintUserRaw: "$1",
|
hintUserRaw: "$1",
|
||||||
hintExtendedContext: "$1",
|
hintExtendedContext: "$1",
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,14 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType
|
||||||
result = semExprCheck(c, n, flags, expectedType)
|
result = semExprCheck(c, n, flags, expectedType)
|
||||||
if result.typ == nil and efInTypeof in flags:
|
if result.typ == nil and efInTypeof in flags:
|
||||||
result.typ = c.voidType
|
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:
|
elif result.typ == nil or result.typ == c.enforceVoidContext:
|
||||||
localError(c.config, n.info, errExprXHasNoType %
|
localError(c.config, n.info, errExprXHasNoType %
|
||||||
renderTree(result, {renderNoComments}))
|
renderTree(result, {renderNoComments}))
|
||||||
|
|
|
||||||
|
|
@ -574,9 +574,13 @@ proc semVarMacroPragma(c: PContext, a: PNode, n: PNode): PNode =
|
||||||
pragma(c, defs[lhsPos][namePos].sym, defs[lhsPos][pragmaPos], validPragmas)
|
pragma(c, defs[lhsPos][namePos].sym, defs[lhsPos][pragmaPos], validPragmas)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
proc errorSymChoiceUseQualifier(c: PContext; n: PNode) =
|
proc msgSymChoiceUseQualifier(c: PContext; n: PNode; note = errGenerated) =
|
||||||
assert n.kind in nkSymChoices
|
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
|
var i = 0
|
||||||
for child in n:
|
for child in n:
|
||||||
let candidate = child.sym
|
let candidate = child.sym
|
||||||
|
|
@ -584,7 +588,7 @@ proc errorSymChoiceUseQualifier(c: PContext; n: PNode) =
|
||||||
else: err.add "\n"
|
else: err.add "\n"
|
||||||
err.add " " & candidate.owner.name.s & "." & candidate.name.s
|
err.add " " & candidate.owner.name.s & "." & candidate.name.s
|
||||||
inc i
|
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 =
|
proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
var b: PNode
|
var b: PNode
|
||||||
|
|
@ -611,8 +615,8 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
if a[^1].kind != nkEmpty:
|
if a[^1].kind != nkEmpty:
|
||||||
def = semExprWithType(c, a[^1], {}, typ)
|
def = semExprWithType(c, a[^1], {}, typ)
|
||||||
|
|
||||||
if def.kind in nkSymChoices and def[0].typ.skipTypes(abstractInst).kind == tyEnum:
|
if def.kind in nkSymChoices and def[0].sym.kind == skEnumField:
|
||||||
errorSymChoiceUseQualifier(c, def)
|
msgSymChoiceUseQualifier(c, def, errGenerated)
|
||||||
elif def.kind == nkSym and def.sym.kind in {skTemplate, skMacro}:
|
elif def.kind == nkSym and def.sym.kind in {skTemplate, skMacro}:
|
||||||
typFlags.incl taIsTemplateOrMacro
|
typFlags.incl taIsTemplateOrMacro
|
||||||
elif def.typ.kind == tyTypeDesc and c.p.owner.kind != skMacro:
|
elif def.typ.kind == tyTypeDesc and c.p.owner.kind != skMacro:
|
||||||
|
|
|
||||||
|
|
@ -591,7 +591,9 @@ proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
|
||||||
branch[i] = semCaseBranchRange(c, t, b, covered)
|
branch[i] = semCaseBranchRange(c, t, b, covered)
|
||||||
else:
|
else:
|
||||||
# constant sets and arrays are allowed:
|
# 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:
|
if r.kind in {nkCurly, nkBracket} and r.len == 0 and branch.len == 2:
|
||||||
# discarding ``{}`` and ``[]`` branches silently
|
# discarding ``{}`` and ``[]`` branches silently
|
||||||
delSon(branch, 0)
|
delSon(branch, 0)
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,10 @@ cc = gcc
|
||||||
--parallel_build: "0" # 0 to auto-detect number of processors
|
--parallel_build: "0" # 0 to auto-detect number of processors
|
||||||
|
|
||||||
hint[LineTooLong]=off
|
hint[LineTooLong]=off
|
||||||
|
@if nimHasAmbiguousEnumHint:
|
||||||
|
# not needed if hint is a style check
|
||||||
|
hint[AmbiguousEnum]=off
|
||||||
|
@end
|
||||||
#hint[XDeclaredButNotUsed]=off
|
#hint[XDeclaredButNotUsed]=off
|
||||||
|
|
||||||
threads:on
|
threads:on
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,15 @@
|
||||||
discard """
|
discard """
|
||||||
errormsg: "ambiguous identifier"
|
errormsg: "ambiguous enum field"
|
||||||
file: "tambsym3.nim"
|
file: "tambsym3.nim"
|
||||||
line: 11
|
line: 14
|
||||||
"""
|
"""
|
||||||
# Test ambiguous symbols
|
# Test ambiguous symbols
|
||||||
|
|
||||||
import mambsym1, times
|
import mambsym1, times
|
||||||
|
|
||||||
|
{.hint[AmbiguousEnum]: on.}
|
||||||
|
{.hintAsError[AmbiguousEnum]: on.}
|
||||||
|
|
||||||
var
|
var
|
||||||
v = mDec #ERROR_MSG ambiguous identifier
|
v = mDec #ERROR_MSG ambiguous identifier
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,3 +8,8 @@ template t =
|
||||||
doAssert some(Success)
|
doAssert some(Success)
|
||||||
|
|
||||||
t()
|
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]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue