Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bitwise shifts - incorrect returned types in certain cases #8462

Closed
scabug opened this issue Mar 29, 2014 · 2 comments
Closed

Bitwise shifts - incorrect returned types in certain cases #8462

scabug opened this issue Mar 29, 2014 · 2 comments
Assignees
Labels
Milestone

Comments

@scabug
Copy link

scabug commented Mar 29, 2014

In some cases bitwise shifts (<<. >> and >>>) for certain numeric types return value of incorrect type. For instance:

scala> val int = 1
int: Int = 1

scala> val long = 2L
long: Long = 2

scala> int << long
res0: Int = 4

scala> int << 2L
res1: Int = 4

scala> 1 << long
res2: Int = 4

scala> 1 << 2L
res3: Long = 4

scala> 1.toInt << long
res4: Int = 4

scala> 1.toInt << 2L
res5: Int = 4

res3: This 1 of type Int has been changed to Long.

As Jason Zaugg said (see https://groups.google.com/forum/#!topic/scala-internals/nr0HOhXjrPs ):

This is related to constant folding.

In the implementation, we have:

  private def foldBinop(op: Name, x: Constant, y: Constant): Constant = {
    val optag =
      if (x.tag == y.tag) x.tag
      else if (x.isNumeric && y.isNumeric) math.max(x.tag, y.tag)
      else NoTag

    try optag match {
      case BooleanTag                               => foldBooleanOp(op, x, y)
      case ByteTag | ShortTag | CharTag | IntTag    => foldSubrangeOp(op, x, y)
      case LongTag                                  => foldLongOp(op, x, y)
      case FloatTag                                 => foldFloatOp(op, x, y)
      case DoubleTag                                => foldDoubleOp(op, x, y)
      case StringTag if op == nme.ADD               => Constant(x.stringValue + y.stringValue)
      case _                                        => null
    }
    catch {
      case ex: ArithmeticException => null
    }
  }

The wider of the operands type is used.

For other arithmetic operations, this lines up with the regular signatures of the methods. For example:

scala> reflect.runtime.universe.reify{1 + (2L: Long)}
res9: reflect.runtime.universe.Expr[Long] = Expr[Long](1.$plus((2L: Long)))

scala> reflect.runtime.universe.reify{1 + 2L}
res8: reflect.runtime.universe.Expr[Long] = Expr[Long(3L)](3L)

But this doesn't hold for the shifts:

scala> reflect.runtime.universe.reify{1 << (2L: Long)}
res10: reflect.runtime.universe.Expr[Int] = Expr[Int](1.$less$less((2L: Long)))

scala> reflect.runtime.universe.reify{1 << (2L)}
res11: reflect.runtime.universe.Expr[Long] = Expr[Long(4L)](4L)
@scabug
Copy link
Author

scabug commented Mar 29, 2014

Imported From: https://issues.scala-lang.org/browse/SI-8462?orig=1
Reporter: @mpociecha

@scabug
Copy link
Author

scabug commented Jan 8, 2015

@som-snytt said:
scala/scala#4238

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants