* better procvar ambiguity errors, clean up after #20457 fixes #6359, fixes #13849 * only trigger on closedsymchoice again * new approach * add manual entry for ambiguous enums too * add indent [skip ci] * move to proc
This commit is contained in:
parent
b36f5119ae
commit
2449c37137
5 changed files with 76 additions and 36 deletions
|
|
@ -70,10 +70,11 @@ type
|
|||
efWantStmt, efAllowStmt, efDetermineType, efExplain,
|
||||
efWantValue, efOperand, efNoSemCheck,
|
||||
efNoEvaluateGeneric, efInCall, efFromHlo, efNoSem2Check,
|
||||
efNoUndeclared, efIsDotCall, efCannotBeDotCall
|
||||
efNoUndeclared, efIsDotCall, efCannotBeDotCall,
|
||||
# Use this if undeclared identifiers should not raise an error during
|
||||
# overload resolution.
|
||||
efNoDiagnostics
|
||||
efNoDiagnostics,
|
||||
efTypeAllowed # typeAllowed will be called after
|
||||
|
||||
TExprFlags* = set[TExprFlag]
|
||||
|
||||
|
|
|
|||
|
|
@ -83,18 +83,39 @@ proc semExprCheck(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType
|
|||
# do not produce another redundant error message:
|
||||
result = errorNode(c, n)
|
||||
|
||||
proc ambiguousSymChoice(c: PContext, orig, n: PNode): PNode =
|
||||
let first = n[0].sym
|
||||
if first.kind == skEnumField:
|
||||
# choose the first resolved enum field, i.e. the latest in scope
|
||||
# to mirror behavior before overloadable enums
|
||||
if hintAmbiguousEnum in c.config.notes:
|
||||
var err = "ambiguous enum field '" & first.name.s &
|
||||
"' assumed to be of type " & typeToString(first.typ) &
|
||||
" -- use one of the following:\n"
|
||||
for child in n:
|
||||
let candidate = child.sym
|
||||
err.add " " & candidate.owner.name.s & "." & candidate.name.s & "\n"
|
||||
message(c.config, orig.info, hintAmbiguousEnum, err)
|
||||
result = n[0]
|
||||
else:
|
||||
var err = "ambiguous identifier '" & first.name.s &
|
||||
"' -- use one of the following:\n"
|
||||
for child in n:
|
||||
let candidate = child.sym
|
||||
err.add " " & candidate.owner.name.s & "." & candidate.name.s
|
||||
err.add ": " & typeToString(candidate.typ) & "\n"
|
||||
localError(c.config, orig.info, err)
|
||||
n.typ = errorType(c)
|
||||
result = n
|
||||
|
||||
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode =
|
||||
result = semExprCheck(c, n, flags, expectedType)
|
||||
if result.typ == nil and efInTypeof in flags:
|
||||
result.typ = c.voidType
|
||||
elif (result.typ == nil or result.typ.kind == tyNone) and
|
||||
result.kind == nkClosedSymChoice and
|
||||
result[0].sym.kind == skEnumField:
|
||||
# if overloaded enum field could not choose a type from a closed list,
|
||||
# choose the first resolved enum field, i.e. the latest in scope
|
||||
# to mirror old behavior
|
||||
msgSymChoiceUseQualifier(c, result, hintAmbiguousEnum)
|
||||
result = result[0]
|
||||
efTypeAllowed in flags and
|
||||
result.kind == nkClosedSymChoice and result.len > 0:
|
||||
result = ambiguousSymChoice(c, n, result)
|
||||
elif result.typ == nil or result.typ == c.enforceVoidContext:
|
||||
localError(c.config, n.info, errExprXHasNoType %
|
||||
renderTree(result, {renderNoComments}))
|
||||
|
|
@ -634,7 +655,7 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PTyp
|
|||
lastValidIndex = lastOrd(c.config, indexType)
|
||||
x = x[1]
|
||||
|
||||
let yy = semExprWithType(c, x, expectedType = expectedElementType)
|
||||
let yy = semExprWithType(c, x, {efTypeAllowed}, expectedElementType)
|
||||
var typ = yy.typ
|
||||
if expectedElementType == nil:
|
||||
expectedElementType = typ
|
||||
|
|
@ -655,7 +676,7 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PTyp
|
|||
localError(c.config, x.info, "invalid order in array constructor")
|
||||
x = x[1]
|
||||
|
||||
let xx = semExprWithType(c, x, {}, expectedElementType)
|
||||
let xx = semExprWithType(c, x, {efTypeAllowed}, expectedElementType)
|
||||
result.add xx
|
||||
typ = commonType(c, typ, xx.typ)
|
||||
#n[i] = semExprWithType(c, x, {})
|
||||
|
|
@ -1806,7 +1827,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
|
|||
renderTree(a, {renderNoComments}))
|
||||
else:
|
||||
let lhs = n[0]
|
||||
let rhs = semExprWithType(c, n[1], {}, le)
|
||||
let rhs = semExprWithType(c, n[1], {efTypeAllowed}, le)
|
||||
if lhs.kind == nkSym and lhs.sym.kind == skResult:
|
||||
n.typ = c.enforceVoidContext
|
||||
if c.p.owner.kind != skMacro and resultTypeIsInferrable(lhs.sym.typ):
|
||||
|
|
@ -2502,8 +2523,8 @@ proc semSetConstr(c: PContext, n: PNode, expectedType: PType = nil): PNode =
|
|||
for i in 0..<n.len:
|
||||
if isRange(n[i]):
|
||||
checkSonsLen(n[i], 3, c.config)
|
||||
n[i][1] = semExprWithType(c, n[i][1], {}, expectedElementType)
|
||||
n[i][2] = semExprWithType(c, n[i][2], {}, expectedElementType)
|
||||
n[i][1] = semExprWithType(c, n[i][1], {efTypeAllowed}, expectedElementType)
|
||||
n[i][2] = semExprWithType(c, n[i][2], {efTypeAllowed}, expectedElementType)
|
||||
if typ == nil:
|
||||
typ = skipTypes(n[i][1].typ,
|
||||
{tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink})
|
||||
|
|
@ -2518,7 +2539,7 @@ proc semSetConstr(c: PContext, n: PNode, expectedType: PType = nil): PNode =
|
|||
if expectedElementType == nil:
|
||||
expectedElementType = typ
|
||||
else:
|
||||
n[i] = semExprWithType(c, n[i], {}, expectedElementType)
|
||||
n[i] = semExprWithType(c, n[i], {efTypeAllowed}, expectedElementType)
|
||||
if typ == nil:
|
||||
typ = skipTypes(n[i].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink})
|
||||
if expectedElementType == nil:
|
||||
|
|
|
|||
|
|
@ -585,22 +585,6 @@ proc semVarMacroPragma(c: PContext, a: PNode, n: PNode): PNode =
|
|||
pragma(c, defs[lhsPos][namePos].sym, defs[lhsPos][pragmaPos], validPragmas)
|
||||
return result
|
||||
|
||||
proc msgSymChoiceUseQualifier(c: PContext; n: PNode; note = errGenerated) =
|
||||
assert n.kind in nkSymChoices
|
||||
var err =
|
||||
if note == hintAmbiguousEnum:
|
||||
"ambiguous enum field '$1' assumed to be of type $2, this will become an error in the future" % [$n[0], typeToString(n[0].typ)]
|
||||
else:
|
||||
"ambiguous identifier: '" & $n[0] & "'"
|
||||
var i = 0
|
||||
for child in n:
|
||||
let candidate = child.sym
|
||||
if i == 0: err.add " -- use one of the following:\n"
|
||||
else: err.add "\n"
|
||||
err.add " " & candidate.owner.name.s & "." & candidate.name.s
|
||||
inc i
|
||||
message(c.config, n.info, note, err)
|
||||
|
||||
template isLocalVarSym(n: PNode): bool =
|
||||
n.kind == nkSym and
|
||||
(n.sym.kind in {skVar, skLet} and not
|
||||
|
|
@ -645,11 +629,9 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
|||
|
||||
var def: PNode = c.graph.emptyNode
|
||||
if a[^1].kind != nkEmpty:
|
||||
def = semExprWithType(c, a[^1], {}, typ)
|
||||
def = semExprWithType(c, a[^1], {efTypeAllowed}, typ)
|
||||
|
||||
if def.kind in nkSymChoices and def[0].sym.kind == skEnumField:
|
||||
msgSymChoiceUseQualifier(c, def, errGenerated)
|
||||
elif def.kind == nkSym and def.sym.kind in {skTemplate, skMacro}:
|
||||
if def.kind == nkSym and def.sym.kind in {skTemplate, skMacro}:
|
||||
typFlags.incl taIsTemplateOrMacro
|
||||
elif def.typ.kind == tyTypeDesc and c.p.owner.kind != skMacro:
|
||||
typFlags.incl taProcContextIsNotMacro
|
||||
|
|
@ -799,7 +781,7 @@ proc semConst(c: PContext, n: PNode): PNode =
|
|||
var typFlags: TTypeAllowedFlags
|
||||
|
||||
# don't evaluate here since the type compatibility check below may add a converter
|
||||
var def = semExprWithType(c, a[^1], {}, typ)
|
||||
var def = semExprWithType(c, a[^1], {efTypeAllowed}, typ)
|
||||
|
||||
if def.kind == nkSym and def.sym.kind in {skTemplate, skMacro}:
|
||||
typFlags.incl taIsTemplateOrMacro
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue