diff options
-rw-r--r-- | compiler/semdata.nim | 5 | ||||
-rw-r--r-- | compiler/semexprs.nim | 47 | ||||
-rw-r--r-- | compiler/semstmts.nim | 24 | ||||
-rw-r--r-- | doc/manual.md | 17 | ||||
-rw-r--r-- | tests/ambsym/tambprocvar.nim | 19 |
5 files changed, 76 insertions, 36 deletions
diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 73276e50a..29c2c139f 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -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] diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index d6745e8e4..cb7b0ae4a 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -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: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index f6b193f3d..7a3bb48a6 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -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 diff --git a/doc/manual.md b/doc/manual.md index a4f864eaa..378aaed90 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -1365,6 +1365,23 @@ ambiguous, a static error will be produced. p value2 ``` +In some cases, ambiguity of enums is resolved depending on the relation +between the current scope and the scope the enums were defined in. + + ```nim + # a.nim + type Foo* = enum abc + + # b.nim + import a + type Bar = enum abc + echo abc is Bar # true + + block: + type Baz = enum abc + echo abc is Baz # true + ``` + To implement bit fields with enums see [Bit fields]. diff --git a/tests/ambsym/tambprocvar.nim b/tests/ambsym/tambprocvar.nim new file mode 100644 index 000000000..2a9921bad --- /dev/null +++ b/tests/ambsym/tambprocvar.nim @@ -0,0 +1,19 @@ +discard """ + action: reject + cmd: "nim check $file" + nimout: ''' +tambprocvar.nim(15, 11) Error: ambiguous identifier 'foo' -- use one of the following: + tambprocvar.foo: proc (x: int){.noSideEffect, gcsafe.} + tambprocvar.foo: proc (x: float){.noSideEffect, gcsafe.} +''' +""" + +block: + proc foo(x: int) = discard + proc foo(x: float) = discard + + let x = foo + +block: + let x = `+` #[tt.Error + ^ ambiguous identifier '+' -- use one of the following:]# |