From a354b18fe189b61ab1ff29039f8cef9502fce934 Mon Sep 17 00:00:00 2001 From: metagn Date: Sat, 17 Aug 2024 17:50:48 +0300 Subject: [PATCH] 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 --- compiler/lookups.nim | 5 +++-- compiler/semexprs.nim | 5 ++++- tests/enum/ttypenameconflict.nim | 13 +++++++++++++ 3 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 tests/enum/ttypenameconflict.nim diff --git a/compiler/lookups.nim b/compiler/lookups.nim index d0e114a185..7591538300 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 e2a4df3ffe..731bd14dc4 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 0000000000..b13bf00cee --- /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}