consider ambiguity for qualified symbols (#23989)

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).
This commit is contained in:
metagn
2024-08-20 22:32:35 +03:00
committed by GitHub
parent ab18962085
commit e38cbd3c84
6 changed files with 41 additions and 7 deletions

View File

@@ -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:

View File

@@ -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)

View File

@@ -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:

View File

@@ -0,0 +1 @@
type K* = object

View File

@@ -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]

View File

@@ -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