minor improvements to follow up recent PRs (#20342)

put mOpenArrayToSeq in compile-time evaluation whitelist
(it was mNone before which was whitelisted), homogenize
"ordinal type expected" errors, put overloadable enums
in non-experimental manual
This commit is contained in:
metagn 2022-09-14 19:30:15 +03:00 • committed by GitHub
commit a73ae3e066
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 45 additions and 51 deletions

View file

@ -738,7 +738,7 @@ const
mEqStr, mLeStr, mLtStr, mEqStr, mLeStr, mLtStr,
mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet, mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet,
mConStrStr, mAppendStrCh, mAppendStrStr, mAppendSeqElem, mConStrStr, mAppendStrCh, mAppendStrStr, mAppendSeqElem,
mInSet, mRepr} mInSet, mRepr, mOpenArrayToSeq}
generatedMagics* = {mNone, mIsolate, mFinished, mOpenArrayToSeq} generatedMagics* = {mNone, mIsolate, mFinished, mOpenArrayToSeq}
## magics that are generated as normal procs in the backend ## magics that are generated as normal procs in the backend

View file

@ -2504,7 +2504,7 @@ proc semSetConstr(c: PContext, n: PNode, expectedType: PType = nil): PNode =
if expectedElementType == nil: if expectedElementType == nil:
expectedElementType = typ expectedElementType = typ
if not isOrdinalType(typ, allowEnumWithHoles=true): if not isOrdinalType(typ, allowEnumWithHoles=true):
localError(c.config, n.info, errOrdinalTypeExpected) localError(c.config, n.info, errOrdinalTypeExpected % typeToString(typ, preferDesc))
typ = makeRangeType(c, 0, MaxSetElements-1, n.info) typ = makeRangeType(c, 0, MaxSetElements-1, n.info)
elif lengthOrd(c.config, typ) > MaxSetElements: elif lengthOrd(c.config, typ) > MaxSetElements:
typ = makeRangeType(c, 0, MaxSetElements-1, n.info) typ = makeRangeType(c, 0, MaxSetElements-1, n.info)

View file

@ -212,7 +212,7 @@ proc semOrd(c: PContext, n: PNode): PNode =
if isOrdinalType(parType, allowEnumWithHoles=true): if isOrdinalType(parType, allowEnumWithHoles=true):
discard discard
else: else:
localError(c.config, n.info, errOrdinalTypeExpected) localError(c.config, n.info, errOrdinalTypeExpected % typeToString(parType, preferDesc))
result.typ = errorType(c) result.typ = errorType(c)
proc semBindSym(c: PContext, n: PNode): PNode = proc semBindSym(c: PContext, n: PNode): PNode =

View file

