diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index ec16439603ebe..12f5e9f3d2de2 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -82,6 +82,7 @@ type warnEffect = "Effect", warnCastSizes = "CastSizes" warnTemplateRedefinition = "TemplateRedefinition", + warnAmbiguousEnum = "AmbiguousEnum", warnUser = "User", # hints hintSuccess = "Success", hintSuccessX = "SuccessX", @@ -177,6 +178,7 @@ const warnEffect: "$1", warnCastSizes: "$1", warnTemplateRedefinition: "template '$1' is implicitly redefined, consider adding an explicit .redefine pragma", + warnAmbiguousEnum: "$1", warnUser: "$1", hintSuccess: "operation successful: $#", # keep in sync with `testament.isSuccess` diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 6491cc1796fd0..eb2edd3474749 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -88,10 +88,12 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}, 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.len != 0 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, warnAmbiguousEnum) result = result[0] elif result.typ == nil or result.typ == c.enforceVoidContext: localError(c.config, n.info, errExprXHasNoType % diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index faf8e3baa8b19..334a3914e06e6 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -574,9 +574,13 @@ 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 == warnAmbiguousEnum: + "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 @@ -584,7 +588,7 @@ proc errorSymChoiceUseQualifier(c: PContext; n: PNode) = 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 @@ -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: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 0a823f20ad6da..d033d5f4403de 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -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) diff --git a/tests/ambsym/tambsym3.nim b/tests/ambsym/tambsym3.nim index 0558517bd0761..14b1b796e621c 100644 --- a/tests/ambsym/tambsym3.nim +++ b/tests/ambsym/tambsym3.nim @@ -1,12 +1,14 @@ discard """ - errormsg: "ambiguous identifier" + errormsg: "ambiguous enum field" file: "tambsym3.nim" - line: 11 + line: 13 """ # Test ambiguous symbols import mambsym1, times +{.warningAsError[AmbiguousEnum]: on.} + var v = mDec #ERROR_MSG ambiguous identifier diff --git a/tests/enum/tcrossmodule.nim b/tests/enum/tcrossmodule.nim index bf2d1dbbef5e8..c21072198ee87 100644 --- a/tests/enum/tcrossmodule.nim +++ b/tests/enum/tcrossmodule.nim @@ -9,7 +9,7 @@ template t = t() -block: # behavior before overloadableEnums - # in case of ambiguity in closed environment, pick latest enum in scope +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]