diff options
-rw-r--r-- | compiler/lookups.nim | 35 | ||||
-rw-r--r-- | compiler/semexprs.nim | 5 | ||||
-rw-r--r-- | tests/enum/tambiguousoverloads.nim | 26 | ||||
-rw-r--r-- | tests/enum/toverloadable_enums.nim | 8 | ||||
-rw-r--r-- | tests/lookups/tambsym3.nim | 7 |
5 files changed, 67 insertions, 14 deletions
diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 3cf759981..90f9a9b2b 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -254,6 +254,41 @@ proc searchInScopesFilterBy*(c: PContext, s: PIdent, filter: TSymKinds): seq[PSy if s.kind in filter: result.add s +proc isAmbiguous*(c: PContext, s: PIdent, filter: TSymKinds, sym: var PSym): bool = + result = false + block outer: + for scope in allScopes(c.currentScope): + var ti: TIdentIter + var candidate = initIdentIter(ti, scope.symbols, s) + var scopeHasCandidate = false + while candidate != nil: + if candidate.kind in filter: + if scopeHasCandidate: + # 2 candidates in same scope, ambiguous + return true + else: + scopeHasCandidate = true + sym = candidate + candidate = nextIdentIter(ti, scope.symbols) + if scopeHasCandidate: + # scope had a candidate but wasn't ambiguous + return false + + var importsHaveCandidate = false + var marked = initIntSet() + for im in c.imports.mitems: + for s in symbols(im, marked, s, c.graph): + if s.kind in filter: + if importsHaveCandidate: + # 2 candidates among imports, ambiguous + return true + else: + importsHaveCandidate = true + sym = s + if importsHaveCandidate: + # imports had a candidate but wasn't ambiguous + return false + proc errorSym*(c: PContext, n: PNode): PSym = ## creates an error symbol to avoid cascading errors (for IDE support) var m = n diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index e9f90dcc0..001ce958a 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -92,7 +92,10 @@ proc semExprCheck(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType proc ambiguousSymChoice(c: PContext, orig, n: PNode): PNode = let first = n[0].sym - if first.kind == skEnumField: + var foundSym: PSym = nil + if first.kind == skEnumField and + not isAmbiguous(c, first.name, {skEnumField}, foundSym) and + foundSym == first: # choose the first resolved enum field, i.e. the latest in scope # to mirror behavior before overloadable enums if hintAmbiguousEnum in c.config.notes: diff --git a/tests/enum/tambiguousoverloads.nim b/tests/enum/tambiguousoverloads.nim new file mode 100644 index 000000000..1b0d92608 --- /dev/null +++ b/tests/enum/tambiguousoverloads.nim @@ -0,0 +1,26 @@ +discard """ +cmd: "nim check --hints:off $file" +""" + +block: # bug #21887 + type + EnumA = enum A = 300, B + EnumB = enum A = 10 + EnumC = enum C + + doAssert typeof(EnumC(A)) is EnumC #[tt.Error + ^ ambiguous identifier 'A' -- use one of the following: + EnumA.A: EnumA + EnumB.A: EnumB]# + +block: # issue #22598 + type + A = enum + red + B = enum + red + + let a = red #[tt.Error + ^ ambiguous identifier 'red' -- use one of the following: + A.red: A + B.red: B]# diff --git a/tests/enum/toverloadable_enums.nim b/tests/enum/toverloadable_enums.nim index 5fdcb1823..9bb551467 100644 --- a/tests/enum/toverloadable_enums.nim +++ b/tests/enum/toverloadable_enums.nim @@ -118,11 +118,3 @@ block: # test with macros/templates doAssert isOneMS(e2) doAssert isOneT(e1) doAssert isOneT(e2) - -block: # bug #21908 - type - EnumA = enum A = 300, B - EnumB = enum A = 10 - EnumC = enum C - - doAssert typeof(EnumC(A)) is EnumC diff --git a/tests/lookups/tambsym3.nim b/tests/lookups/tambsym3.nim index e50f9c461..6e7589cd8 100644 --- a/tests/lookups/tambsym3.nim +++ b/tests/lookups/tambsym3.nim @@ -1,15 +1,12 @@ discard """ - errormsg: "ambiguous enum field" + errormsg: "ambiguous identifier 'mDec' -- use one of the following:" file: "tambsym3.nim" - line: 14 + line: 11 """ # Test ambiguous symbols import mambsym1, times -{.hint[AmbiguousEnum]: on.} -{.hintAsError[AmbiguousEnum]: on.} - var v = mDec #ERROR_MSG ambiguous identifier |