@ -16,7 +16,7 @@ const
errIntLiteralExpected = "integer literal expected" errIntLiteralExpected = "integer literal expected"
errWrongNumberOfVariables = "wrong number of variables" errWrongNumberOfVariables = "wrong number of variables"
errInvalidOrderInEnumX = "invalid order in enum '$1'" errInvalidOrderInEnumX = "invalid order in enum '$1'"
errOrdinalTypeExpected = "ordinal type expected" errOrdinalTypeExpected = "ordinal type expected; given: $1"
errSetTooBig = "set is too large; use `std/sets` for ordinal types with more than 2^16 elements" errSetTooBig = "set is too large; use `std/sets` for ordinal types with more than 2^16 elements"
errBaseTypeMustBeOrdinal = "base type of a set must be an ordinal" errBaseTypeMustBeOrdinal = "base type of a set must be an ordinal"
errInheritanceOnlyWithNonFinalObjects = "inheritance only works with non-final objects" errInheritanceOnlyWithNonFinalObjects = "inheritance only works with non-final objects"
@ -95,7 +95,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
strVal = v[1] # second tuple part is the string value strVal = v[1] # second tuple part is the string value
if skipTypes(strVal.typ, abstractInst).kind in {tyString, tyCstring}: if skipTypes(strVal.typ, abstractInst).kind in {tyString, tyCstring}:
if not isOrdinalType(v[0].typ, allowEnumWithHoles=true): if not isOrdinalType(v[0].typ, allowEnumWithHoles=true):
localError(c.config, v[0].info, errOrdinalTypeExpected & "; given: " & typeToString(v[0].typ, preferDesc)) localError(c.config, v[0].info, errOrdinalTypeExpected % typeToString(v[0].typ, preferDesc))
x = toInt64(getOrdValue(v[0])) # first tuple part is the ordinal x = toInt64(getOrdValue(v[0])) # first tuple part is the ordinal
n[i][1][0] = newIntTypeNode(x, getSysType(c.graph, unknownLineInfo, tyInt)) n[i][1][0] = newIntTypeNode(x, getSysType(c.graph, unknownLineInfo, tyInt))
else: else:
@ -107,7 +107,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
x = counter x = counter
else: else:
if not isOrdinalType(v.typ, allowEnumWithHoles=true): if not isOrdinalType(v.typ, allowEnumWithHoles=true):
localError(c.config, v.info, errOrdinalTypeExpected & "; given: " & typeToString(v.typ, preferDesc)) localError(c.config, v.info, errOrdinalTypeExpected % typeToString(v.typ, preferDesc))
x = toInt64(getOrdValue(v)) x = toInt64(getOrdValue(v))
n[i][1] = newIntTypeNode(x, getSysType(c.graph, unknownLineInfo, tyInt)) n[i][1] = newIntTypeNode(x, getSysType(c.graph, unknownLineInfo, tyInt))
if i != 1: if i != 1:
@ -163,7 +163,7 @@ proc semSet(c: PContext, n: PNode, prev: PType): PType =
if base.kind in {tyGenericInst, tyAlias, tySink}: base = lastSon(base) if base.kind in {tyGenericInst, tyAlias, tySink}: base = lastSon(base)
if base.kind notin {tyGenericParam, tyGenericInvocation}: if base.kind notin {tyGenericParam, tyGenericInvocation}:
if not isOrdinalType(base, allowEnumWithHoles = true): if not isOrdinalType(base, allowEnumWithHoles = true):
localError(c.config, n.info, errOrdinalTypeExpected) localError(c.config, n.info, errOrdinalTypeExpected % typeToString(base, preferDesc))
elif lengthOrd(c.config, base) > MaxSetElements: elif lengthOrd(c.config, base) > MaxSetElements:
localError(c.config, n.info, errSetTooBig) localError(c.config, n.info, errSetTooBig)
else: else:
@ -331,12 +331,12 @@ proc semArrayIndex(c: PContext, n: PNode): PType =
return semArrayIndex(c, e.sym.ast) return semArrayIndex(c, e.sym.ast)
if not isOrdinalType(e.typ.lastSon): if not isOrdinalType(e.typ.lastSon):
let info = if n.safeLen > 1: n[1].info else: n.info let info = if n.safeLen > 1: n[1].info else: n.info
localError(c.config, info, errOrdinalTypeExpected) localError(c.config, info, errOrdinalTypeExpected % typeToString(e.typ, preferDesc))
result = makeRangeWithStaticExpr(c, e) result = makeRangeWithStaticExpr(c, e)
if c.inGenericContext > 0: result.flags.incl tfUnresolved if c.inGenericContext > 0: result.flags.incl tfUnresolved
elif e.kind in (nkCallKinds + {nkBracketExpr}) and hasUnresolvedArgs(c, e): elif e.kind in (nkCallKinds + {nkBracketExpr}) and hasUnresolvedArgs(c, e):
if not isOrdinalType(e.typ.skipTypes({tyStatic, tyAlias, tyGenericInst, tySink})): if not isOrdinalType(e.typ.skipTypes({tyStatic, tyAlias, tyGenericInst, tySink})):
localError(c.config, n[1].info, errOrdinalTypeExpected) localError(c.config, n[1].info, errOrdinalTypeExpected % typeToString(e.typ, preferDesc))
# This is an int returning call, depending on an # This is an int returning call, depending on an
# yet unknown generic param (see tgenericshardcases). # yet unknown generic param (see tgenericshardcases).
# We are going to construct a range type that will be # We are going to construct a range type that will be
@ -365,7 +365,7 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType =
if indxB.skipTypes({tyRange}).kind in {tyUInt, tyUInt64}: if indxB.skipTypes({tyRange}).kind in {tyUInt, tyUInt64}:
discard discard
elif not isOrdinalType(indxB): elif not isOrdinalType(indxB):
localError(c.config, n[1].info, errOrdinalTypeExpected) localError(c.config, n[1].info, errOrdinalTypeExpected % typeToString(indxB, preferDesc))
elif enumHasHoles(indxB): elif enumHasHoles(indxB):
localError(c.config, n[1].info, "enum '$1' has holes" % localError(c.config, n[1].info, "enum '$1' has holes" %
typeToString(indxB.skipTypes({tyRange}))) typeToString(indxB.skipTypes({tyRange})))
@ -395,7 +395,7 @@ proc semOrdinal(c: PContext, n: PNode, prev: PType): PType =
var base = semTypeNode(c, n[1], nil) var base = semTypeNode(c, n[1], nil)
if base.kind != tyGenericParam: if base.kind != tyGenericParam:
if not isOrdinalType(base): if not isOrdinalType(base):
localError(c.config, n[1].info, errOrdinalTypeExpected) localError(c.config, n[1].info, errOrdinalTypeExpected % typeToString(base, preferDesc))
addSonSkipIntLit(result, base, c.idgen) addSonSkipIntLit(result, base, c.idgen)
else: else:
localError(c.config, n.info, errXExpectsOneTypeParam % "ordinal") localError(c.config, n.info, errXExpectsOneTypeParam % "ordinal")

