From 8bb74d7e80df4c436a02741d9392a9a608552767 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Andres?= Date: Mon, 20 Feb 2023 11:00:37 +0100 Subject: [PATCH 1/9] Add InlineNumeric prototype skeleton --- InlineNumeric.scala | 50 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 InlineNumeric.scala diff --git a/InlineNumeric.scala b/InlineNumeric.scala new file mode 100644 index 000000000000..e044998e8d70 --- /dev/null +++ b/InlineNumeric.scala @@ -0,0 +1,50 @@ +// community-build/community-projects/stdLib213/src/library/scala/math/Numeric.scala +// community-build/community-projects/stdLib213/src/library/scala/math/Integral.scala +// community-build/community-projects/stdLib213/src/library/scala/math/Fractional.scala + + +trait InlineNumeric[T]: // extends Numeric[T] // TODO can we do this? + transparent inline def plus(inline x: T, inline y: T): T + transparent inline def times(inline x: T, inline y: T): T + // TODO add missing methods +object InlineNumeric: + extension [T](inline x: T)(using inline num: InlineNumeric[T]) + transparent inline def +(inline y: T): T = num.plus(x, y) + transparent inline def *(inline y: T): T = num.times(x, y) + // TODO add missing methods + +trait InlineIntegral[T] extends InlineNumeric[T]: + transparent inline def quot(inline x: T, inline y: T): T + // TODO add missing methods +object InlineIntegral: + // TODO: how are these imported/composed with Numeric/Integral. Should the extension methods be defined in trait InlineIntegral? + extension [T](inline lhs: T)(using inline int: InlineIntegral[T]) + transparent inline def /(inline rhs: T) = int.quot(lhs, rhs) + // TODO add missing methods + +// TODO: InlineFractional + +given IntIsInlineIntegral: InlineIntegral[Int] with + transparent inline def plus(inline x: Int, inline y: Int): Int = x + y + transparent inline def times(inline x: Int, inline y: Int): Int = x * y + transparent inline def quot(inline x: Int, inline y: Int): Int = x / y + // TODO add missing methods + +given ShortIsInlineIntegral: InlineIntegral[Short] with + transparent inline def plus(inline x: Short, inline y: Short): Short = (x + y).toShort + transparent inline def times(inline x: Short, inline y: Short): Short = (x * y).toShort + transparent inline def quot(inline x: Short, inline y: Short): Short = (x / y).toShort + // TODO add missing methods + +// TODO add missing primitive types + +object tests: + import InlineNumeric.* + + // A generic inline operation that inlines/specializes primitive operations + inline def foo[T: InlineNumeric](a: T, b: T) = + a + b * b + + def test(a: Int, b: Int) = + foo(a, b) // should be a + b * b // can check with -Xprint:inlining + foo(a.toShort, b.toShort) // should be a + b * b From a1b4cc3a1a9784cae6d736ac3e2eb0d29595a0b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Andres?= Date: Mon, 20 Feb 2023 14:34:47 +0100 Subject: [PATCH 2/9] Implement missing methods, add examples Add methods missing in the skeleton Add given for all primitive types Add test methods for division, modulo, sign and toInt --- InlineNumeric.scala | 203 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 192 insertions(+), 11 deletions(-) diff --git a/InlineNumeric.scala b/InlineNumeric.scala index e044998e8d70..c011923e1fa2 100644 --- a/InlineNumeric.scala +++ b/InlineNumeric.scala @@ -2,41 +2,200 @@ // community-build/community-projects/stdLib213/src/library/scala/math/Integral.scala // community-build/community-projects/stdLib213/src/library/scala/math/Fractional.scala +import scala.util.Try -trait InlineNumeric[T]: // extends Numeric[T] // TODO can we do this? +trait InlineNumeric[T] extends Ordering[T]: // extends Numeric[T] // TODO can we do this? transparent inline def plus(inline x: T, inline y: T): T + transparent inline def minus(inline x: T, inline y: T): T transparent inline def times(inline x: T, inline y: T): T - // TODO add missing methods + transparent inline def negate(inline x: T): T + transparent inline def fromInt(inline x: Int): T + transparent inline def parseString(inline str: String): Option[T] + transparent inline def toInt(inline x: T): Int + transparent inline def toLong(inline x: T): Long + transparent inline def toFloat(inline x: T): Float + transparent inline def toDouble(inline x: T): Double + + transparent inline def zero = fromInt(0) + transparent inline def one = fromInt(1) + + transparent inline def abs(inline x: T): T = if lt(x, zero) then negate(x) else x + + transparent inline def sign(inline x: T): T = + if lt(x, zero) then negate(one) + else if gt(x, zero) then one + else zero + object InlineNumeric: extension [T](inline x: T)(using inline num: InlineNumeric[T]) transparent inline def +(inline y: T): T = num.plus(x, y) + transparent inline def -(inline y: T) = num.minus(x, y) transparent inline def *(inline y: T): T = num.times(x, y) - // TODO add missing methods + transparent inline def unary_- = num.negate(x) + transparent inline def toInt: Int = num.toInt(x) + transparent inline def toLong: Long = num.toLong(x) + transparent inline def toFloat: Float = num.toFloat(x) + transparent inline def toDouble: Double = num.toDouble(x) + + transparent inline def abs: T = num.abs(x) + + transparent inline def sign: T = num.sign(x) trait InlineIntegral[T] extends InlineNumeric[T]: transparent inline def quot(inline x: T, inline y: T): T - // TODO add missing methods + transparent inline def rem(inline x: T, inline y: T): T + object InlineIntegral: // TODO: how are these imported/composed with Numeric/Integral. Should the extension methods be defined in trait InlineIntegral? extension [T](inline lhs: T)(using inline int: InlineIntegral[T]) transparent inline def /(inline rhs: T) = int.quot(lhs, rhs) - // TODO add missing methods + transparent inline def %(inline rhs: T) = int.rem(lhs, rhs) + transparent inline def /%(inline rhs: T) = (int.quot(lhs, rhs), int.rem(lhs, rhs)) + +trait InlineFractional[T] extends InlineNumeric[T]: + transparent inline def div(inline x: T, inline y: T): T -// TODO: InlineFractional +object InlineFractional: + // TODO: how are these imported/composed with Numeric/Fractional. Should the extension methods be defined in trait InlineFractional? + extension [T](inline lhs: T)(using inline frac: InlineFractional[T]) + transparent inline def /(inline rhs: T) = frac.div(lhs, rhs) -given IntIsInlineIntegral: InlineIntegral[Int] with +given IntIsInlineIntegral: InlineIntegral[Int] with Ordering.IntOrdering with transparent inline def plus(inline x: Int, inline y: Int): Int = x + y + transparent inline def minus(inline x: Int, inline y: Int): Int = x - y transparent inline def times(inline x: Int, inline y: Int): Int = x * y + transparent inline def negate(inline x: Int): Int = -x + transparent inline def fromInt(inline x: Int): Int = x + transparent inline def parseString(inline str: String): Option[Int] = str.toIntOption + transparent inline def toInt(inline x: Int): Int = x + transparent inline def toLong(inline x: Int): Long = x.toLong + transparent inline def toFloat(inline x: Int): Float = x.toFloat + transparent inline def toDouble(inline x: Int): Double = x.toDouble + transparent inline def quot(inline x: Int, inline y: Int): Int = x / y - // TODO add missing methods + transparent inline def rem(inline x: Int, inline y: Int): Int = x % y + +given BigIntIsInlineIntegral: InlineIntegral[BigInt] with Ordering.BigIntOrdering with + transparent inline def plus(inline x: BigInt, inline y: BigInt): BigInt = x + y + transparent inline def minus(inline x: BigInt, inline y: BigInt): BigInt = x - y + transparent inline def times(inline x: BigInt, inline y: BigInt): BigInt = x * y + transparent inline def negate(inline x: BigInt): BigInt = -x + transparent inline def fromInt(inline x: Int): BigInt = BigInt(x) + transparent inline def parseString(inline str: String): Option[BigInt] = Try(BigInt(str)).toOption + transparent inline def toInt(inline x: BigInt): Int = x.intValue + transparent inline def toLong(inline x: BigInt): Long = x.longValue + transparent inline def toFloat(inline x: BigInt): Float = x.floatValue + transparent inline def toDouble(inline x: BigInt): Double = x.doubleValue -given ShortIsInlineIntegral: InlineIntegral[Short] with + transparent inline def quot(inline x: BigInt, inline y: BigInt): BigInt = x / y + transparent inline def rem(inline x: BigInt, inline y: BigInt): BigInt = x % y + +given ShortIsInlineIntegral: InlineIntegral[Short] with Ordering.ShortOrdering with transparent inline def plus(inline x: Short, inline y: Short): Short = (x + y).toShort + transparent inline def minus(inline x: Short, inline y: Short): Short = (x - y).toShort transparent inline def times(inline x: Short, inline y: Short): Short = (x * y).toShort + transparent inline def negate(inline x: Short): Short = (-x).toShort + transparent inline def fromInt(inline x: Int): Short = x.toShort + transparent inline def parseString(inline str: String): Option[Short] = str.toShortOption + transparent inline def toInt(inline x: Short): Int = x.toInt + transparent inline def toLong(inline x: Short): Long = x.toLong + transparent inline def toFloat(inline x: Short): Float = x.toFloat + transparent inline def toDouble(inline x: Short): Double = x.toDouble + transparent inline def quot(inline x: Short, inline y: Short): Short = (x / y).toShort - // TODO add missing methods + transparent inline def rem(inline x: Short, inline y: Short): Short = (x % y).toShort + +given ByteIsInlineIntegral: InlineIntegral[Byte] with Ordering.ByteOrdering with + transparent inline def plus(inline x: Byte, inline y: Byte): Byte = (x + y).toByte + transparent inline def minus(inline x: Byte, inline y: Byte): Byte = (x - y).toByte + transparent inline def times(inline x: Byte, inline y: Byte): Byte = (x * y).toByte + transparent inline def negate(inline x: Byte): Byte = (-x).toByte + transparent inline def fromInt(inline x: Int): Byte = x.toByte + transparent inline def parseString(inline str: String): Option[Byte] = str.toByteOption + transparent inline def toInt(inline x: Byte): Int = x.toInt + transparent inline def toLong(inline x: Byte): Long = x.toLong + transparent inline def toFloat(inline x: Byte): Float = x.toFloat + transparent inline def toDouble(inline x: Byte): Double = x.toDouble + + transparent inline def quot(inline x: Byte, inline y: Byte): Byte = (x / y).toByte + transparent inline def rem(inline x: Byte, inline y: Byte): Byte = (x % y).toByte + +given CharIsInlineIntegral: InlineIntegral[Char] with Ordering.CharOrdering with + transparent inline def plus(inline x: Char, inline y: Char): Char = (x + y).toChar + transparent inline def minus(inline x: Char, inline y: Char): Char = (x - y).toChar + transparent inline def times(inline x: Char, inline y: Char): Char = (x * y).toChar + transparent inline def negate(inline x: Char): Char = (-x).toChar + transparent inline def fromInt(inline x: Int): Char = x.toChar + transparent inline def parseString(inline str: String): Option[Char] = Try(str.toInt.toChar).toOption + transparent inline def toInt(inline x: Char): Int = x.toInt + transparent inline def toLong(inline x: Char): Long = x.toLong + transparent inline def toFloat(inline x: Char): Float = x.toFloat + transparent inline def toDouble(inline x: Char): Double = x.toDouble + + transparent inline def quot(inline x: Char, inline y: Char): Char = (x / y).toChar + transparent inline def rem(inline x: Char, inline y: Char): Char = (x % y).toChar -// TODO add missing primitive types +given LongIsInlineIntegral: InlineIntegral[Long] with Ordering.LongOrdering with + transparent inline def plus(inline x: Long, inline y: Long): Long = x + y + transparent inline def minus(inline x: Long, inline y: Long): Long = x - y + transparent inline def times(inline x: Long, inline y: Long): Long = x * y + transparent inline def negate(inline x: Long): Long = -x + transparent inline def fromInt(inline x: Int): Long = x.toLong + transparent inline def parseString(inline str: String): Option[Long] = str.toLongOption + transparent inline def toInt(inline x: Long): Int = x.toInt + transparent inline def toLong(inline x: Long): Long = x + transparent inline def toFloat(inline x: Long): Float = x.toFloat + transparent inline def toDouble(inline x: Long): Double = x.toDouble + + transparent inline def quot(inline x: Long, inline y: Long): Long = (x / y).toLong + transparent inline def rem(inline x: Long, inline y: Long): Long = (x % y).toLong + +given FloatIsInlineFractional: InlineFractional[Float] with Ordering.Float.IeeeOrdering with + transparent inline def plus(inline x: Float, inline y: Float): Float = x + y + transparent inline def minus(inline x: Float, inline y: Float): Float = x - y + transparent inline def times(inline x: Float, inline y: Float): Float = x * y + transparent inline def negate(inline x: Float): Float = -x + transparent inline def fromInt(inline x: Int): Float = x.toFloat + transparent inline def parseString(inline str: String): Option[Float] = str.toFloatOption + transparent inline def toInt(inline x: Float): Int = x.toInt + transparent inline def toLong(inline x: Float): Long = x.toLong + transparent inline def toFloat(inline x: Float): Float = x + transparent inline def toDouble(inline x: Float): Double = x.toDouble + + transparent inline def div(inline x: Float, inline y: Float): Float = x / y + +given DoubleIsInlineFractional: InlineFractional[Double] with Ordering.Double.IeeeOrdering with + transparent inline def plus(inline x: Double, inline y: Double): Double = x + y + transparent inline def minus(inline x: Double, inline y: Double): Double = x - y + transparent inline def times(inline x: Double, inline y: Double): Double = x * y + transparent inline def negate(inline x: Double): Double = -x + transparent inline def fromInt(inline x: Int): Double = x.toDouble + transparent inline def parseString(inline str: String): Option[Double] = str.toDoubleOption + transparent inline def toInt(inline x: Double): Int = x.toInt + transparent inline def toLong(inline x: Double): Long = x.toLong + transparent inline def toFloat(inline x: Double): Float = x.toFloat + transparent inline def toDouble(inline x: Double): Double = x + + transparent inline def div(inline x: Double, inline y: Double): Double = x / y + +trait BigDecimalIsConflicted extends InlineNumeric[BigDecimal] with Ordering.BigDecimalOrdering: + transparent inline def plus(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x + y + transparent inline def minus(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x - y + transparent inline def times(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x * y + transparent inline def negate(inline x: BigDecimal): BigDecimal = -x + transparent inline def fromInt(inline x: Int): BigDecimal = BigDecimal(x) + transparent inline def parseString(inline str: String): Option[BigDecimal] = Try(BigDecimal(str)).toOption + transparent inline def toInt(inline x: BigDecimal): Int = x.intValue + transparent inline def toLong(inline x: BigDecimal): Long = x.longValue + transparent inline def toFloat(inline x: BigDecimal): Float = x.floatValue + transparent inline def toDouble(inline x: BigDecimal): Double = x.doubleValue + +given BigDecimalIsInlineFractional: BigDecimalIsConflicted with InlineFractional[BigDecimal] with + transparent inline def div(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x / y + +given BigDecimalAsIfInlineIntegral: BigDecimalIsConflicted with InlineIntegral[BigDecimal] with + transparent inline def quot(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x quot y + transparent inline def rem(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x remainder y object tests: import InlineNumeric.* @@ -45,6 +204,28 @@ object tests: inline def foo[T: InlineNumeric](a: T, b: T) = a + b * b + inline def integDiv[T: InlineIntegral](a: T, b: T) = + import InlineIntegral.{/, %} + a / b % b + + inline def fracDiv[T: InlineFractional](a: T, b: T) = + import InlineFractional.{/} + a / b + a + + inline def bar[T: InlineNumeric](a: T) = a.toInt + + inline def sign[T: InlineNumeric](a: T) = a.sign + def test(a: Int, b: Int) = foo(a, b) // should be a + b * b // can check with -Xprint:inlining foo(a.toShort, b.toShort) // should be a + b * b + + integDiv(BigDecimal(a), BigDecimal(b)) // should be BigDecimal(a) quot BigDecimal(b) remainder BigDecimal(b) + fracDiv(BigDecimal(a), BigDecimal(b)) // should be BigDecimal(a) / BigDecimal(b) + BigDecimal(a) + + bar(a.toFloat) // should be a.toFloat.toInt + bar(a) // should be a + + sign(a) + sign(a.toChar) + sign(-7F) From 66db95a0ab9aa04731cdb20defda6224bbc72fc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Andres?= Date: Tue, 21 Feb 2023 11:06:36 +0100 Subject: [PATCH 3/9] Fix mishandling of abs and sign for float and double --- InlineNumeric.scala | 45 ++++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/InlineNumeric.scala b/InlineNumeric.scala index c011923e1fa2..99bd447d6307 100644 --- a/InlineNumeric.scala +++ b/InlineNumeric.scala @@ -15,17 +15,12 @@ trait InlineNumeric[T] extends Ordering[T]: // extends Numeric[T] // TODO can we transparent inline def toLong(inline x: T): Long transparent inline def toFloat(inline x: T): Float transparent inline def toDouble(inline x: T): Double + transparent inline def abs(inline x: T): T + transparent inline def sign(inline x: T): T transparent inline def zero = fromInt(0) transparent inline def one = fromInt(1) - transparent inline def abs(inline x: T): T = if lt(x, zero) then negate(x) else x - - transparent inline def sign(inline x: T): T = - if lt(x, zero) then negate(one) - else if gt(x, zero) then one - else zero - object InlineNumeric: extension [T](inline x: T)(using inline num: InlineNumeric[T]) transparent inline def +(inline y: T): T = num.plus(x, y) @@ -36,12 +31,16 @@ object InlineNumeric: transparent inline def toLong: Long = num.toLong(x) transparent inline def toFloat: Float = num.toFloat(x) transparent inline def toDouble: Double = num.toDouble(x) - transparent inline def abs: T = num.abs(x) - transparent inline def sign: T = num.sign(x) trait InlineIntegral[T] extends InlineNumeric[T]: + transparent inline def abs(inline x: T): T = if lt(x, zero) then negate(x) else x + transparent inline def sign(inline x: T): T = + if lt(x, zero) then negate(one) + else if gt(x, zero) then one + else zero + transparent inline def quot(inline x: T, inline y: T): T transparent inline def rem(inline x: T, inline y: T): T @@ -53,7 +52,16 @@ object InlineIntegral: transparent inline def /%(inline rhs: T) = (int.quot(lhs, rhs), int.rem(lhs, rhs)) trait InlineFractional[T] extends InlineNumeric[T]: + transparent inline def abs(inline x: T): T = if lt(x, zero) || isNegZero(x) then negate(x) else x + transparent inline def sign(inline x: T): T = + if isNaN(x) || isNegZero(x) then x + else if lt(x, zero) then negate(one) + else if gt(x, zero) then one + else zero + transparent inline def div(inline x: T, inline y: T): T + protected transparent inline def isNaN(inline x: T): Boolean + protected transparent inline def isNegZero(inline x: T): Boolean object InlineFractional: // TODO: how are these imported/composed with Numeric/Fractional. Should the extension methods be defined in trait InlineFractional? @@ -163,6 +171,8 @@ given FloatIsInlineFractional: InlineFractional[Float] with Ordering.Float.IeeeO transparent inline def toDouble(inline x: Float): Double = x.toDouble transparent inline def div(inline x: Float, inline y: Float): Float = x / y + protected transparent inline def isNaN(inline x: Float): Boolean = x.isNaN + protected transparent inline def isNegZero(inline x: Float): Boolean = x.equals(-0f) given DoubleIsInlineFractional: InlineFractional[Double] with Ordering.Double.IeeeOrdering with transparent inline def plus(inline x: Double, inline y: Double): Double = x + y @@ -177,6 +187,8 @@ given DoubleIsInlineFractional: InlineFractional[Double] with Ordering.Double.Ie transparent inline def toDouble(inline x: Double): Double = x transparent inline def div(inline x: Double, inline y: Double): Double = x / y + protected transparent inline def isNaN(inline x: Double): Boolean = x.isNaN + protected transparent inline def isNegZero(inline x: Double): Boolean = x.equals(-0.0) trait BigDecimalIsConflicted extends InlineNumeric[BigDecimal] with Ordering.BigDecimalOrdering: transparent inline def plus(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x + y @@ -192,6 +204,9 @@ trait BigDecimalIsConflicted extends InlineNumeric[BigDecimal] with Ordering.Big given BigDecimalIsInlineFractional: BigDecimalIsConflicted with InlineFractional[BigDecimal] with transparent inline def div(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x / y + protected transparent inline def isNaN(inline x: BigDecimal): Boolean = false + protected transparent inline def isNegZero(inline x: BigDecimal): Boolean = false + given BigDecimalAsIfInlineIntegral: BigDecimalIsConflicted with InlineIntegral[BigDecimal] with transparent inline def quot(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x quot y @@ -214,7 +229,8 @@ object tests: inline def bar[T: InlineNumeric](a: T) = a.toInt - inline def sign[T: InlineNumeric](a: T) = a.sign + inline def signInt[T: InlineIntegral](a: T) = a.sign + inline def signFrac[T: InlineFractional](a: T) = a.sign def test(a: Int, b: Int) = foo(a, b) // should be a + b * b // can check with -Xprint:inlining @@ -226,6 +242,9 @@ object tests: bar(a.toFloat) // should be a.toFloat.toInt bar(a) // should be a - sign(a) - sign(a.toChar) - sign(-7F) + signInt(a) + signInt(a.toChar) + signFrac(-7F) + + signInt(BigDecimal(a)) + signFrac(BigDecimal(a)) // the condition with isNan() should be removed From 28bf386ca3a654c0c2b9479dd0538dcc39cdad3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Andres?= Date: Tue, 21 Feb 2023 12:06:54 +0100 Subject: [PATCH 4/9] Use explicit InlineNumeric for BigDecimal --- InlineNumeric.scala | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/InlineNumeric.scala b/InlineNumeric.scala index 99bd447d6307..25a5185287f3 100644 --- a/InlineNumeric.scala +++ b/InlineNumeric.scala @@ -219,32 +219,33 @@ object tests: inline def foo[T: InlineNumeric](a: T, b: T) = a + b * b - inline def integDiv[T: InlineIntegral](a: T, b: T) = + inline def div[T: InlineIntegral](a: T, b: T) = import InlineIntegral.{/, %} a / b % b - inline def fracDiv[T: InlineFractional](a: T, b: T) = + inline def div[T: InlineFractional](a: T, b: T) = import InlineFractional.{/} a / b + a - inline def bar[T: InlineNumeric](a: T) = a.toInt + inline def bar[T: InlineNumeric](a: T) = + a.toInt - inline def signInt[T: InlineIntegral](a: T) = a.sign - inline def signFrac[T: InlineFractional](a: T) = a.sign + inline def sign[T: InlineNumeric](a: T) = + a.sign def test(a: Int, b: Int) = - foo(a, b) // should be a + b * b // can check with -Xprint:inlining - foo(a.toShort, b.toShort) // should be a + b * b + val v1 = foo(a, b) // should be a + b * b // can check with -Xprint:inlining + val v2 = foo(a.toShort, b.toShort) // should be a + b * b - integDiv(BigDecimal(a), BigDecimal(b)) // should be BigDecimal(a) quot BigDecimal(b) remainder BigDecimal(b) - fracDiv(BigDecimal(a), BigDecimal(b)) // should be BigDecimal(a) / BigDecimal(b) + BigDecimal(a) + val v3 = div(BigDecimal(a), BigDecimal(b))(using BigDecimalAsIfInlineIntegral) // should be BigDecimal(a) quot BigDecimal(b) remainder BigDecimal(b) + val v4 = div(BigDecimal(a), BigDecimal(b))(using BigDecimalIsInlineFractional) // should be BigDecimal(a) / BigDecimal(b) + BigDecimal(a) - bar(a.toFloat) // should be a.toFloat.toInt - bar(a) // should be a + val v5 = bar(a.toFloat) // should be a.toFloat.toInt + val v6 = bar(a) // should be a - signInt(a) - signInt(a.toChar) - signFrac(-7F) + val v7 = sign(a) + val v8 = sign(a.toChar) + val v9 = sign(-7F) - signInt(BigDecimal(a)) - signFrac(BigDecimal(a)) // the condition with isNan() should be removed + val v10 = sign(BigDecimal(a))(using BigDecimalAsIfInlineIntegral) + val v11 = sign(BigDecimal(a))(using BigDecimalIsInlineFractional) // the condition with isNan() should be removed, i.e. it should be equivalent to v10 \ No newline at end of file From c8251983a75e30b8135e22588353365fac44ed0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Andres?= Date: Tue, 21 Feb 2023 14:20:21 +0100 Subject: [PATCH 5/9] Inline parameters to shorten generated code --- InlineNumeric.scala | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/InlineNumeric.scala b/InlineNumeric.scala index 25a5185287f3..061f8b11942d 100644 --- a/InlineNumeric.scala +++ b/InlineNumeric.scala @@ -214,23 +214,23 @@ given BigDecimalAsIfInlineIntegral: BigDecimalIsConflicted with InlineIntegral[B object tests: import InlineNumeric.* + import InlineIntegral.{/ => quot, %} + import InlineFractional.{/} // A generic inline operation that inlines/specializes primitive operations - inline def foo[T: InlineNumeric](a: T, b: T) = + inline def foo[T: InlineNumeric](inline a: T, inline b: T) = a + b * b - inline def div[T: InlineIntegral](a: T, b: T) = - import InlineIntegral.{/, %} - a / b % b + inline def div[T: InlineIntegral](inline a: T, inline b: T) = + a quot b % b - inline def div[T: InlineFractional](a: T, b: T) = - import InlineFractional.{/} + inline def div[T: InlineFractional](inline a: T, inline b: T) = a / b + a - inline def bar[T: InlineNumeric](a: T) = + inline def bar[T: InlineNumeric](inline a: T) = a.toInt - inline def sign[T: InlineNumeric](a: T) = + inline def sign[T: InlineNumeric](inline a: T) = a.sign def test(a: Int, b: Int) = From 563f2c5a755eba625abdc87852cb76191de7522a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Andres?= Date: Tue, 21 Feb 2023 14:37:19 +0100 Subject: [PATCH 6/9] Use symbol for integral division --- InlineNumeric.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/InlineNumeric.scala b/InlineNumeric.scala index 061f8b11942d..265343dfc793 100644 --- a/InlineNumeric.scala +++ b/InlineNumeric.scala @@ -214,7 +214,7 @@ given BigDecimalAsIfInlineIntegral: BigDecimalIsConflicted with InlineIntegral[B object tests: import InlineNumeric.* - import InlineIntegral.{/ => quot, %} + import InlineIntegral.{/ => ¦, %} import InlineFractional.{/} // A generic inline operation that inlines/specializes primitive operations @@ -222,7 +222,7 @@ object tests: a + b * b inline def div[T: InlineIntegral](inline a: T, inline b: T) = - a quot b % b + a ¦ b % b inline def div[T: InlineFractional](inline a: T, inline b: T) = a / b + a From 2113507cca507c041dea67c385423865a4833689 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Andres?= Date: Tue, 21 Feb 2023 16:54:05 +0100 Subject: [PATCH 7/9] Create two new versions of InlineNumeric Create version of InlineNumeric that extends Numeric. This requires: - dropping the inline keyword for parameters (cannot override non-inline parameter with inline parameter) - dropping abs, sign, zero and one from InlineNumeric (see code for the errors). Instead, override them in the given instances Create version of InlineNumeric with extension methods defined in the traits instead of in the companion objects. This allows the usage of said methods without having to import them. The inconvenient is that the overriding must be done with extension methods, but since an extension method object A: extension (x: T) def foo: U = ??? can be called both like x.foo and A.foo(x), this allows for both forms when performing operations such as toInt. --- InlineNumeric-extendsNumeric.scala | 242 ++++++++++++++++++++++++ InlineNumeric-extensionsInTrait.scala | 263 ++++++++++++++++++++++++++ 2 files changed, 505 insertions(+) create mode 100644 InlineNumeric-extendsNumeric.scala create mode 100644 InlineNumeric-extensionsInTrait.scala diff --git a/InlineNumeric-extendsNumeric.scala b/InlineNumeric-extendsNumeric.scala new file mode 100644 index 000000000000..0c0587c8c416 --- /dev/null +++ b/InlineNumeric-extendsNumeric.scala @@ -0,0 +1,242 @@ +import scala.util.Try + +trait InlineNumeric[T] extends Numeric[T]: + transparent inline def plus(x: T, y: T): T + transparent inline def minus(x: T, y: T): T + transparent inline def times(x: T, y: T): T + transparent inline def negate(x: T): T + transparent inline def fromInt(x: Int): T + transparent inline def parseString(str: String): Option[T] + transparent inline def toInt(x: T): Int + transparent inline def toLong(x: T): Long + transparent inline def toFloat(x: T): Float + transparent inline def toDouble(x: T): Double + + // error overriding method abs in trait InlineNumeric of type (x: T): T; + // method abs in trait Numeric of type (x: T): T is not inline, cannot implement an inline method + //transparent inline def abs(x: T): T + //transparent inline def sign(x: T): T + + // Deferred inline method fromInt in trait InlineNumeric cannot be invoked + //transparent inline def zero = fromInt(0) + //transparent inline def one = fromInt(1) + +object InlineNumeric: + extension [T](x: T)(using num: InlineNumeric[T]) + transparent inline def +(y: T): T = num.plus(x, y) + transparent inline def -(y: T) = num.minus(x, y) + transparent inline def *(y: T): T = num.times(x, y) + transparent inline def unary_- = num.negate(x) + transparent inline def toInt: Int = num.toInt(x) + transparent inline def toLong: Long = num.toLong(x) + transparent inline def toFloat: Float = num.toFloat(x) + transparent inline def toDouble: Double = num.toDouble(x) + transparent inline def abs: T = num.abs(x) + transparent inline def sign: T = num.sign(x) + +trait InlineIntegral[T] extends InlineNumeric[T]: + transparent inline def quot(x: T, y: T): T + transparent inline def rem(x: T, y: T): T + +object InlineIntegral: + extension [T](lhs: T)(using int: InlineIntegral[T]) + transparent inline def /(rhs: T) = int.quot(lhs, rhs) + transparent inline def %(rhs: T) = int.rem(lhs, rhs) + transparent inline def /%(rhs: T) = (int.quot(lhs, rhs), int.rem(lhs, rhs)) + +trait InlineFractional[T] extends InlineNumeric[T]: + transparent inline def div(x: T, y: T): T + +object InlineFractional: + extension [T](lhs: T)(using frac: InlineFractional[T]) + transparent inline def /(rhs: T) = frac.div(lhs, rhs) + +given IntIsInlineIntegral: InlineIntegral[Int] with Ordering.IntOrdering with + transparent inline def plus(x: Int, y: Int): Int = x + y + transparent inline def minus(x: Int, y: Int): Int = x - y + transparent inline def times(x: Int, y: Int): Int = x * y + transparent inline def negate(x: Int): Int = -x + transparent inline def fromInt(x: Int): Int = x + transparent inline def parseString(str: String): Option[Int] = str.toIntOption + transparent inline def toInt(x: Int): Int = x + transparent inline def toLong(x: Int): Long = x.toLong + transparent inline def toFloat(x: Int): Float = x.toFloat + transparent inline def toDouble(x: Int): Double = x.toDouble + transparent override inline def abs(x: Int): Int = math.abs(x) + transparent override inline def sign(x: Int): Int = math.signum(x) + + transparent inline def quot(x: Int, y: Int): Int = x / y + transparent inline def rem(x: Int, y: Int): Int = x % y + +given BigIntIsInlineIntegral: InlineIntegral[BigInt] with Ordering.BigIntOrdering with + transparent inline def plus(x: BigInt, y: BigInt): BigInt = x + y + transparent inline def minus(x: BigInt, y: BigInt): BigInt = x - y + transparent inline def times(x: BigInt, y: BigInt): BigInt = x * y + transparent inline def negate(x: BigInt): BigInt = -x + transparent inline def fromInt(x: Int): BigInt = BigInt(x) + transparent inline def parseString(str: String): Option[BigInt] = Try(BigInt(str)).toOption + transparent inline def toInt(x: BigInt): Int = x.intValue + transparent inline def toLong(x: BigInt): Long = x.longValue + transparent inline def toFloat(x: BigInt): Float = x.floatValue + transparent inline def toDouble(x: BigInt): Double = x.doubleValue + transparent override inline def abs(x: BigInt): BigInt = x.abs + transparent override inline def sign(x: BigInt): BigInt = x.sign + + transparent inline def quot(x: BigInt, y: BigInt): BigInt = x / y + transparent inline def rem(x: BigInt, y: BigInt): BigInt = x % y + +given ShortIsInlineIntegral: InlineIntegral[Short] with Ordering.ShortOrdering with + transparent inline def plus(x: Short, y: Short): Short = (x + y).toShort + transparent inline def minus(x: Short, y: Short): Short = (x - y).toShort + transparent inline def times(x: Short, y: Short): Short = (x * y).toShort + transparent inline def negate(x: Short): Short = (-x).toShort + transparent inline def fromInt(x: Int): Short = x.toShort + transparent inline def parseString(str: String): Option[Short] = str.toShortOption + transparent inline def toInt(x: Short): Int = x.toInt + transparent inline def toLong(x: Short): Long = x.toLong + transparent inline def toFloat(x: Short): Float = x.toFloat + transparent inline def toDouble(x: Short): Double = x.toDouble + transparent override inline def abs(x: Short): Short = math.abs(x).toShort + transparent override inline def sign(x: Short): Short = math.signum(x).toShort + + transparent inline def quot(x: Short, y: Short): Short = (x / y).toShort + transparent inline def rem(x: Short, y: Short): Short = (x % y).toShort + +given ByteIsInlineIntegral: InlineIntegral[Byte] with Ordering.ByteOrdering with + transparent inline def plus(x: Byte, y: Byte): Byte = (x + y).toByte + transparent inline def minus(x: Byte, y: Byte): Byte = (x - y).toByte + transparent inline def times(x: Byte, y: Byte): Byte = (x * y).toByte + transparent inline def negate(x: Byte): Byte = (-x).toByte + transparent inline def fromInt(x: Int): Byte = x.toByte + transparent inline def parseString(str: String): Option[Byte] = str.toByteOption + transparent inline def toInt(x: Byte): Int = x.toInt + transparent inline def toLong(x: Byte): Long = x.toLong + transparent inline def toFloat(x: Byte): Float = x.toFloat + transparent inline def toDouble(x: Byte): Double = x.toDouble + transparent override inline def abs(x: Byte): Byte = math.abs(x).toByte + transparent override inline def sign(x: Byte): Byte = math.signum(x).toByte + + transparent inline def quot(x: Byte, y: Byte): Byte = (x / y).toByte + transparent inline def rem(x: Byte, y: Byte): Byte = (x % y).toByte + +given CharIsInlineIntegral: InlineIntegral[Char] with Ordering.CharOrdering with + transparent inline def plus(x: Char, y: Char): Char = (x + y).toChar + transparent inline def minus(x: Char, y: Char): Char = (x - y).toChar + transparent inline def times(x: Char, y: Char): Char = (x * y).toChar + transparent inline def negate(x: Char): Char = (-x).toChar + transparent inline def fromInt(x: Int): Char = x.toChar + transparent inline def parseString(str: String): Option[Char] = Try(str.toInt.toChar).toOption + transparent inline def toInt(x: Char): Int = x.toInt + transparent inline def toLong(x: Char): Long = x.toLong + transparent inline def toFloat(x: Char): Float = x.toFloat + transparent inline def toDouble(x: Char): Double = x.toDouble + transparent override inline def abs(x: Char): Char = math.abs(x).toChar + transparent override inline def sign(x: Char): Char = math.signum(x).toChar + + transparent inline def quot(x: Char, y: Char): Char = (x / y).toChar + transparent inline def rem(x: Char, y: Char): Char = (x % y).toChar + +given LongIsInlineIntegral: InlineIntegral[Long] with Ordering.LongOrdering with + transparent inline def plus(x: Long, y: Long): Long = x + y + transparent inline def minus(x: Long, y: Long): Long = x - y + transparent inline def times(x: Long, y: Long): Long = x * y + transparent inline def negate(x: Long): Long = -x + transparent inline def fromInt(x: Int): Long = x.toLong + transparent inline def parseString(str: String): Option[Long] = str.toLongOption + transparent inline def toInt(x: Long): Int = x.toInt + transparent inline def toLong(x: Long): Long = x + transparent inline def toFloat(x: Long): Float = x.toFloat + transparent inline def toDouble(x: Long): Double = x.toDouble + transparent override inline def abs(x: Long): Long = math.abs(x) + transparent override inline def sign(x: Long): Long = math.signum(x) + + transparent inline def quot(x: Long, y: Long): Long = (x / y).toLong + transparent inline def rem(x: Long, y: Long): Long = (x % y).toLong + +given FloatIsInlineFractional: InlineFractional[Float] with Ordering.Float.IeeeOrdering with + transparent inline def plus(x: Float, y: Float): Float = x + y + transparent inline def minus(x: Float, y: Float): Float = x - y + transparent inline def times(x: Float, y: Float): Float = x * y + transparent inline def negate(x: Float): Float = -x + transparent inline def fromInt(x: Int): Float = x.toFloat + transparent inline def parseString(str: String): Option[Float] = str.toFloatOption + transparent inline def toInt(x: Float): Int = x.toInt + transparent inline def toLong(x: Float): Long = x.toLong + transparent inline def toFloat(x: Float): Float = x + transparent inline def toDouble(x: Float): Double = x.toDouble + transparent override inline def abs(x: Float): Float = math.abs(x) + transparent override inline def sign(x: Float): Float = math.signum(x) + + transparent inline def div(x: Float, y: Float): Float = x / y + +given DoubleIsInlineFractional: InlineFractional[Double] with Ordering.Double.IeeeOrdering with + transparent inline def plus(x: Double, y: Double): Double = x + y + transparent inline def minus(x: Double, y: Double): Double = x - y + transparent inline def times(x: Double, y: Double): Double = x * y + transparent inline def negate(x: Double): Double = -x + transparent inline def fromInt(x: Int): Double = x.toDouble + transparent inline def parseString(str: String): Option[Double] = str.toDoubleOption + transparent inline def toInt(x: Double): Int = x.toInt + transparent inline def toLong(x: Double): Long = x.toLong + transparent inline def toFloat(x: Double): Float = x.toFloat + transparent inline def toDouble(x: Double): Double = x + transparent override inline def abs(x: Double): Double = math.abs(x) + transparent override inline def sign(x: Double): Double = math.signum(x) + + transparent inline def div(x: Double, y: Double): Double = x / y + +trait BigDecimalIsConflicted extends InlineNumeric[BigDecimal] with Ordering.BigDecimalOrdering: + transparent inline def plus(x: BigDecimal, y: BigDecimal): BigDecimal = x + y + transparent inline def minus(x: BigDecimal, y: BigDecimal): BigDecimal = x - y + transparent inline def times(x: BigDecimal, y: BigDecimal): BigDecimal = x * y + transparent inline def negate(x: BigDecimal): BigDecimal = -x + transparent inline def fromInt(x: Int): BigDecimal = BigDecimal(x) + transparent inline def parseString(str: String): Option[BigDecimal] = Try(BigDecimal(str)).toOption + transparent inline def toInt(x: BigDecimal): Int = x.intValue + transparent inline def toLong(x: BigDecimal): Long = x.longValue + transparent inline def toFloat(x: BigDecimal): Float = x.floatValue + transparent inline def toDouble(x: BigDecimal): Double = x.doubleValue + transparent override inline def abs(x: BigDecimal): BigDecimal = x.abs + transparent override inline def sign(x: BigDecimal): BigDecimal = x.sign + +given BigDecimalIsInlineFractional: BigDecimalIsConflicted with InlineFractional[BigDecimal] with + transparent inline def div(x: BigDecimal, y: BigDecimal): BigDecimal = x / y + +given BigDecimalAsIfInlineIntegral: BigDecimalIsConflicted with InlineIntegral[BigDecimal] with + transparent inline def quot(x: BigDecimal, y: BigDecimal): BigDecimal = x quot y + transparent inline def rem(x: BigDecimal, y: BigDecimal): BigDecimal = x remainder y + +object tests: + import InlineNumeric.* + import InlineIntegral.{/ => ¦, %} + import InlineFractional./ + + inline def foo[T: InlineNumeric](a: T, b: T) = + a + b * b + + inline def div[T: InlineIntegral](a: T, b: T) = + a ¦ b % b + + inline def div[T: InlineFractional](a: T, b: T) = + a / b + a + + inline def bar[T: InlineNumeric](a: T) = a.toInt + + inline def sign[T: InlineNumeric](a: T) = a.sign + + def test(a: Int, b: Int) = + val v1 = foo(a, b) // should be a + b * b // can check with -Xprint:inlining + val v2 = foo(a.toShort, b.toShort) // should be a + b * b + + val v3 = div(BigDecimal(a), BigDecimal(b))(using BigDecimalAsIfInlineIntegral) // should be BigDecimal(a) quot BigDecimal(b) remainder BigDecimal(b) + val v4 = div(BigDecimal(a), BigDecimal(b))(using BigDecimalIsInlineFractional) // should be BigDecimal(a) / BigDecimal(b) + BigDecimal(a) + + val v5 = bar(a.toFloat) // should be a.toFloat.toInt + val v6 = bar(a) // should be a + + val v7 = sign(a) + val v8 = sign(a.toChar) + val v9 = sign(-7F) + + val v10 = sign(BigDecimal(a))(using BigDecimalAsIfInlineIntegral) + val v11 = sign(BigDecimal(a))(using BigDecimalIsInlineFractional) // the condition with isNan() should be removed, i.e. it should be equivalent to v10 \ No newline at end of file diff --git a/InlineNumeric-extensionsInTrait.scala b/InlineNumeric-extensionsInTrait.scala new file mode 100644 index 000000000000..bac390783e65 --- /dev/null +++ b/InlineNumeric-extensionsInTrait.scala @@ -0,0 +1,263 @@ +import scala.util.Try + +trait InlineNumeric[T] extends Ordering[T]: // extends Numeric[T] // TODO can we do this? + transparent inline def plus(inline x: T, inline y: T): T + transparent inline def minus(inline x: T, inline y: T): T + transparent inline def times(inline x: T, inline y: T): T + transparent inline def negate(inline x: T): T + transparent inline def fromInt(inline x: Int): T + transparent inline def parseString(inline str: String): Option[T] + + transparent inline def zero = fromInt(0) + transparent inline def one = fromInt(1) + + extension (inline x: T) + transparent inline def +(inline y: T): T = plus(x, y) + transparent inline def -(inline y: T) = minus(x, y) + transparent inline def *(inline y: T): T = times(x, y) + transparent inline def unary_- = negate(x) + transparent inline def toInt: Int + transparent inline def toLong: Long + transparent inline def toFloat: Float + transparent inline def toDouble: Double + transparent inline def abs: T + transparent inline def sign: T + +trait InlineIntegral[T] extends InlineNumeric[T]: + transparent inline def quot(inline x: T, inline y: T): T + transparent inline def rem(inline x: T, inline y: T): T + + extension (inline lhs: T) + transparent inline def /(inline rhs: T) = quot(lhs, rhs) + transparent inline def %(inline rhs: T) = rem(lhs, rhs) + transparent inline def /%(inline rhs: T) = (quot(lhs, rhs), rem(lhs, rhs)) + + transparent inline def abs: T = if lt(lhs, zero) then negate(lhs) else lhs + transparent inline def sign: T = + if lt(lhs, zero) then negate(one) + else if gt(lhs, zero) then one + else zero + +trait InlineFractional[T] extends InlineNumeric[T]: + transparent inline def div(inline x: T, inline y: T): T + protected transparent inline def isNaN(inline x: T): Boolean + protected transparent inline def isNegZero(inline x: T): Boolean + + extension (inline lhs: T) + transparent inline def /(inline rhs: T) = div(lhs, rhs) + transparent inline def abs: T = if lt(lhs, zero) || isNegZero(lhs) then negate(lhs) else lhs + transparent inline def sign: T = + if isNaN(lhs) || isNegZero(lhs) then lhs + else if lt(lhs, zero) then negate(one) + else if gt(lhs, zero) then one + else zero + +given IntIsInlineIntegral: InlineIntegral[Int] with Ordering.IntOrdering with + transparent inline def plus(inline x: Int, inline y: Int): Int = x + y + transparent inline def minus(inline x: Int, inline y: Int): Int = x - y + transparent inline def times(inline x: Int, inline y: Int): Int = x * y + transparent inline def negate(inline x: Int): Int = -x + transparent inline def fromInt(inline x: Int): Int = x + transparent inline def parseString(inline str: String): Option[Int] = str.toIntOption + + transparent inline def quot(inline x: Int, inline y: Int): Int = x / y + transparent inline def rem(inline x: Int, inline y: Int): Int = x % y + + extension (inline x: Int) + transparent inline def toInt: Int = x + transparent inline def toLong: Long = x.toLong + transparent inline def toFloat: Float = x.toFloat + transparent inline def toDouble: Double = x.toDouble + +given BigIntIsInlineIntegral: InlineIntegral[BigInt] with Ordering.BigIntOrdering with + transparent inline def plus(inline x: BigInt, inline y: BigInt): BigInt = x + y + transparent inline def minus(inline x: BigInt, inline y: BigInt): BigInt = x - y + transparent inline def times(inline x: BigInt, inline y: BigInt): BigInt = x * y + transparent inline def negate(inline x: BigInt): BigInt = -x + transparent inline def fromInt(inline x: Int): BigInt = BigInt(x) + transparent inline def parseString(inline str: String): Option[BigInt] = Try(BigInt(str)).toOption + + transparent inline def quot(inline x: BigInt, inline y: BigInt): BigInt = x / y + transparent inline def rem(inline x: BigInt, inline y: BigInt): BigInt = x % y + + extension (inline x: BigInt) + transparent inline def toInt: Int = x.intValue + transparent inline def toLong: Long = x.longValue + transparent inline def toFloat: Float = x.floatValue + transparent inline def toDouble: Double = x.doubleValue + +given ShortIsInlineIntegral: InlineIntegral[Short] with Ordering.ShortOrdering with + transparent inline def plus(inline x: Short, inline y: Short): Short = (x + y).toShort + transparent inline def minus(inline x: Short, inline y: Short): Short = (x - y).toShort + transparent inline def times(inline x: Short, inline y: Short): Short = (x * y).toShort + transparent inline def negate(inline x: Short): Short = (-x).toShort + transparent inline def fromInt(inline x: Int): Short = x.toShort + transparent inline def parseString(inline str: String): Option[Short] = str.toShortOption + + transparent inline def quot(inline x: Short, inline y: Short): Short = (x / y).toShort + transparent inline def rem(inline x: Short, inline y: Short): Short = (x % y).toShort + + extension (inline x: Short) + transparent inline def toInt: Int = x.toInt + transparent inline def toLong: Long = x.toLong + transparent inline def toFloat: Float = x.toFloat + transparent inline def toDouble: Double = x.toDouble + +given ByteIsInlineIntegral: InlineIntegral[Byte] with Ordering.ByteOrdering with + transparent inline def plus(inline x: Byte, inline y: Byte): Byte = (x + y).toByte + transparent inline def minus(inline x: Byte, inline y: Byte): Byte = (x - y).toByte + transparent inline def times(inline x: Byte, inline y: Byte): Byte = (x * y).toByte + transparent inline def negate(inline x: Byte): Byte = (-x).toByte + transparent inline def fromInt(inline x: Int): Byte = x.toByte + transparent inline def parseString(inline str: String): Option[Byte] = str.toByteOption + + transparent inline def quot(inline x: Byte, inline y: Byte): Byte = (x / y).toByte + transparent inline def rem(inline x: Byte, inline y: Byte): Byte = (x % y).toByte + + extension (inline x: Byte) + transparent inline def toInt: Int = x.toInt + transparent inline def toLong: Long = x.toLong + transparent inline def toFloat: Float = x.toFloat + transparent inline def toDouble: Double = x.toDouble + +given CharIsInlineIntegral: InlineIntegral[Char] with Ordering.CharOrdering with + transparent inline def plus(inline x: Char, inline y: Char): Char = (x + y).toChar + transparent inline def minus(inline x: Char, inline y: Char): Char = (x - y).toChar + transparent inline def times(inline x: Char, inline y: Char): Char = (x * y).toChar + transparent inline def negate(inline x: Char): Char = (-x).toChar + transparent inline def fromInt(inline x: Int): Char = x.toChar + transparent inline def parseString(inline str: String): Option[Char] = Try(str.toInt.toChar).toOption + + transparent inline def quot(inline x: Char, inline y: Char): Char = (x / y).toChar + transparent inline def rem(inline x: Char, inline y: Char): Char = (x % y).toChar + + extension (inline x: Char) + transparent inline def toInt: Int = x.toInt + transparent inline def toLong: Long = x.toLong + transparent inline def toFloat: Float = x.toFloat + transparent inline def toDouble: Double = x.toDouble + +given LongIsInlineIntegral: InlineIntegral[Long] with Ordering.LongOrdering with + transparent inline def plus(inline x: Long, inline y: Long): Long = x + y + transparent inline def minus(inline x: Long, inline y: Long): Long = x - y + transparent inline def times(inline x: Long, inline y: Long): Long = x * y + transparent inline def negate(inline x: Long): Long = -x + transparent inline def fromInt(inline x: Int): Long = x.toLong + transparent inline def parseString(inline str: String): Option[Long] = str.toLongOption + + transparent inline def quot(inline x: Long, inline y: Long): Long = (x / y).toLong + transparent inline def rem(inline x: Long, inline y: Long): Long = (x % y).toLong + + extension (inline x: Long) + transparent inline def toInt: Int = x.toInt + transparent inline def toLong: Long = x + transparent inline def toFloat: Float = x.toFloat + transparent inline def toDouble: Double = x.toDouble + +given FloatIsInlineFractional: InlineFractional[Float] with Ordering.Float.IeeeOrdering with + transparent inline def plus(inline x: Float, inline y: Float): Float = x + y + transparent inline def minus(inline x: Float, inline y: Float): Float = x - y + transparent inline def times(inline x: Float, inline y: Float): Float = x * y + transparent inline def negate(inline x: Float): Float = -x + transparent inline def fromInt(inline x: Int): Float = x.toFloat + transparent inline def parseString(inline str: String): Option[Float] = str.toFloatOption + + transparent inline def div(inline x: Float, inline y: Float): Float = x / y + protected transparent inline def isNaN(inline x: Float): Boolean = x.isNaN + protected transparent inline def isNegZero(inline x: Float): Boolean = x.equals(-0f) + + extension (inline x: Float) + transparent inline def toInt: Int = x.toInt + transparent inline def toLong: Long = x.toLong + transparent inline def toFloat: Float = x + transparent inline def toDouble: Double = x.toDouble + +given DoubleIsInlineFractional: InlineFractional[Double] with Ordering.Double.IeeeOrdering with + transparent inline def plus(inline x: Double, inline y: Double): Double = x + y + transparent inline def minus(inline x: Double, inline y: Double): Double = x - y + transparent inline def times(inline x: Double, inline y: Double): Double = x * y + transparent inline def negate(inline x: Double): Double = -x + transparent inline def fromInt(inline x: Int): Double = x.toDouble + transparent inline def parseString(inline str: String): Option[Double] = str.toDoubleOption + + transparent inline def div(inline x: Double, inline y: Double): Double = x / y + protected transparent inline def isNaN(inline x: Double): Boolean = x.isNaN + protected transparent inline def isNegZero(inline x: Double): Boolean = x.equals(-0.0) + + extension (inline x: Double) + transparent inline def toInt: Int = x.toInt + transparent inline def toLong: Long = x.toLong + transparent inline def toFloat: Float = x.toFloat + transparent inline def toDouble: Double = x.toDouble + +trait BigDecimalIsConflicted extends InlineNumeric[BigDecimal] with Ordering.BigDecimalOrdering: + transparent inline def plus(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x + y + transparent inline def minus(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x - y + transparent inline def times(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x * y + transparent inline def negate(inline x: BigDecimal): BigDecimal = -x + transparent inline def fromInt(inline x: Int): BigDecimal = BigDecimal(x) + transparent inline def parseString(inline str: String): Option[BigDecimal] = Try(BigDecimal(str)).toOption + + extension (inline x: BigDecimal) + transparent inline def toInt: Int = x.intValue + transparent inline def toLong: Long = x.longValue + transparent inline def toFloat: Float = x.floatValue + transparent inline def toDouble: Double = x.doubleValue + +given BigDecimalIsInlineFractional: BigDecimalIsConflicted with InlineFractional[BigDecimal] with + transparent inline def div(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x / y + protected transparent inline def isNaN(inline x: BigDecimal): Boolean = false + protected transparent inline def isNegZero(inline x: BigDecimal): Boolean = false + + +given BigDecimalAsIfInlineIntegral: BigDecimalIsConflicted with InlineIntegral[BigDecimal] with + transparent inline def quot(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x quot y + transparent inline def rem(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x remainder y + +object tests: + // A generic inline operation that inlines/specializes primitive operations + inline def foo[T: InlineNumeric](inline a: T, inline b: T) = + a + b * b + + inline def div[T: InlineIntegral](inline a: T, inline b: T) = + a / b % b + + inline def div[T: InlineFractional](inline a: T, inline b: T) = + a / b + a + + inline def toInt[T: InlineNumeric](inline a: T) = + a.toInt + + inline def explicitToInt[T](inline a: T)(using n: InlineNumeric[T]) = + n.toInt(a) + + inline def sign[T: InlineNumeric](inline a: T) = + a.sign + + inline def explicitPlus[T](inline a: T, inline b: T)(using n: InlineNumeric[T]) = + n.plus(a, b) + + def test(a: Int, b: Int) = + val v1 = foo(a, b) // should be a + b * b // can check with -Xprint:inlining + val v2 = foo(a.toShort, b.toShort) // should be a + b * b + + val v3 = div(BigDecimal(a), BigDecimal(b))(using BigDecimalAsIfInlineIntegral) // should be BigDecimal(a) quot BigDecimal(b) remainder BigDecimal(b) + val v4 = div(BigDecimal(a), BigDecimal(b))(using BigDecimalIsInlineFractional) // should be BigDecimal(a) / BigDecimal(b) + BigDecimal(a) + + val v5 = toInt(a.toFloat) // should be a.toFloat.toInt + val v6 = toInt(a) // should be a + + val v7 = sign(a) + val v8 = sign(a.toChar) + val v9 = sign(-7F) + + val v10 = sign(BigDecimal(a))(using BigDecimalAsIfInlineIntegral) + val v11 = sign(BigDecimal(a))(using BigDecimalIsInlineFractional) // the condition with isNan() should be removed, i.e. it should be equivalent to v10 + + val v12 = explicitPlus(3, 5) // should be 8 + val v13 = explicitPlus(a, b) // should be a + b + + val v14 = explicitToInt(3.2) // should be (3.2).toInt + val v15 = explicitToInt(3) // should be 3 + val v16 = explicitToInt(a) // should be a + val v17 = explicitToInt(a.toShort) // should be a.toShort.toInt \ No newline at end of file From 4e27a3acf829d36f35e37249c52af0b4b60be5b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Andres?= Date: Fri, 24 Feb 2023 10:31:38 +0100 Subject: [PATCH 8/9] Create clean test for inline Numeric Split code into separate files for clarity Reimplement Numeric and Ordering as inline Place symbols in the trait --- InlineNumeric-extendsNumeric.scala | 242 -------------------- InlineNumeric-extensionsInTrait.scala | 263 ---------------------- InlineNumeric.scala | 251 --------------------- tests/run/inline-numeric/Fractional.scala | 62 +++++ tests/run/inline-numeric/Integral.scala | 132 +++++++++++ tests/run/inline-numeric/Numeric.scala | 43 ++++ tests/run/inline-numeric/Ordering.scala | 56 +++++ tests/run/inline-numeric/test.scala | 54 +++++ 8 files changed, 347 insertions(+), 756 deletions(-) delete mode 100644 InlineNumeric-extendsNumeric.scala delete mode 100644 InlineNumeric-extensionsInTrait.scala delete mode 100644 InlineNumeric.scala create mode 100644 tests/run/inline-numeric/Fractional.scala create mode 100644 tests/run/inline-numeric/Integral.scala create mode 100644 tests/run/inline-numeric/Numeric.scala create mode 100644 tests/run/inline-numeric/Ordering.scala create mode 100644 tests/run/inline-numeric/test.scala diff --git a/InlineNumeric-extendsNumeric.scala b/InlineNumeric-extendsNumeric.scala deleted file mode 100644 index 0c0587c8c416..000000000000 --- a/InlineNumeric-extendsNumeric.scala +++ /dev/null @@ -1,242 +0,0 @@ -import scala.util.Try - -trait InlineNumeric[T] extends Numeric[T]: - transparent inline def plus(x: T, y: T): T - transparent inline def minus(x: T, y: T): T - transparent inline def times(x: T, y: T): T - transparent inline def negate(x: T): T - transparent inline def fromInt(x: Int): T - transparent inline def parseString(str: String): Option[T] - transparent inline def toInt(x: T): Int - transparent inline def toLong(x: T): Long - transparent inline def toFloat(x: T): Float - transparent inline def toDouble(x: T): Double - - // error overriding method abs in trait InlineNumeric of type (x: T): T; - // method abs in trait Numeric of type (x: T): T is not inline, cannot implement an inline method - //transparent inline def abs(x: T): T - //transparent inline def sign(x: T): T - - // Deferred inline method fromInt in trait InlineNumeric cannot be invoked - //transparent inline def zero = fromInt(0) - //transparent inline def one = fromInt(1) - -object InlineNumeric: - extension [T](x: T)(using num: InlineNumeric[T]) - transparent inline def +(y: T): T = num.plus(x, y) - transparent inline def -(y: T) = num.minus(x, y) - transparent inline def *(y: T): T = num.times(x, y) - transparent inline def unary_- = num.negate(x) - transparent inline def toInt: Int = num.toInt(x) - transparent inline def toLong: Long = num.toLong(x) - transparent inline def toFloat: Float = num.toFloat(x) - transparent inline def toDouble: Double = num.toDouble(x) - transparent inline def abs: T = num.abs(x) - transparent inline def sign: T = num.sign(x) - -trait InlineIntegral[T] extends InlineNumeric[T]: - transparent inline def quot(x: T, y: T): T - transparent inline def rem(x: T, y: T): T - -object InlineIntegral: - extension [T](lhs: T)(using int: InlineIntegral[T]) - transparent inline def /(rhs: T) = int.quot(lhs, rhs) - transparent inline def %(rhs: T) = int.rem(lhs, rhs) - transparent inline def /%(rhs: T) = (int.quot(lhs, rhs), int.rem(lhs, rhs)) - -trait InlineFractional[T] extends InlineNumeric[T]: - transparent inline def div(x: T, y: T): T - -object InlineFractional: - extension [T](lhs: T)(using frac: InlineFractional[T]) - transparent inline def /(rhs: T) = frac.div(lhs, rhs) - -given IntIsInlineIntegral: InlineIntegral[Int] with Ordering.IntOrdering with - transparent inline def plus(x: Int, y: Int): Int = x + y - transparent inline def minus(x: Int, y: Int): Int = x - y - transparent inline def times(x: Int, y: Int): Int = x * y - transparent inline def negate(x: Int): Int = -x - transparent inline def fromInt(x: Int): Int = x - transparent inline def parseString(str: String): Option[Int] = str.toIntOption - transparent inline def toInt(x: Int): Int = x - transparent inline def toLong(x: Int): Long = x.toLong - transparent inline def toFloat(x: Int): Float = x.toFloat - transparent inline def toDouble(x: Int): Double = x.toDouble - transparent override inline def abs(x: Int): Int = math.abs(x) - transparent override inline def sign(x: Int): Int = math.signum(x) - - transparent inline def quot(x: Int, y: Int): Int = x / y - transparent inline def rem(x: Int, y: Int): Int = x % y - -given BigIntIsInlineIntegral: InlineIntegral[BigInt] with Ordering.BigIntOrdering with - transparent inline def plus(x: BigInt, y: BigInt): BigInt = x + y - transparent inline def minus(x: BigInt, y: BigInt): BigInt = x - y - transparent inline def times(x: BigInt, y: BigInt): BigInt = x * y - transparent inline def negate(x: BigInt): BigInt = -x - transparent inline def fromInt(x: Int): BigInt = BigInt(x) - transparent inline def parseString(str: String): Option[BigInt] = Try(BigInt(str)).toOption - transparent inline def toInt(x: BigInt): Int = x.intValue - transparent inline def toLong(x: BigInt): Long = x.longValue - transparent inline def toFloat(x: BigInt): Float = x.floatValue - transparent inline def toDouble(x: BigInt): Double = x.doubleValue - transparent override inline def abs(x: BigInt): BigInt = x.abs - transparent override inline def sign(x: BigInt): BigInt = x.sign - - transparent inline def quot(x: BigInt, y: BigInt): BigInt = x / y - transparent inline def rem(x: BigInt, y: BigInt): BigInt = x % y - -given ShortIsInlineIntegral: InlineIntegral[Short] with Ordering.ShortOrdering with - transparent inline def plus(x: Short, y: Short): Short = (x + y).toShort - transparent inline def minus(x: Short, y: Short): Short = (x - y).toShort - transparent inline def times(x: Short, y: Short): Short = (x * y).toShort - transparent inline def negate(x: Short): Short = (-x).toShort - transparent inline def fromInt(x: Int): Short = x.toShort - transparent inline def parseString(str: String): Option[Short] = str.toShortOption - transparent inline def toInt(x: Short): Int = x.toInt - transparent inline def toLong(x: Short): Long = x.toLong - transparent inline def toFloat(x: Short): Float = x.toFloat - transparent inline def toDouble(x: Short): Double = x.toDouble - transparent override inline def abs(x: Short): Short = math.abs(x).toShort - transparent override inline def sign(x: Short): Short = math.signum(x).toShort - - transparent inline def quot(x: Short, y: Short): Short = (x / y).toShort - transparent inline def rem(x: Short, y: Short): Short = (x % y).toShort - -given ByteIsInlineIntegral: InlineIntegral[Byte] with Ordering.ByteOrdering with - transparent inline def plus(x: Byte, y: Byte): Byte = (x + y).toByte - transparent inline def minus(x: Byte, y: Byte): Byte = (x - y).toByte - transparent inline def times(x: Byte, y: Byte): Byte = (x * y).toByte - transparent inline def negate(x: Byte): Byte = (-x).toByte - transparent inline def fromInt(x: Int): Byte = x.toByte - transparent inline def parseString(str: String): Option[Byte] = str.toByteOption - transparent inline def toInt(x: Byte): Int = x.toInt - transparent inline def toLong(x: Byte): Long = x.toLong - transparent inline def toFloat(x: Byte): Float = x.toFloat - transparent inline def toDouble(x: Byte): Double = x.toDouble - transparent override inline def abs(x: Byte): Byte = math.abs(x).toByte - transparent override inline def sign(x: Byte): Byte = math.signum(x).toByte - - transparent inline def quot(x: Byte, y: Byte): Byte = (x / y).toByte - transparent inline def rem(x: Byte, y: Byte): Byte = (x % y).toByte - -given CharIsInlineIntegral: InlineIntegral[Char] with Ordering.CharOrdering with - transparent inline def plus(x: Char, y: Char): Char = (x + y).toChar - transparent inline def minus(x: Char, y: Char): Char = (x - y).toChar - transparent inline def times(x: Char, y: Char): Char = (x * y).toChar - transparent inline def negate(x: Char): Char = (-x).toChar - transparent inline def fromInt(x: Int): Char = x.toChar - transparent inline def parseString(str: String): Option[Char] = Try(str.toInt.toChar).toOption - transparent inline def toInt(x: Char): Int = x.toInt - transparent inline def toLong(x: Char): Long = x.toLong - transparent inline def toFloat(x: Char): Float = x.toFloat - transparent inline def toDouble(x: Char): Double = x.toDouble - transparent override inline def abs(x: Char): Char = math.abs(x).toChar - transparent override inline def sign(x: Char): Char = math.signum(x).toChar - - transparent inline def quot(x: Char, y: Char): Char = (x / y).toChar - transparent inline def rem(x: Char, y: Char): Char = (x % y).toChar - -given LongIsInlineIntegral: InlineIntegral[Long] with Ordering.LongOrdering with - transparent inline def plus(x: Long, y: Long): Long = x + y - transparent inline def minus(x: Long, y: Long): Long = x - y - transparent inline def times(x: Long, y: Long): Long = x * y - transparent inline def negate(x: Long): Long = -x - transparent inline def fromInt(x: Int): Long = x.toLong - transparent inline def parseString(str: String): Option[Long] = str.toLongOption - transparent inline def toInt(x: Long): Int = x.toInt - transparent inline def toLong(x: Long): Long = x - transparent inline def toFloat(x: Long): Float = x.toFloat - transparent inline def toDouble(x: Long): Double = x.toDouble - transparent override inline def abs(x: Long): Long = math.abs(x) - transparent override inline def sign(x: Long): Long = math.signum(x) - - transparent inline def quot(x: Long, y: Long): Long = (x / y).toLong - transparent inline def rem(x: Long, y: Long): Long = (x % y).toLong - -given FloatIsInlineFractional: InlineFractional[Float] with Ordering.Float.IeeeOrdering with - transparent inline def plus(x: Float, y: Float): Float = x + y - transparent inline def minus(x: Float, y: Float): Float = x - y - transparent inline def times(x: Float, y: Float): Float = x * y - transparent inline def negate(x: Float): Float = -x - transparent inline def fromInt(x: Int): Float = x.toFloat - transparent inline def parseString(str: String): Option[Float] = str.toFloatOption - transparent inline def toInt(x: Float): Int = x.toInt - transparent inline def toLong(x: Float): Long = x.toLong - transparent inline def toFloat(x: Float): Float = x - transparent inline def toDouble(x: Float): Double = x.toDouble - transparent override inline def abs(x: Float): Float = math.abs(x) - transparent override inline def sign(x: Float): Float = math.signum(x) - - transparent inline def div(x: Float, y: Float): Float = x / y - -given DoubleIsInlineFractional: InlineFractional[Double] with Ordering.Double.IeeeOrdering with - transparent inline def plus(x: Double, y: Double): Double = x + y - transparent inline def minus(x: Double, y: Double): Double = x - y - transparent inline def times(x: Double, y: Double): Double = x * y - transparent inline def negate(x: Double): Double = -x - transparent inline def fromInt(x: Int): Double = x.toDouble - transparent inline def parseString(str: String): Option[Double] = str.toDoubleOption - transparent inline def toInt(x: Double): Int = x.toInt - transparent inline def toLong(x: Double): Long = x.toLong - transparent inline def toFloat(x: Double): Float = x.toFloat - transparent inline def toDouble(x: Double): Double = x - transparent override inline def abs(x: Double): Double = math.abs(x) - transparent override inline def sign(x: Double): Double = math.signum(x) - - transparent inline def div(x: Double, y: Double): Double = x / y - -trait BigDecimalIsConflicted extends InlineNumeric[BigDecimal] with Ordering.BigDecimalOrdering: - transparent inline def plus(x: BigDecimal, y: BigDecimal): BigDecimal = x + y - transparent inline def minus(x: BigDecimal, y: BigDecimal): BigDecimal = x - y - transparent inline def times(x: BigDecimal, y: BigDecimal): BigDecimal = x * y - transparent inline def negate(x: BigDecimal): BigDecimal = -x - transparent inline def fromInt(x: Int): BigDecimal = BigDecimal(x) - transparent inline def parseString(str: String): Option[BigDecimal] = Try(BigDecimal(str)).toOption - transparent inline def toInt(x: BigDecimal): Int = x.intValue - transparent inline def toLong(x: BigDecimal): Long = x.longValue - transparent inline def toFloat(x: BigDecimal): Float = x.floatValue - transparent inline def toDouble(x: BigDecimal): Double = x.doubleValue - transparent override inline def abs(x: BigDecimal): BigDecimal = x.abs - transparent override inline def sign(x: BigDecimal): BigDecimal = x.sign - -given BigDecimalIsInlineFractional: BigDecimalIsConflicted with InlineFractional[BigDecimal] with - transparent inline def div(x: BigDecimal, y: BigDecimal): BigDecimal = x / y - -given BigDecimalAsIfInlineIntegral: BigDecimalIsConflicted with InlineIntegral[BigDecimal] with - transparent inline def quot(x: BigDecimal, y: BigDecimal): BigDecimal = x quot y - transparent inline def rem(x: BigDecimal, y: BigDecimal): BigDecimal = x remainder y - -object tests: - import InlineNumeric.* - import InlineIntegral.{/ => ¦, %} - import InlineFractional./ - - inline def foo[T: InlineNumeric](a: T, b: T) = - a + b * b - - inline def div[T: InlineIntegral](a: T, b: T) = - a ¦ b % b - - inline def div[T: InlineFractional](a: T, b: T) = - a / b + a - - inline def bar[T: InlineNumeric](a: T) = a.toInt - - inline def sign[T: InlineNumeric](a: T) = a.sign - - def test(a: Int, b: Int) = - val v1 = foo(a, b) // should be a + b * b // can check with -Xprint:inlining - val v2 = foo(a.toShort, b.toShort) // should be a + b * b - - val v3 = div(BigDecimal(a), BigDecimal(b))(using BigDecimalAsIfInlineIntegral) // should be BigDecimal(a) quot BigDecimal(b) remainder BigDecimal(b) - val v4 = div(BigDecimal(a), BigDecimal(b))(using BigDecimalIsInlineFractional) // should be BigDecimal(a) / BigDecimal(b) + BigDecimal(a) - - val v5 = bar(a.toFloat) // should be a.toFloat.toInt - val v6 = bar(a) // should be a - - val v7 = sign(a) - val v8 = sign(a.toChar) - val v9 = sign(-7F) - - val v10 = sign(BigDecimal(a))(using BigDecimalAsIfInlineIntegral) - val v11 = sign(BigDecimal(a))(using BigDecimalIsInlineFractional) // the condition with isNan() should be removed, i.e. it should be equivalent to v10 \ No newline at end of file diff --git a/InlineNumeric-extensionsInTrait.scala b/InlineNumeric-extensionsInTrait.scala deleted file mode 100644 index bac390783e65..000000000000 --- a/InlineNumeric-extensionsInTrait.scala +++ /dev/null @@ -1,263 +0,0 @@ -import scala.util.Try - -trait InlineNumeric[T] extends Ordering[T]: // extends Numeric[T] // TODO can we do this? - transparent inline def plus(inline x: T, inline y: T): T - transparent inline def minus(inline x: T, inline y: T): T - transparent inline def times(inline x: T, inline y: T): T - transparent inline def negate(inline x: T): T - transparent inline def fromInt(inline x: Int): T - transparent inline def parseString(inline str: String): Option[T] - - transparent inline def zero = fromInt(0) - transparent inline def one = fromInt(1) - - extension (inline x: T) - transparent inline def +(inline y: T): T = plus(x, y) - transparent inline def -(inline y: T) = minus(x, y) - transparent inline def *(inline y: T): T = times(x, y) - transparent inline def unary_- = negate(x) - transparent inline def toInt: Int - transparent inline def toLong: Long - transparent inline def toFloat: Float - transparent inline def toDouble: Double - transparent inline def abs: T - transparent inline def sign: T - -trait InlineIntegral[T] extends InlineNumeric[T]: - transparent inline def quot(inline x: T, inline y: T): T - transparent inline def rem(inline x: T, inline y: T): T - - extension (inline lhs: T) - transparent inline def /(inline rhs: T) = quot(lhs, rhs) - transparent inline def %(inline rhs: T) = rem(lhs, rhs) - transparent inline def /%(inline rhs: T) = (quot(lhs, rhs), rem(lhs, rhs)) - - transparent inline def abs: T = if lt(lhs, zero) then negate(lhs) else lhs - transparent inline def sign: T = - if lt(lhs, zero) then negate(one) - else if gt(lhs, zero) then one - else zero - -trait InlineFractional[T] extends InlineNumeric[T]: - transparent inline def div(inline x: T, inline y: T): T - protected transparent inline def isNaN(inline x: T): Boolean - protected transparent inline def isNegZero(inline x: T): Boolean - - extension (inline lhs: T) - transparent inline def /(inline rhs: T) = div(lhs, rhs) - transparent inline def abs: T = if lt(lhs, zero) || isNegZero(lhs) then negate(lhs) else lhs - transparent inline def sign: T = - if isNaN(lhs) || isNegZero(lhs) then lhs - else if lt(lhs, zero) then negate(one) - else if gt(lhs, zero) then one - else zero - -given IntIsInlineIntegral: InlineIntegral[Int] with Ordering.IntOrdering with - transparent inline def plus(inline x: Int, inline y: Int): Int = x + y - transparent inline def minus(inline x: Int, inline y: Int): Int = x - y - transparent inline def times(inline x: Int, inline y: Int): Int = x * y - transparent inline def negate(inline x: Int): Int = -x - transparent inline def fromInt(inline x: Int): Int = x - transparent inline def parseString(inline str: String): Option[Int] = str.toIntOption - - transparent inline def quot(inline x: Int, inline y: Int): Int = x / y - transparent inline def rem(inline x: Int, inline y: Int): Int = x % y - - extension (inline x: Int) - transparent inline def toInt: Int = x - transparent inline def toLong: Long = x.toLong - transparent inline def toFloat: Float = x.toFloat - transparent inline def toDouble: Double = x.toDouble - -given BigIntIsInlineIntegral: InlineIntegral[BigInt] with Ordering.BigIntOrdering with - transparent inline def plus(inline x: BigInt, inline y: BigInt): BigInt = x + y - transparent inline def minus(inline x: BigInt, inline y: BigInt): BigInt = x - y - transparent inline def times(inline x: BigInt, inline y: BigInt): BigInt = x * y - transparent inline def negate(inline x: BigInt): BigInt = -x - transparent inline def fromInt(inline x: Int): BigInt = BigInt(x) - transparent inline def parseString(inline str: String): Option[BigInt] = Try(BigInt(str)).toOption - - transparent inline def quot(inline x: BigInt, inline y: BigInt): BigInt = x / y - transparent inline def rem(inline x: BigInt, inline y: BigInt): BigInt = x % y - - extension (inline x: BigInt) - transparent inline def toInt: Int = x.intValue - transparent inline def toLong: Long = x.longValue - transparent inline def toFloat: Float = x.floatValue - transparent inline def toDouble: Double = x.doubleValue - -given ShortIsInlineIntegral: InlineIntegral[Short] with Ordering.ShortOrdering with - transparent inline def plus(inline x: Short, inline y: Short): Short = (x + y).toShort - transparent inline def minus(inline x: Short, inline y: Short): Short = (x - y).toShort - transparent inline def times(inline x: Short, inline y: Short): Short = (x * y).toShort - transparent inline def negate(inline x: Short): Short = (-x).toShort - transparent inline def fromInt(inline x: Int): Short = x.toShort - transparent inline def parseString(inline str: String): Option[Short] = str.toShortOption - - transparent inline def quot(inline x: Short, inline y: Short): Short = (x / y).toShort - transparent inline def rem(inline x: Short, inline y: Short): Short = (x % y).toShort - - extension (inline x: Short) - transparent inline def toInt: Int = x.toInt - transparent inline def toLong: Long = x.toLong - transparent inline def toFloat: Float = x.toFloat - transparent inline def toDouble: Double = x.toDouble - -given ByteIsInlineIntegral: InlineIntegral[Byte] with Ordering.ByteOrdering with - transparent inline def plus(inline x: Byte, inline y: Byte): Byte = (x + y).toByte - transparent inline def minus(inline x: Byte, inline y: Byte): Byte = (x - y).toByte - transparent inline def times(inline x: Byte, inline y: Byte): Byte = (x * y).toByte - transparent inline def negate(inline x: Byte): Byte = (-x).toByte - transparent inline def fromInt(inline x: Int): Byte = x.toByte - transparent inline def parseString(inline str: String): Option[Byte] = str.toByteOption - - transparent inline def quot(inline x: Byte, inline y: Byte): Byte = (x / y).toByte - transparent inline def rem(inline x: Byte, inline y: Byte): Byte = (x % y).toByte - - extension (inline x: Byte) - transparent inline def toInt: Int = x.toInt - transparent inline def toLong: Long = x.toLong - transparent inline def toFloat: Float = x.toFloat - transparent inline def toDouble: Double = x.toDouble - -given CharIsInlineIntegral: InlineIntegral[Char] with Ordering.CharOrdering with - transparent inline def plus(inline x: Char, inline y: Char): Char = (x + y).toChar - transparent inline def minus(inline x: Char, inline y: Char): Char = (x - y).toChar - transparent inline def times(inline x: Char, inline y: Char): Char = (x * y).toChar - transparent inline def negate(inline x: Char): Char = (-x).toChar - transparent inline def fromInt(inline x: Int): Char = x.toChar - transparent inline def parseString(inline str: String): Option[Char] = Try(str.toInt.toChar).toOption - - transparent inline def quot(inline x: Char, inline y: Char): Char = (x / y).toChar - transparent inline def rem(inline x: Char, inline y: Char): Char = (x % y).toChar - - extension (inline x: Char) - transparent inline def toInt: Int = x.toInt - transparent inline def toLong: Long = x.toLong - transparent inline def toFloat: Float = x.toFloat - transparent inline def toDouble: Double = x.toDouble - -given LongIsInlineIntegral: InlineIntegral[Long] with Ordering.LongOrdering with - transparent inline def plus(inline x: Long, inline y: Long): Long = x + y - transparent inline def minus(inline x: Long, inline y: Long): Long = x - y - transparent inline def times(inline x: Long, inline y: Long): Long = x * y - transparent inline def negate(inline x: Long): Long = -x - transparent inline def fromInt(inline x: Int): Long = x.toLong - transparent inline def parseString(inline str: String): Option[Long] = str.toLongOption - - transparent inline def quot(inline x: Long, inline y: Long): Long = (x / y).toLong - transparent inline def rem(inline x: Long, inline y: Long): Long = (x % y).toLong - - extension (inline x: Long) - transparent inline def toInt: Int = x.toInt - transparent inline def toLong: Long = x - transparent inline def toFloat: Float = x.toFloat - transparent inline def toDouble: Double = x.toDouble - -given FloatIsInlineFractional: InlineFractional[Float] with Ordering.Float.IeeeOrdering with - transparent inline def plus(inline x: Float, inline y: Float): Float = x + y - transparent inline def minus(inline x: Float, inline y: Float): Float = x - y - transparent inline def times(inline x: Float, inline y: Float): Float = x * y - transparent inline def negate(inline x: Float): Float = -x - transparent inline def fromInt(inline x: Int): Float = x.toFloat - transparent inline def parseString(inline str: String): Option[Float] = str.toFloatOption - - transparent inline def div(inline x: Float, inline y: Float): Float = x / y - protected transparent inline def isNaN(inline x: Float): Boolean = x.isNaN - protected transparent inline def isNegZero(inline x: Float): Boolean = x.equals(-0f) - - extension (inline x: Float) - transparent inline def toInt: Int = x.toInt - transparent inline def toLong: Long = x.toLong - transparent inline def toFloat: Float = x - transparent inline def toDouble: Double = x.toDouble - -given DoubleIsInlineFractional: InlineFractional[Double] with Ordering.Double.IeeeOrdering with - transparent inline def plus(inline x: Double, inline y: Double): Double = x + y - transparent inline def minus(inline x: Double, inline y: Double): Double = x - y - transparent inline def times(inline x: Double, inline y: Double): Double = x * y - transparent inline def negate(inline x: Double): Double = -x - transparent inline def fromInt(inline x: Int): Double = x.toDouble - transparent inline def parseString(inline str: String): Option[Double] = str.toDoubleOption - - transparent inline def div(inline x: Double, inline y: Double): Double = x / y - protected transparent inline def isNaN(inline x: Double): Boolean = x.isNaN - protected transparent inline def isNegZero(inline x: Double): Boolean = x.equals(-0.0) - - extension (inline x: Double) - transparent inline def toInt: Int = x.toInt - transparent inline def toLong: Long = x.toLong - transparent inline def toFloat: Float = x.toFloat - transparent inline def toDouble: Double = x.toDouble - -trait BigDecimalIsConflicted extends InlineNumeric[BigDecimal] with Ordering.BigDecimalOrdering: - transparent inline def plus(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x + y - transparent inline def minus(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x - y - transparent inline def times(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x * y - transparent inline def negate(inline x: BigDecimal): BigDecimal = -x - transparent inline def fromInt(inline x: Int): BigDecimal = BigDecimal(x) - transparent inline def parseString(inline str: String): Option[BigDecimal] = Try(BigDecimal(str)).toOption - - extension (inline x: BigDecimal) - transparent inline def toInt: Int = x.intValue - transparent inline def toLong: Long = x.longValue - transparent inline def toFloat: Float = x.floatValue - transparent inline def toDouble: Double = x.doubleValue - -given BigDecimalIsInlineFractional: BigDecimalIsConflicted with InlineFractional[BigDecimal] with - transparent inline def div(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x / y - protected transparent inline def isNaN(inline x: BigDecimal): Boolean = false - protected transparent inline def isNegZero(inline x: BigDecimal): Boolean = false - - -given BigDecimalAsIfInlineIntegral: BigDecimalIsConflicted with InlineIntegral[BigDecimal] with - transparent inline def quot(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x quot y - transparent inline def rem(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x remainder y - -object tests: - // A generic inline operation that inlines/specializes primitive operations - inline def foo[T: InlineNumeric](inline a: T, inline b: T) = - a + b * b - - inline def div[T: InlineIntegral](inline a: T, inline b: T) = - a / b % b - - inline def div[T: InlineFractional](inline a: T, inline b: T) = - a / b + a - - inline def toInt[T: InlineNumeric](inline a: T) = - a.toInt - - inline def explicitToInt[T](inline a: T)(using n: InlineNumeric[T]) = - n.toInt(a) - - inline def sign[T: InlineNumeric](inline a: T) = - a.sign - - inline def explicitPlus[T](inline a: T, inline b: T)(using n: InlineNumeric[T]) = - n.plus(a, b) - - def test(a: Int, b: Int) = - val v1 = foo(a, b) // should be a + b * b // can check with -Xprint:inlining - val v2 = foo(a.toShort, b.toShort) // should be a + b * b - - val v3 = div(BigDecimal(a), BigDecimal(b))(using BigDecimalAsIfInlineIntegral) // should be BigDecimal(a) quot BigDecimal(b) remainder BigDecimal(b) - val v4 = div(BigDecimal(a), BigDecimal(b))(using BigDecimalIsInlineFractional) // should be BigDecimal(a) / BigDecimal(b) + BigDecimal(a) - - val v5 = toInt(a.toFloat) // should be a.toFloat.toInt - val v6 = toInt(a) // should be a - - val v7 = sign(a) - val v8 = sign(a.toChar) - val v9 = sign(-7F) - - val v10 = sign(BigDecimal(a))(using BigDecimalAsIfInlineIntegral) - val v11 = sign(BigDecimal(a))(using BigDecimalIsInlineFractional) // the condition with isNan() should be removed, i.e. it should be equivalent to v10 - - val v12 = explicitPlus(3, 5) // should be 8 - val v13 = explicitPlus(a, b) // should be a + b - - val v14 = explicitToInt(3.2) // should be (3.2).toInt - val v15 = explicitToInt(3) // should be 3 - val v16 = explicitToInt(a) // should be a - val v17 = explicitToInt(a.toShort) // should be a.toShort.toInt \ No newline at end of file diff --git a/InlineNumeric.scala b/InlineNumeric.scala deleted file mode 100644 index 265343dfc793..000000000000 --- a/InlineNumeric.scala +++ /dev/null @@ -1,251 +0,0 @@ -// community-build/community-projects/stdLib213/src/library/scala/math/Numeric.scala -// community-build/community-projects/stdLib213/src/library/scala/math/Integral.scala -// community-build/community-projects/stdLib213/src/library/scala/math/Fractional.scala - -import scala.util.Try - -trait InlineNumeric[T] extends Ordering[T]: // extends Numeric[T] // TODO can we do this? - transparent inline def plus(inline x: T, inline y: T): T - transparent inline def minus(inline x: T, inline y: T): T - transparent inline def times(inline x: T, inline y: T): T - transparent inline def negate(inline x: T): T - transparent inline def fromInt(inline x: Int): T - transparent inline def parseString(inline str: String): Option[T] - transparent inline def toInt(inline x: T): Int - transparent inline def toLong(inline x: T): Long - transparent inline def toFloat(inline x: T): Float - transparent inline def toDouble(inline x: T): Double - transparent inline def abs(inline x: T): T - transparent inline def sign(inline x: T): T - - transparent inline def zero = fromInt(0) - transparent inline def one = fromInt(1) - -object InlineNumeric: - extension [T](inline x: T)(using inline num: InlineNumeric[T]) - transparent inline def +(inline y: T): T = num.plus(x, y) - transparent inline def -(inline y: T) = num.minus(x, y) - transparent inline def *(inline y: T): T = num.times(x, y) - transparent inline def unary_- = num.negate(x) - transparent inline def toInt: Int = num.toInt(x) - transparent inline def toLong: Long = num.toLong(x) - transparent inline def toFloat: Float = num.toFloat(x) - transparent inline def toDouble: Double = num.toDouble(x) - transparent inline def abs: T = num.abs(x) - transparent inline def sign: T = num.sign(x) - -trait InlineIntegral[T] extends InlineNumeric[T]: - transparent inline def abs(inline x: T): T = if lt(x, zero) then negate(x) else x - transparent inline def sign(inline x: T): T = - if lt(x, zero) then negate(one) - else if gt(x, zero) then one - else zero - - transparent inline def quot(inline x: T, inline y: T): T - transparent inline def rem(inline x: T, inline y: T): T - -object InlineIntegral: - // TODO: how are these imported/composed with Numeric/Integral. Should the extension methods be defined in trait InlineIntegral? - extension [T](inline lhs: T)(using inline int: InlineIntegral[T]) - transparent inline def /(inline rhs: T) = int.quot(lhs, rhs) - transparent inline def %(inline rhs: T) = int.rem(lhs, rhs) - transparent inline def /%(inline rhs: T) = (int.quot(lhs, rhs), int.rem(lhs, rhs)) - -trait InlineFractional[T] extends InlineNumeric[T]: - transparent inline def abs(inline x: T): T = if lt(x, zero) || isNegZero(x) then negate(x) else x - transparent inline def sign(inline x: T): T = - if isNaN(x) || isNegZero(x) then x - else if lt(x, zero) then negate(one) - else if gt(x, zero) then one - else zero - - transparent inline def div(inline x: T, inline y: T): T - protected transparent inline def isNaN(inline x: T): Boolean - protected transparent inline def isNegZero(inline x: T): Boolean - -object InlineFractional: - // TODO: how are these imported/composed with Numeric/Fractional. Should the extension methods be defined in trait InlineFractional? - extension [T](inline lhs: T)(using inline frac: InlineFractional[T]) - transparent inline def /(inline rhs: T) = frac.div(lhs, rhs) - -given IntIsInlineIntegral: InlineIntegral[Int] with Ordering.IntOrdering with - transparent inline def plus(inline x: Int, inline y: Int): Int = x + y - transparent inline def minus(inline x: Int, inline y: Int): Int = x - y - transparent inline def times(inline x: Int, inline y: Int): Int = x * y - transparent inline def negate(inline x: Int): Int = -x - transparent inline def fromInt(inline x: Int): Int = x - transparent inline def parseString(inline str: String): Option[Int] = str.toIntOption - transparent inline def toInt(inline x: Int): Int = x - transparent inline def toLong(inline x: Int): Long = x.toLong - transparent inline def toFloat(inline x: Int): Float = x.toFloat - transparent inline def toDouble(inline x: Int): Double = x.toDouble - - transparent inline def quot(inline x: Int, inline y: Int): Int = x / y - transparent inline def rem(inline x: Int, inline y: Int): Int = x % y - -given BigIntIsInlineIntegral: InlineIntegral[BigInt] with Ordering.BigIntOrdering with - transparent inline def plus(inline x: BigInt, inline y: BigInt): BigInt = x + y - transparent inline def minus(inline x: BigInt, inline y: BigInt): BigInt = x - y - transparent inline def times(inline x: BigInt, inline y: BigInt): BigInt = x * y - transparent inline def negate(inline x: BigInt): BigInt = -x - transparent inline def fromInt(inline x: Int): BigInt = BigInt(x) - transparent inline def parseString(inline str: String): Option[BigInt] = Try(BigInt(str)).toOption - transparent inline def toInt(inline x: BigInt): Int = x.intValue - transparent inline def toLong(inline x: BigInt): Long = x.longValue - transparent inline def toFloat(inline x: BigInt): Float = x.floatValue - transparent inline def toDouble(inline x: BigInt): Double = x.doubleValue - - transparent inline def quot(inline x: BigInt, inline y: BigInt): BigInt = x / y - transparent inline def rem(inline x: BigInt, inline y: BigInt): BigInt = x % y - -given ShortIsInlineIntegral: InlineIntegral[Short] with Ordering.ShortOrdering with - transparent inline def plus(inline x: Short, inline y: Short): Short = (x + y).toShort - transparent inline def minus(inline x: Short, inline y: Short): Short = (x - y).toShort - transparent inline def times(inline x: Short, inline y: Short): Short = (x * y).toShort - transparent inline def negate(inline x: Short): Short = (-x).toShort - transparent inline def fromInt(inline x: Int): Short = x.toShort - transparent inline def parseString(inline str: String): Option[Short] = str.toShortOption - transparent inline def toInt(inline x: Short): Int = x.toInt - transparent inline def toLong(inline x: Short): Long = x.toLong - transparent inline def toFloat(inline x: Short): Float = x.toFloat - transparent inline def toDouble(inline x: Short): Double = x.toDouble - - transparent inline def quot(inline x: Short, inline y: Short): Short = (x / y).toShort - transparent inline def rem(inline x: Short, inline y: Short): Short = (x % y).toShort - -given ByteIsInlineIntegral: InlineIntegral[Byte] with Ordering.ByteOrdering with - transparent inline def plus(inline x: Byte, inline y: Byte): Byte = (x + y).toByte - transparent inline def minus(inline x: Byte, inline y: Byte): Byte = (x - y).toByte - transparent inline def times(inline x: Byte, inline y: Byte): Byte = (x * y).toByte - transparent inline def negate(inline x: Byte): Byte = (-x).toByte - transparent inline def fromInt(inline x: Int): Byte = x.toByte - transparent inline def parseString(inline str: String): Option[Byte] = str.toByteOption - transparent inline def toInt(inline x: Byte): Int = x.toInt - transparent inline def toLong(inline x: Byte): Long = x.toLong - transparent inline def toFloat(inline x: Byte): Float = x.toFloat - transparent inline def toDouble(inline x: Byte): Double = x.toDouble - - transparent inline def quot(inline x: Byte, inline y: Byte): Byte = (x / y).toByte - transparent inline def rem(inline x: Byte, inline y: Byte): Byte = (x % y).toByte - -given CharIsInlineIntegral: InlineIntegral[Char] with Ordering.CharOrdering with - transparent inline def plus(inline x: Char, inline y: Char): Char = (x + y).toChar - transparent inline def minus(inline x: Char, inline y: Char): Char = (x - y).toChar - transparent inline def times(inline x: Char, inline y: Char): Char = (x * y).toChar - transparent inline def negate(inline x: Char): Char = (-x).toChar - transparent inline def fromInt(inline x: Int): Char = x.toChar - transparent inline def parseString(inline str: String): Option[Char] = Try(str.toInt.toChar).toOption - transparent inline def toInt(inline x: Char): Int = x.toInt - transparent inline def toLong(inline x: Char): Long = x.toLong - transparent inline def toFloat(inline x: Char): Float = x.toFloat - transparent inline def toDouble(inline x: Char): Double = x.toDouble - - transparent inline def quot(inline x: Char, inline y: Char): Char = (x / y).toChar - transparent inline def rem(inline x: Char, inline y: Char): Char = (x % y).toChar - -given LongIsInlineIntegral: InlineIntegral[Long] with Ordering.LongOrdering with - transparent inline def plus(inline x: Long, inline y: Long): Long = x + y - transparent inline def minus(inline x: Long, inline y: Long): Long = x - y - transparent inline def times(inline x: Long, inline y: Long): Long = x * y - transparent inline def negate(inline x: Long): Long = -x - transparent inline def fromInt(inline x: Int): Long = x.toLong - transparent inline def parseString(inline str: String): Option[Long] = str.toLongOption - transparent inline def toInt(inline x: Long): Int = x.toInt - transparent inline def toLong(inline x: Long): Long = x - transparent inline def toFloat(inline x: Long): Float = x.toFloat - transparent inline def toDouble(inline x: Long): Double = x.toDouble - - transparent inline def quot(inline x: Long, inline y: Long): Long = (x / y).toLong - transparent inline def rem(inline x: Long, inline y: Long): Long = (x % y).toLong - -given FloatIsInlineFractional: InlineFractional[Float] with Ordering.Float.IeeeOrdering with - transparent inline def plus(inline x: Float, inline y: Float): Float = x + y - transparent inline def minus(inline x: Float, inline y: Float): Float = x - y - transparent inline def times(inline x: Float, inline y: Float): Float = x * y - transparent inline def negate(inline x: Float): Float = -x - transparent inline def fromInt(inline x: Int): Float = x.toFloat - transparent inline def parseString(inline str: String): Option[Float] = str.toFloatOption - transparent inline def toInt(inline x: Float): Int = x.toInt - transparent inline def toLong(inline x: Float): Long = x.toLong - transparent inline def toFloat(inline x: Float): Float = x - transparent inline def toDouble(inline x: Float): Double = x.toDouble - - transparent inline def div(inline x: Float, inline y: Float): Float = x / y - protected transparent inline def isNaN(inline x: Float): Boolean = x.isNaN - protected transparent inline def isNegZero(inline x: Float): Boolean = x.equals(-0f) - -given DoubleIsInlineFractional: InlineFractional[Double] with Ordering.Double.IeeeOrdering with - transparent inline def plus(inline x: Double, inline y: Double): Double = x + y - transparent inline def minus(inline x: Double, inline y: Double): Double = x - y - transparent inline def times(inline x: Double, inline y: Double): Double = x * y - transparent inline def negate(inline x: Double): Double = -x - transparent inline def fromInt(inline x: Int): Double = x.toDouble - transparent inline def parseString(inline str: String): Option[Double] = str.toDoubleOption - transparent inline def toInt(inline x: Double): Int = x.toInt - transparent inline def toLong(inline x: Double): Long = x.toLong - transparent inline def toFloat(inline x: Double): Float = x.toFloat - transparent inline def toDouble(inline x: Double): Double = x - - transparent inline def div(inline x: Double, inline y: Double): Double = x / y - protected transparent inline def isNaN(inline x: Double): Boolean = x.isNaN - protected transparent inline def isNegZero(inline x: Double): Boolean = x.equals(-0.0) - -trait BigDecimalIsConflicted extends InlineNumeric[BigDecimal] with Ordering.BigDecimalOrdering: - transparent inline def plus(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x + y - transparent inline def minus(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x - y - transparent inline def times(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x * y - transparent inline def negate(inline x: BigDecimal): BigDecimal = -x - transparent inline def fromInt(inline x: Int): BigDecimal = BigDecimal(x) - transparent inline def parseString(inline str: String): Option[BigDecimal] = Try(BigDecimal(str)).toOption - transparent inline def toInt(inline x: BigDecimal): Int = x.intValue - transparent inline def toLong(inline x: BigDecimal): Long = x.longValue - transparent inline def toFloat(inline x: BigDecimal): Float = x.floatValue - transparent inline def toDouble(inline x: BigDecimal): Double = x.doubleValue - -given BigDecimalIsInlineFractional: BigDecimalIsConflicted with InlineFractional[BigDecimal] with - transparent inline def div(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x / y - protected transparent inline def isNaN(inline x: BigDecimal): Boolean = false - protected transparent inline def isNegZero(inline x: BigDecimal): Boolean = false - - -given BigDecimalAsIfInlineIntegral: BigDecimalIsConflicted with InlineIntegral[BigDecimal] with - transparent inline def quot(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x quot y - transparent inline def rem(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x remainder y - -object tests: - import InlineNumeric.* - import InlineIntegral.{/ => ¦, %} - import InlineFractional.{/} - - // A generic inline operation that inlines/specializes primitive operations - inline def foo[T: InlineNumeric](inline a: T, inline b: T) = - a + b * b - - inline def div[T: InlineIntegral](inline a: T, inline b: T) = - a ¦ b % b - - inline def div[T: InlineFractional](inline a: T, inline b: T) = - a / b + a - - inline def bar[T: InlineNumeric](inline a: T) = - a.toInt - - inline def sign[T: InlineNumeric](inline a: T) = - a.sign - - def test(a: Int, b: Int) = - val v1 = foo(a, b) // should be a + b * b // can check with -Xprint:inlining - val v2 = foo(a.toShort, b.toShort) // should be a + b * b - - val v3 = div(BigDecimal(a), BigDecimal(b))(using BigDecimalAsIfInlineIntegral) // should be BigDecimal(a) quot BigDecimal(b) remainder BigDecimal(b) - val v4 = div(BigDecimal(a), BigDecimal(b))(using BigDecimalIsInlineFractional) // should be BigDecimal(a) / BigDecimal(b) + BigDecimal(a) - - val v5 = bar(a.toFloat) // should be a.toFloat.toInt - val v6 = bar(a) // should be a - - val v7 = sign(a) - val v8 = sign(a.toChar) - val v9 = sign(-7F) - - val v10 = sign(BigDecimal(a))(using BigDecimalAsIfInlineIntegral) - val v11 = sign(BigDecimal(a))(using BigDecimalIsInlineFractional) // the condition with isNan() should be removed, i.e. it should be equivalent to v10 \ No newline at end of file diff --git a/tests/run/inline-numeric/Fractional.scala b/tests/run/inline-numeric/Fractional.scala new file mode 100644 index 000000000000..a61c60063fd9 --- /dev/null +++ b/tests/run/inline-numeric/Fractional.scala @@ -0,0 +1,62 @@ +package scala.math +package inline + +trait Fractional[T] extends Numeric[T]: + transparent inline def div(inline x: T, inline y: T): T + protected transparent inline def isNaN(inline x: T): Boolean + protected transparent inline def isNegZero(inline x: T): Boolean + + extension (inline x: T) + transparent inline def abs: T = + if lt(x, zero) || isNegZero(x) then negate(x) else x + transparent inline def sign: T = + if isNaN(x) || isNegZero(x) then x + else if lt(x, zero) then negate(one) + else if gt(x, zero) then one + else zero + transparent inline def /(inline y: T) = div(x, y) + +object Fractional: + given BigDecimalIsFractional: BigDecimalIsConflicted with Fractional[BigDecimal] with + transparent inline def div(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x / y + + protected transparent inline def isNaN(inline x: BigDecimal): Boolean = false + protected transparent inline def isNegZero(inline x: BigDecimal): Boolean = false + + given DoubleIsFractional: Fractional[Double] with Ordering.DoubleIeeeOrdering with + transparent inline def plus(inline x: Double, inline y: Double): Double = x + y + transparent inline def minus(inline x: Double, inline y: Double): Double = x - y + transparent inline def times(inline x: Double, inline y: Double): Double = x * y + transparent inline def div(inline x: Double, inline y: Double): Double = x / y + transparent inline def negate(inline x: Double): Double = -x + + transparent inline def fromInt(x: Int): Double = x.toDouble + def parseString(str: String): Option[Double] = str.toDoubleOption + + protected transparent inline def isNaN(inline x: Double): Boolean = x.isNaN + protected transparent inline def isNegZero(inline x: Double): Boolean = x.equals(-0.0) + + extension (inline x: Double) + transparent inline def toInt: Int = x.toInt + transparent inline def toLong: Long = x.toLong + transparent inline def toFloat: Float = x.toFloat + transparent inline def toDouble: Double = x + + given FloatIsFractional: Fractional[Float] with Ordering.FloatIeeeOrdering with + transparent inline def plus(inline x: Float, inline y: Float): Float = x + y + transparent inline def minus(inline x: Float, inline y: Float): Float = x - y + transparent inline def times(inline x: Float, inline y: Float): Float = x * y + transparent inline def div(inline x: Float, inline y: Float): Float = x / y + transparent inline def negate(inline x: Float): Float = -x + + transparent inline def fromInt(x: Int): Float = x.toFloat + def parseString(str: String): Option[Float] = str.toFloatOption + + protected transparent inline def isNaN(inline x: Float): Boolean = x.isNaN + protected transparent inline def isNegZero(inline x: Float): Boolean = x.equals(-0f) + + extension (inline x: Float) + transparent inline def toInt: Int = x.toInt + transparent inline def toLong: Long = x.toLong + transparent inline def toFloat: Float = x + transparent inline def toDouble: Double = x.toDouble \ No newline at end of file diff --git a/tests/run/inline-numeric/Integral.scala b/tests/run/inline-numeric/Integral.scala new file mode 100644 index 000000000000..4ef11738113c --- /dev/null +++ b/tests/run/inline-numeric/Integral.scala @@ -0,0 +1,132 @@ +package scala.math +package inline + +import scala.util.Try + +trait Integral[T] extends Numeric[T]: + inline def quot(inline x: T, inline y: T): T + inline def rem(inline x: T, inline y: T): T + + extension (inline x: T) + transparent inline def abs: T = + if lt(x, zero) then negate(x) else x + transparent inline def sign: T = + if lt(x, zero) then negate(one) + else if gt(x, zero) then one + else zero + transparent inline def /(inline y: T) = quot(x, y) + transparent inline def %(inline y: T) = rem(x, y) + transparent inline def /%(inline y: T) = (quot(x, y), rem(x, y)) + +object Integral: + given BigDecimalAsIfIntegral: Integral[BigDecimal] with BigDecimalIsConflicted with + transparent inline def quot(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x quot y + transparent inline def rem(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x remainder y + + given BigIntIsIntegral: Integral[BigInt] with Ordering.BigIntOrdering with + transparent inline def plus(inline x: BigInt, inline y: BigInt): BigInt = x + y + transparent inline def minus(inline x: BigInt, inline y: BigInt): BigInt = x - y + transparent inline def times(inline x: BigInt, inline y: BigInt): BigInt = x * y + transparent inline def negate(inline x: BigInt): BigInt = -x + + extension (inline x: BigInt) + transparent inline def toInt: Int = x.intValue + transparent inline def toLong: Long = x.longValue + transparent inline def toFloat: Float = x.floatValue + transparent inline def toDouble: Double = x.doubleValue + + transparent inline def fromInt(x: Int): BigInt = BigInt(x) + def parseString(str: String): Option[BigInt] = Try(BigInt(str)).toOption + + transparent inline def quot(inline x: BigInt, inline y: BigInt): BigInt = x / y + transparent inline def rem(inline x: BigInt, inline y: BigInt): BigInt = x % y + + given ByteIsIntegral: Integral[Byte] with Ordering.ByteOrdering with + transparent inline def plus(inline x: Byte, inline y: Byte): Byte = (x + y).toByte + transparent inline def minus(inline x: Byte, inline y: Byte): Byte = (x - y).toByte + transparent inline def times(inline x: Byte, inline y: Byte): Byte = (x * y).toByte + transparent inline def negate(inline x: Byte): Byte = (-x).toByte + + transparent inline def fromInt(x: Int): Byte = x.toByte + def parseString(str: String): Option[Byte] = str.toByteOption + + transparent inline def quot(inline x: Byte, inline y: Byte): Byte = (x / y).toByte + transparent inline def rem(inline x: Byte, inline y: Byte): Byte = (x % y).toByte + + extension (inline x: Byte) + transparent inline def toInt: Int = x.toInt + transparent inline def toLong: Long = x.toLong + transparent inline def toFloat: Float = x.toFloat + transparent inline def toDouble: Double = x.toDouble + + given CharIsIntegral: Integral[Char] with Ordering.CharOrdering with + transparent inline def plus(inline x: Char, inline y: Char): Char = (x + y).toChar + transparent inline def minus(inline x: Char, inline y: Char): Char = (x - y).toChar + transparent inline def times(inline x: Char, inline y: Char): Char = (x * y).toChar + transparent inline def negate(inline x: Char): Char = (-x).toChar + + transparent inline def fromInt(x: Int): Char = x.toChar + def parseString(str: String): Option[Char] = Try(str.toInt.toChar).toOption + + transparent inline def quot(inline x: Char, inline y: Char): Char = (x / y).toChar + transparent inline def rem(inline x: Char, inline y: Char): Char = (x % y).toChar + + extension (inline x: Char) + transparent inline def toInt: Int = x.toInt + transparent inline def toLong: Long = x.toLong + transparent inline def toFloat: Float = x.toFloat + transparent inline def toDouble: Double = x.toDouble + + given IntIsIntegral: Integral[Int] with Ordering.IntOrdering with + transparent inline def plus(inline x: Int, inline y: Int): Int = x + y + transparent inline def minus(inline x: Int, inline y: Int): Int = x - y + transparent inline def times(inline x: Int, inline y: Int): Int = x * y + transparent inline def negate(inline x: Int): Int = -x + + transparent inline def fromInt(x: Int): Int = x + def parseString(str: String): Option[Int] = str.toIntOption + + transparent inline def quot(inline x: Int, inline y: Int): Int = x / y + transparent inline def rem(inline x: Int, inline y: Int): Int = x % y + + extension (inline x: Int) + transparent inline def toInt: Int = x + transparent inline def toLong: Long = x.toLong + transparent inline def toFloat: Float = x.toFloat + transparent inline def toDouble: Double = x.toDouble + + given LongIsIntegral: Integral[Long] with Ordering.LongOrdering with + transparent inline def plus(inline x: Long, inline y: Long): Long = x + y + transparent inline def minus(inline x: Long, inline y: Long): Long = x - y + transparent inline def times(inline x: Long, inline y: Long): Long = x * y + transparent inline def negate(inline x: Long): Long = -x + + transparent inline def fromInt(x: Int): Long = x.toLong + def parseString(str: String): Option[Long] = str.toLongOption + + transparent inline def quot(inline x: Long, inline y: Long): Long = (x / y).toLong + transparent inline def rem(inline x: Long, inline y: Long): Long = (x % y).toLong + + extension (inline x: Long) + transparent inline def toInt: Int = x.toInt + transparent inline def toLong: Long = x + transparent inline def toFloat: Float = x.toFloat + transparent inline def toDouble: Double = x.toDouble + + given ShortIsIntegral: Integral[Short] with Ordering.ShortOrdering with + transparent inline def plus(inline x: Short, inline y: Short): Short = (x + y).toShort + transparent inline def minus(inline x: Short, inline y: Short): Short = (x - y).toShort + transparent inline def times(inline x: Short, inline y: Short): Short = (x * y).toShort + transparent inline def negate(inline x: Short): Short = (-x).toShort + + transparent inline def fromInt(x: Int): Short = x.toShort + def parseString(str: String): Option[Short] = str.toShortOption + + transparent inline def quot(inline x: Short, inline y: Short): Short = (x / y).toShort + transparent inline def rem(inline x: Short, inline y: Short): Short = (x % y).toShort + + extension (inline x: Short) + transparent inline def toInt: Int = x.toInt + transparent inline def toLong: Long = x.toLong + transparent inline def toFloat: Float = x.toFloat + transparent inline def toDouble: Double = x.toDouble \ No newline at end of file diff --git a/tests/run/inline-numeric/Numeric.scala b/tests/run/inline-numeric/Numeric.scala new file mode 100644 index 000000000000..2ab4e5cf5db0 --- /dev/null +++ b/tests/run/inline-numeric/Numeric.scala @@ -0,0 +1,43 @@ +package scala.math +package inline + +import scala.util.Try + +trait Numeric[T] extends Ordering[T]: + inline def plus(inline x: T, inline y: T): T + inline def minus(inline x: T, inline y: T): T + inline def times(inline x: T, inline y: T): T + inline def negate(inline x: T): T + + def fromInt(x: Int): T + def parseString(str: String): Option[T] + + transparent inline def zero = fromInt(0) + transparent inline def one = fromInt(1) + + extension (inline x: T) + transparent inline def +(inline y: T): T = plus(x, y) + transparent inline def -(inline y: T) = minus(x, y) + transparent inline def *(inline y: T): T = times(x, y) + transparent inline def unary_- = negate(x) + inline def toInt: Int + inline def toLong: Long + inline def toFloat: Float + inline def toDouble: Double + inline def abs: T + inline def sign: T + +trait BigDecimalIsConflicted extends Numeric[BigDecimal] with Ordering.BigDecimalOrdering: + transparent inline def plus(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x + y + transparent inline def minus(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x - y + transparent inline def times(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x * y + transparent inline def negate(inline x: BigDecimal): BigDecimal = -x + + transparent inline def fromInt(x: Int): BigDecimal = BigDecimal(x) + def parseString(str: String): Option[BigDecimal] = Try(BigDecimal(str)).toOption + + extension (inline x: BigDecimal) + transparent inline def toInt: Int = x.intValue + transparent inline def toLong: Long = x.longValue + transparent inline def toFloat: Float = x.floatValue + transparent inline def toDouble: Double = x.doubleValue \ No newline at end of file diff --git a/tests/run/inline-numeric/Ordering.scala b/tests/run/inline-numeric/Ordering.scala new file mode 100644 index 000000000000..9be3377b8dc4 --- /dev/null +++ b/tests/run/inline-numeric/Ordering.scala @@ -0,0 +1,56 @@ +package scala.math +package inline + +import java.util.Comparator + +trait Ordering[T] extends Comparator[T] with PartialOrdering[T] with Serializable: + outer => + + inline def tryCompare(x: T, y: T) = Some(compare(x, y)) + + def compare(x: T, y: T): Int + + override inline def lteq(x: T, y: T): Boolean = compare(x, y) <= 0 + override inline def gteq(x: T, y: T): Boolean = compare(x, y) >= 0 + override inline def lt(x: T, y: T): Boolean = compare(x, y) < 0 + override inline def gt(x: T, y: T): Boolean = compare(x, y) > 0 + override inline def equiv(x: T, y: T): Boolean = compare(x, y) == 0 + + inline def max(x: T, y: T): T = if gteq(x, y) then x else y + inline def min(x: T, y: T): T = if lteq(x, y) then x else y + + // This is made into a separate trait, because defining the reverse ordering + // anonymously results in an error: + // Implementation restriction: nested inline methods are not supported + inline def on[U](f: U => T): Ordering[U] = new ReverseOrdering(f) {} + + private trait ReverseOrdering[U](f: U => T) extends Ordering[U]: + inline def compare(x: U, y: U) = outer.compare(f(x), f(y)) + +object Ordering: + trait BigDecimalOrdering extends Ordering[BigDecimal]: + inline def compare(x: BigDecimal, y: BigDecimal) = x.compare(y) + + trait BigIntOrdering extends Ordering[BigInt]: + inline def compare(x: BigInt, y: BigInt) = x.compare(y) + + trait ByteOrdering extends Ordering[Byte]: + inline def compare(x: Byte, y: Byte) = java.lang.Byte.compare(x, y) + + trait CharOrdering extends Ordering[Char]: + inline def compare(x: Char, y: Char) = java.lang.Character.compare(x, y) + + trait IntOrdering extends Ordering[Int]: + inline def compare(x: Int, y: Int) = java.lang.Integer.compare(x, y) + + trait LongOrdering extends Ordering[Long]: + inline def compare(x: Long, y: Long) = java.lang.Long.compare(x, y) + + trait ShortOrdering extends Ordering[Short]: + inline def compare(x: Short, y: Short) = java.lang.Short.compare(x, y) + + trait FloatIeeeOrdering extends Ordering[Float]: + inline def compare(x: Float, y: Float) = java.lang.Float.compare(x, y) + + trait DoubleIeeeOrdering extends Ordering[Double]: + inline def compare(x: Double, y: Double) = java.lang.Double.compare(x, y) \ No newline at end of file diff --git a/tests/run/inline-numeric/test.scala b/tests/run/inline-numeric/test.scala new file mode 100644 index 000000000000..deab452bcce8 --- /dev/null +++ b/tests/run/inline-numeric/test.scala @@ -0,0 +1,54 @@ +import scala.math.inline.* +import scala.math.inline.Ordering.* +import scala.math.inline.Integral.given +import scala.math.inline.Fractional.given + +object tests: + inline def foo[T: Numeric](inline a: T, inline b: T) = + a + b * b + + inline def div[T: Integral](inline a: T, inline b: T) = + a / b % b + + inline def div[T: Fractional](inline a: T, inline b: T) = + a / b + a + + inline def toInt[T: Numeric](inline a: T) = + a.toInt + + inline def explicitToInt[T](inline a: T)(using n: Numeric[T]) = + n.toInt(a) + + inline def sign[T: Numeric](inline a: T) = + a.sign + + inline def explicitPlus[T](inline a: T, inline b: T)(using n: Numeric[T]) = + n.plus(a, b) + + @main def Test = + def a: Int = 0 + def b: Int = 1 + + val v1 = foo(a, b) // should be a + b * b // can check with -Xprint:inlining + val v2 = foo(a.toShort, b.toShort) // should be a + b * b + + val v3 = div(BigDecimal(a), BigDecimal(b))(using BigDecimalAsIfIntegral) // should be BigDecimal(a) quot BigDecimal(b) remainder BigDecimal(b) + val v4 = div(BigDecimal(a), BigDecimal(b))(using BigDecimalIsFractional) // should be BigDecimal(a) / BigDecimal(b) + BigDecimal(a) + + val v5 = toInt(a.toFloat) // should be a.toFloat.toInt + val v6 = toInt(a) // should be a + + val v7 = sign(a) + val v8 = sign(a.toChar) + val v9 = sign(-7F) + + val v10 = sign(BigDecimal(a))(using BigDecimalAsIfIntegral) + val v11 = sign(BigDecimal(a))(using BigDecimalIsFractional) // the condition with isNan() should be removed, i.e. it should be equivalent to v10 + + val v12 = explicitPlus(3, 5) // should be 8 + val v13 = explicitPlus(a, b) // should be a + b + + val v14 = explicitToInt(3.2) // should be (3.2).toInt + val v15 = explicitToInt(3) // should be 3 + val v16 = explicitToInt(a) // should be a + val v17 = explicitToInt(a.toShort) // should be a.toShort.toInt \ No newline at end of file From e9d87184cdbd40516f6bb2844c484bd6d12ce1e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Andres?= Date: Tue, 14 Mar 2023 13:45:45 +0100 Subject: [PATCH 9/9] Add newlines at end of test files --- tests/run/inline-numeric/Fractional.scala | 2 +- tests/run/inline-numeric/Integral.scala | 2 +- tests/run/inline-numeric/Numeric.scala | 2 +- tests/run/inline-numeric/Ordering.scala | 2 +- tests/run/inline-numeric/test.scala | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/run/inline-numeric/Fractional.scala b/tests/run/inline-numeric/Fractional.scala index a61c60063fd9..f1bc81246a43 100644 --- a/tests/run/inline-numeric/Fractional.scala +++ b/tests/run/inline-numeric/Fractional.scala @@ -59,4 +59,4 @@ object Fractional: transparent inline def toInt: Int = x.toInt transparent inline def toLong: Long = x.toLong transparent inline def toFloat: Float = x - transparent inline def toDouble: Double = x.toDouble \ No newline at end of file + transparent inline def toDouble: Double = x.toDouble diff --git a/tests/run/inline-numeric/Integral.scala b/tests/run/inline-numeric/Integral.scala index 4ef11738113c..1a740a3e1d99 100644 --- a/tests/run/inline-numeric/Integral.scala +++ b/tests/run/inline-numeric/Integral.scala @@ -129,4 +129,4 @@ object Integral: transparent inline def toInt: Int = x.toInt transparent inline def toLong: Long = x.toLong transparent inline def toFloat: Float = x.toFloat - transparent inline def toDouble: Double = x.toDouble \ No newline at end of file + transparent inline def toDouble: Double = x.toDouble diff --git a/tests/run/inline-numeric/Numeric.scala b/tests/run/inline-numeric/Numeric.scala index 2ab4e5cf5db0..99b46b05aa9d 100644 --- a/tests/run/inline-numeric/Numeric.scala +++ b/tests/run/inline-numeric/Numeric.scala @@ -40,4 +40,4 @@ trait BigDecimalIsConflicted extends Numeric[BigDecimal] with Ordering.BigDecima transparent inline def toInt: Int = x.intValue transparent inline def toLong: Long = x.longValue transparent inline def toFloat: Float = x.floatValue - transparent inline def toDouble: Double = x.doubleValue \ No newline at end of file + transparent inline def toDouble: Double = x.doubleValue diff --git a/tests/run/inline-numeric/Ordering.scala b/tests/run/inline-numeric/Ordering.scala index 9be3377b8dc4..714fa51b1226 100644 --- a/tests/run/inline-numeric/Ordering.scala +++ b/tests/run/inline-numeric/Ordering.scala @@ -53,4 +53,4 @@ object Ordering: inline def compare(x: Float, y: Float) = java.lang.Float.compare(x, y) trait DoubleIeeeOrdering extends Ordering[Double]: - inline def compare(x: Double, y: Double) = java.lang.Double.compare(x, y) \ No newline at end of file + inline def compare(x: Double, y: Double) = java.lang.Double.compare(x, y) diff --git a/tests/run/inline-numeric/test.scala b/tests/run/inline-numeric/test.scala index deab452bcce8..9ca88aee0374 100644 --- a/tests/run/inline-numeric/test.scala +++ b/tests/run/inline-numeric/test.scala @@ -51,4 +51,4 @@ object tests: val v14 = explicitToInt(3.2) // should be (3.2).toInt val v15 = explicitToInt(3) // should be 3 val v16 = explicitToInt(a) // should be a - val v17 = explicitToInt(a.toShort) // should be a.toShort.toInt \ No newline at end of file + val v17 = explicitToInt(a.toShort) // should be a.toShort.toInt