Skip to content

Commit

Permalink
consider ambiguity for qualified symbols (#23989)
Browse files Browse the repository at this point in the history
fixes #23893

When type symbols are ambiguous, calls to them aren't allowed to be type
conversions and only routine symbols are considered instead. But the
compiler doesn't acknowledge that qualified symbols can be ambiguous,
`qualifiedLookUp` directly tries to access the identifier from the
module string table. Now it checks the relevant symbol iterators for any
symbol after the first received symbol, in which case the symbol is
considered ambiguous. `nkDotExpr` is also included in the whitelist of
node kinds for ambiguous type symbols (not entirely sure why this
exists, it's missing `nkAccQuoted` as well).
  • Loading branch information
metagn authored Aug 20, 2024
1 parent ab18962 commit e38cbd3
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 7 deletions.
11 changes: 8 additions & 3 deletions compiler/lookups.nim
Original file line number Diff line number Diff line change
Expand Up @@ -679,13 +679,18 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
ident = considerQuotedIdent(c, n[1])
if ident != nil:
if m == c.module:
result = strTableGet(c.topLevelScope.symbols, ident)
var ti: TIdentIter = default(TIdentIter)
result = initIdentIter(ti, c.topLevelScope.symbols, ident)
if result != nil and nextIdentIter(ti, c.topLevelScope.symbols) != nil:
# another symbol exists with same name
c.isAmbiguous = true
else:
var amb: bool = false
if c.importModuleLookup.getOrDefault(m.name.id).len > 1:
var amb: bool = false
result = errorUseQualifier(c, n.info, m, amb)
else:
result = someSym(c.graph, m, ident)
result = someSymAmb(c.graph, m, ident, amb)
if amb: c.isAmbiguous = true
if result == nil and checkUndeclared in flags:
result = errorUndeclaredIdentifierHint(c, ident, n[1].info)
elif n[1].kind == nkSym:
Expand Down
19 changes: 19 additions & 0 deletions compiler/modulegraphs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,25 @@ proc someSym*(g: ModuleGraph; m: PSym; name: PIdent): PSym =
else:
result = strTableGet(g.ifaces[m.position].interfSelect(importHidden), name)

proc someSymAmb*(g: ModuleGraph; m: PSym; name: PIdent; amb: var bool): PSym =
let importHidden = optImportHidden in m.options
if isCachedModule(g, m):
result = nil
for s in interfaceSymbols(g.config, g.cache, g.packed, FileIndex(m.position), name, importHidden):
if result == nil:
# set result to the first symbol
result = s
else:
# another symbol found
amb = true
break
else:
var ti: TIdentIter = default(TIdentIter)
result = initIdentIter(ti, g.ifaces[m.position].interfSelect(importHidden), name)
if result != nil and nextIdentIter(ti, g.ifaces[m.position].interfSelect(importHidden)) != nil:
# another symbol exists with same name
amb = true

proc systemModuleSym*(g: ModuleGraph; name: PIdent): PSym =
result = someSym(g, g.systemModule, name)

Expand Down
9 changes: 5 additions & 4 deletions compiler/semexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -3321,12 +3321,13 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
of skType:
# XXX think about this more (``set`` procs)
let ambig = c.isAmbiguous
if not (n[0].kind in {nkClosedSymChoice, nkOpenSymChoice, nkIdent} and ambig) and n.len == 2:
if not (n[0].kind in nkSymChoices + {nkIdent, nkDotExpr} and ambig) and n.len == 2:
result = semConv(c, n, flags, expectedType)
elif ambig and n.len == 1:
errorUseQualifier(c, n.info, s)
elif n.len == 1:
result = semObjConstr(c, n, flags, expectedType)
if ambig:
errorUseQualifier(c, n.info, s)
else:
result = semObjConstr(c, n, flags, expectedType)
elif s.magic == mNone: result = semDirectOp(c, n, flags, expectedType)
else: result = semMagic(c, n, s, flags, expectedType)
of skProc, skFunc, skMethod, skConverter, skIterator:
Expand Down
1 change: 1 addition & 0 deletions tests/lookups/mqualifiedamb1.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
type K* = object
4 changes: 4 additions & 0 deletions tests/lookups/mqualifiedamb2.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import ./mqualifiedamb1
export mqualifiedamb1
template K*(kind: static int): auto = typedesc[mqualifiedamb1.K]
template B*(kind: static int): auto = typedesc[mqualifiedamb1.K]
4 changes: 4 additions & 0 deletions tests/lookups/tqualifiedamb.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import ./mqualifiedamb2
discard default(K(0)) # works
discard default(mqualifiedamb2.B(0)) # works
discard default(mqualifiedamb2.K(0)) # doesn't work

0 comments on commit e38cbd3

Please sign in to comment.