View file

@ -1313,6 +1313,38 @@ as `MyEnum.value`:
echo MyEnum.amb # OK. echo MyEnum.amb # OK.
``` ```
Enum value names are overloadable, much like routines. If both of the enums
`T` and `U` have a member named `foo`, then the identifier `foo` corresponds
to a choice between `T.foo` and `U.foo`. During overload resolution,
the correct type of `foo` is decided from the context. If the type of `foo` is
ambiguous, a static error will be produced.
```nim test = "nim c $1"
type
E1 = enum
value1,
value2
E2 = enum
value1,
value2 = 4
const
Lookuptable = [
E1.value1: "1",
# no need to qualify value2, known to be E1.value2
value2: "2"
]
proc p(e: E1) =
# disambiguation in 'case' statements:
case e
of value1: echo "A"
of value2: echo "B"
p value2
```
To implement bit fields with enums see [Bit fields]. To implement bit fields with enums see [Bit fields].

View file

@ -86,44 +86,6 @@ No Unicode normalization step is performed.
pragma `{.experimental: "unicodeOperators".}` reliably. pragma `{.experimental: "unicodeOperators".}` reliably.
Overloadable enum value names
=============================
Enum value names are overloadable, much like routines. If both of the enums
`T` and `U` have a member named `foo`, then the identifier `foo` corresponds
to a choice between `T.foo` and `U.foo`. During overload resolution,
the correct type of `foo` is decided from the context. If the type of `foo` is
ambiguous, a static error will be produced.
```nim test = "nim c $1"
type
E1 = enum
value1,
value2
E2 = enum
value1,
value2 = 4
const
Lookuptable = [
E1.value1: "1",
# no need to qualify value2, known to be E1.value2
value2: "2"
]
proc p(e: E1) =
# disambiguation in 'case' statements:
case e
of value1: echo "A"
of value2: echo "B"
p value2
```
Previously required `{.experimental: "overloadableEnums".}` to enable,
now always enabled.
Top-down type inference Top-down type inference
======================= =======================

View file

@ -1,5 +1,5 @@
discard """ discard """
errormsg: "ordinal type expected" errormsg: "ordinal type expected; given: string"
line: 10 line: 10
""" """

View file

@ -1,5 +1,5 @@
discard """ discard """
errormsg: "ordinal type expected" errormsg: "ordinal type expected; given: float"
line: 10 line: 10
""" """