diff options
-rw-r--r-- | compiler/msgs.nim | 5 | ||||
-rw-r--r-- | compiler/semtypes.nim | 4 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 33 | ||||
-rw-r--r-- | compiler/types.nim | 192 |
4 files changed, 145 insertions, 89 deletions
diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 5ae2c4970..e16a5cea2 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -46,7 +46,8 @@ type errInvalidArgForX, errStmtHasNoEffect, errXExpectsTypeOrValue, errXExpectsArrayType, errIteratorCannotBeInstantiated, errExprXAmbiguous, errConstantDivisionByZero, errOrdinalTypeExpected, - errOrdinalOrFloatTypeExpected, errOverOrUnderflow, + errOrdinalOrFloatTypeExpected, errFloatTypeExpected, errStringTypeExpected, + errOverOrUnderflow, errCannotEvalXBecauseIncompletelyDefined, errChrExpectsRange0_255, errDynlibRequiresExportc, errUndeclaredFieldX, errNilAccess, errIndexOutOfBounds, errIndexTypesDoNotMatch, errBracketsInvalidForType, @@ -219,6 +220,8 @@ const errConstantDivisionByZero: "division by zero", errOrdinalTypeExpected: "ordinal type expected", errOrdinalOrFloatTypeExpected: "ordinal or float type expected", + errFloatTypeExpected: "float type expected", + errStringTypeExpected: "string type expected", errOverOrUnderflow: "over- or underflow", errCannotEvalXBecauseIncompletelyDefined: "cannot evaluate '$1' because type is not defined completely", errChrExpectsRange0_255: "\'chr\' expects an int in the range 0..255", diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 1fc263617..0d1688d33 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -205,8 +205,8 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType = if not hasUnknownTypes: if not sameType(rangeT[0].skipTypes({tyRange}), rangeT[1].skipTypes({tyRange})): localError(n.info, errPureTypeMismatch) - elif not rangeT[0].isOrdinalType: - localError(n.info, errOrdinalTypeExpected) + elif not rangeT[0].isOrdinalType and rangeT[0].kind notin tyFloat..tyFloat128: + localError(n.info, errOrdinalOrFloatTypeExpected) elif enumHasHoles(rangeT[0]): localError(n.info, errEnumXHasHoles, rangeT[0].sym.name.s) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 96d815df7..cb821c02f 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -628,20 +628,27 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = else: discard proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} = - let - a0 = firstOrd(a) - a1 = lastOrd(a) - f0 = firstOrd(f) - f1 = lastOrd(f) - if a0 == f0 and a1 == f1: - result = isEqual - elif a0 >= f0 and a1 <= f1: - result = isConvertible - elif a0 <= f1 and f0 <= a1: - # X..Y and C..D overlap iff (X <= D and C <= Y) - result = isConvertible + template check_range_in(t: typedesc): untyped = + let + a0 = firstValue[t](a) + a1 = lastValue[t](a) + f0 = firstValue[t](f) + f1 = lastValue[t](f) + if a0 == f0 and a1 == f1: + result = isEqual + elif a0 >= f0 and a1 <= f1: + result = isConvertible + elif a0 <= f1 and f0 <= a1: + # X..Y and C..D overlap iff (X <= D and C <= Y) + result = isConvertible + else: + result = isNone + + if f.isOrdinalType: + check_range_in(BiggestInt) else: - result = isNone + check_range_in(BiggestFloat) + proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType = var diff --git a/compiler/types.nim b/compiler/types.nim index 5d60fa9b4..19e61a332 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -86,14 +86,33 @@ proc isPureObject*(typ: PType): bool = t = t.sons[0].skipTypes(skipPtrs) result = t.sym != nil and sfPure in t.sym.flags -proc getOrdValue*(n: PNode): BiggestInt = +proc getValue*[T:BiggestInt|BiggestFloat|string](n: PNode): T = + ## get value of liternal node case n.kind - of nkCharLit..nkUInt64Lit: result = n.intVal - of nkNilLit: result = 0 - of nkHiddenStdConv: result = getOrdValue(n.sons[1]) + of nkNilLit: reset(result) + of nkHiddenStdConv: result = getValue[T](n.sons[1]) else: - localError(n.info, errOrdinalTypeExpected) - result = 0 + when T is BiggestInt: + case n.kind + of nkCharLit..nkUInt64Lit: result = n.intVal + else: + localError(n.info, errOrdinalTypeExpected) + result = 0 + elif T is BiggestFloat: + case n.kind + of nkFloatLiterals: result = n.floatVal + else: + localError(n.info, errFloatTypeExpected) + result = NaN + else: + case n.kind: + of nkStrLit..nkTripleStrLit: result = n.strVal + else: + localError(n.info, errStringTypeExpected) + result = nil + +proc getOrdValue*(n: PNode): BiggestInt {.inline.} = + getValue[BiggestInt](n) proc isIntLit*(t: PType): bool {.inline.} = result = t.kind == tyInt and t.n != nil and t.n.kind == nkIntLit @@ -587,79 +606,106 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = result = typeToStr[t.kind] result.addTypeFlags(t) -proc firstOrd*(t: PType): BiggestInt = - case t.kind - of tyBool, tyChar, tySequence, tyOpenArray, tyString, tyVarargs, tyProxy: - result = 0 - of tySet, tyVar: result = firstOrd(t.sons[0]) - of tyArray: result = firstOrd(t.sons[0]) - of tyRange: - assert(t.n != nil) # range directly given: - assert(t.n.kind == nkRange) - result = getOrdValue(t.n.sons[0]) - of tyInt: - if platform.intSize == 4: result = - (2147483646) - 2 - else: result = 0x8000000000000000'i64 - of tyInt8: result = - 128 - of tyInt16: result = - 32768 - of tyInt32: result = - 2147483646 - 2 - of tyInt64: result = 0x8000000000000000'i64 - of tyUInt..tyUInt64: result = 0 - of tyEnum: - # if basetype <> nil then return firstOrd of basetype - if sonsLen(t) > 0 and t.sons[0] != nil: - result = firstOrd(t.sons[0]) +proc firstValue*[T:BiggestInt|BiggestFloat](t: PType): T = + case t.kind: + of tyVar: result = firstValue[T](t.sons[0]) + of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias: + result = firstValue[T](lastSon(t)) + of tyRange: + assert(t.n != nil) # range directly given: + assert(t.n.kind == nkRange) + result = getValue[T](t.n.sons[0]) else: - assert(t.n.sons[0].kind == nkSym) - result = t.n.sons[0].sym.position - of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias: - result = firstOrd(lastSon(t)) - of tyOrdinal: - if t.len > 0: result = firstOrd(lastSon(t)) - else: internalError("invalid kind for first(" & $t.kind & ')') - else: - internalError("invalid kind for first(" & $t.kind & ')') - result = 0 - -proc lastOrd*(t: PType; fixedUnsigned = false): BiggestInt = + when T is BiggestInt: + case t.kind: + of tyBool, tyChar, tySequence, tyOpenArray, tyString, tyVarargs, tyProxy: + result = 0 + of tySet, tyVar: result = firstValue[T](t.sons[0]) + of tyArray: result = firstValue[T](t.sons[0]) + of tyInt: + if platform.intSize == 4: result = - (2147483646) - 2 + else: result = 0x8000000000000000'i64 + of tyInt8: result = - 128 + of tyInt16: result = - 32768 + of tyInt32: result = - 2147483646 - 2 + of tyInt64: result = 0x8000000000000000'i64 + of tyUInt..tyUInt64: result = 0 + of tyEnum: + # if basetype <> nil then return firstOrd of basetype + if sonsLen(t) > 0 and t.sons[0] != nil: + result = firstValue[T](t.sons[0]) + else: + assert(t.n.sons[0].kind == nkSym) + result = t.n.sons[0].sym.position + of tyOrdinal: + if t.len > 0: result = firstValue[T](lastSon(t)) + else: internalError("invalid kind for first(" & $t.kind & ')') + else: + internalError("invalid kind for first(" & $t.kind & ')') + result = 0 + + elif T is BiggestFloat: + case t.kind: + of tyFloat..tyFloat128: result = -Inf + else: + internalError("invalid kind for first(" & $t.kind & ')') + result = NaN + +proc firstOrd*(t: PType): BiggestInt {.inline.} = + firstValue[BiggestInt](t) + +proc lastValue*[T:BiggestInt|BiggestFloat](t: PType; fixedUnsigned = false): T = case t.kind - of tyBool: result = 1 - of tyChar: result = 255 - of tySet, tyVar: result = lastOrd(t.sons[0]) - of tyArray: result = lastOrd(t.sons[0]) + of tyVar: result = lastValue[T](t.sons[0]) + of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias: + result = lastValue[T](lastSon(t)) of tyRange: assert(t.n != nil) # range directly given: assert(t.n.kind == nkRange) - result = getOrdValue(t.n.sons[1]) - of tyInt: - if platform.intSize == 4: result = 0x7FFFFFFF - else: result = 0x7FFFFFFFFFFFFFFF'i64 - of tyInt8: result = 0x0000007F - of tyInt16: result = 0x00007FFF - of tyInt32: result = 0x7FFFFFFF - of tyInt64: result = 0x7FFFFFFFFFFFFFFF'i64 - of tyUInt: - if platform.intSize == 4: result = 0xFFFFFFFF - elif fixedUnsigned: result = 0xFFFFFFFFFFFFFFFF'i64 - else: result = 0x7FFFFFFFFFFFFFFF'i64 - of tyUInt8: result = 0xFF - of tyUInt16: result = 0xFFFF - of tyUInt32: result = 0xFFFFFFFF - of tyUInt64: - if fixedUnsigned: result = 0xFFFFFFFFFFFFFFFF'i64 - else: result = 0x7FFFFFFFFFFFFFFF'i64 - of tyEnum: - assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym) - result = t.n.sons[sonsLen(t.n) - 1].sym.position - of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias: - result = lastOrd(lastSon(t)) - of tyProxy: result = 0 - of tyOrdinal: - if t.len > 0: result = lastOrd(lastSon(t)) - else: internalError("invalid kind for last(" & $t.kind & ')') + result = getValue[T](t.n.sons[1]) else: - internalError("invalid kind for last(" & $t.kind & ')') - result = 0 + when T is BiggestInt: + case t.kind + of tyBool: result = 1 + of tyChar: result = 255 + of tySet, tyArray: result = lastValue[T](t.sons[0]) + of tyInt: + if platform.intSize == 4: result = 0x7FFFFFFF + else: result = 0x7FFFFFFFFFFFFFFF'i64 + of tyInt8: result = 0x0000007F + of tyInt16: result = 0x00007FFF + of tyInt32: result = 0x7FFFFFFF + of tyInt64: result = 0x7FFFFFFFFFFFFFFF'i64 + of tyUInt: + if platform.intSize == 4: result = 0xFFFFFFFF + elif fixedUnsigned: result = 0xFFFFFFFFFFFFFFFF'i64 + else: result = 0x7FFFFFFFFFFFFFFF'i64 + of tyUInt8: result = 0xFF + of tyUInt16: result = 0xFFFF + of tyUInt32: result = 0xFFFFFFFF + of tyUInt64: + if fixedUnsigned: result = 0xFFFFFFFFFFFFFFFF'i64 + else: result = 0x7FFFFFFFFFFFFFFF'i64 + of tyEnum: + assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym) + result = t.n.sons[sonsLen(t.n) - 1].sym.position + + of tyProxy: result = 0 + of tyOrdinal: + if t.len > 0: result = lastValue[T](lastSon(t)) + else: internalError("invalid kind for last(" & $t.kind & ')') + else: + internalError("invalid kind for last(" & $t.kind & ')') + result = 0 + elif T is BiggestFloat: + case t.kind: + of tyFloat..tyFloat128: result = Inf + else: + internalError("invalid kind for first(" & $t.kind & ')') + result = NaN + +proc lastOrd*(t: PType; fixedUnsigned = false): BiggestInt {.inline.}= + lastValue[BiggestInt](t, fixedUnsigned) proc lengthOrd*(t: PType): BiggestInt = case t.kind |