summary refs log tree commit diff stats
diff options
context:
space:
mode:
authormetagn <metagngn@gmail.com>2024-08-17 17:50:48 +0300
committerGitHub <noreply@github.com>2024-08-17 16:50:48 +0200
commita354b18fe189b61ab1ff29039f8cef9502fce934 (patch)
treeec580118738aee3e32f0b8a70b8b575bb49559a5
parent0ffc0493a35fe1bcd8417a9d137318aa7f82eb98 (diff)
downloadNim-a354b18fe189b61ab1ff29039f8cef9502fce934.tar.gz
always lookup pure enum symbols if expected type is enum (#23976)
fixes #23689

Normally pure enum symbols only "exist" in lookup if nothing else with
the same name is in scope. But if an expression is expected to be an
enum type, we know that ambiguity can be resolved between different
symbols based on their type, so we can include the normally inaccessible
pure enum fields in the ambiguity resolution in the case that the
expected enum type is actually a pure enum. This handles the use case in
the issue of the type inference for enums reverted in #23588.

I know pure enums are supposed to be on their way out so this might seem
excessive, but the `pure` pragma can't be removed in the code in the
issue due to a redefinition error, they have to be separated into
different modules. Normal enums can still resolve the ambiguity here
though. I always think about making a list of all the remaining use
cases for pure enums and I always forget.

Will close #23694 if CI passes
-rw-r--r--compiler/lookups.nim5
-rw-r--r--compiler/semexprs.nim5
-rw-r--r--tests/enum/ttypenameconflict.nim13
3 files changed, 20 insertions, 3 deletions
diff --git a/compiler/lookups.nim b/compiler/lookups.nim
index d0e114a18..759153830 100644
--- a/compiler/lookups.nim
+++ b/compiler/lookups.nim
@@ -632,9 +632,10 @@ type
 
 const allExceptModule = {low(TSymKind)..high(TSymKind)} - {skModule, skPackage}
 
-proc lookUpCandidates*(c: PContext, ident: PIdent, filter: set[TSymKind]): seq[PSym] =
+proc lookUpCandidates*(c: PContext, ident: PIdent, filter: set[TSymKind],
+                       includePureEnum = false): seq[PSym] =
   result = searchInScopesFilterBy(c, ident, filter)
-  if result.len == 0:
+  if skEnumField in filter and (result.len == 0 or includePureEnum):
     result.add allPureEnumFields(c, ident)
 
 proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index e2a4df3ff..731bd14dc 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -3107,7 +3107,10 @@ proc resolveIdentToSym(c: PContext, n: PNode, resultNode: var PNode,
   if efNoEvaluateGeneric in flags or expectedType != nil:
     # `a[...]` where `a` is a module or package is not possible
     filter.excl {skModule, skPackage}
-  let candidates = lookUpCandidates(c, ident, filter)
+  let includePureEnum = expectedType != nil and
+    expectedType.skipTypes(abstractRange-{tyDistinct}).kind == tyEnum
+  let candidates = lookUpCandidates(c, ident, filter,
+    includePureEnum = includePureEnum)
   if candidates.len == 0:
     result = errorUndeclaredIdentifierHint(c, ident, n.info)
   elif candidates.len == 1 or {efNoEvaluateGeneric, efInCall} * flags != {}:
diff --git a/tests/enum/ttypenameconflict.nim b/tests/enum/ttypenameconflict.nim
new file mode 100644
index 000000000..b13bf00ce
--- /dev/null
+++ b/tests/enum/ttypenameconflict.nim
@@ -0,0 +1,13 @@
+# issue #23689
+
+type
+  MyEnum {.pure.} = enum
+    A, B, C, D
+
+  B = object
+    field: int
+
+let x: MyEnum = B
+doAssert $x == "B"
+doAssert typeof(x) is MyEnum
+doAssert x in {A, B}