Skip to content

Closes #579 Implement mini-phase for classOf[T] #677

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

Merged

Conversation

alexander-myltsev
Copy link
Contributor

Closes #579

@DarkDimius
Copy link
Contributor

Hi, Nice to see your first contribution!

@@ -47,6 +47,7 @@ class Compiler {
new ExtensionMethods,
new ExpandSAMs,
new TailRec),
List(new ClassOf),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at the implementation, it could be safely squashed with previous group.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

      List(new RefChecks,
           new ElimRepeated,
           new NormalizeFlags,
           new ExtensionMethods,
           new ExpandSAMs,
           new TailRec,
           new ClassOf),

Right?

@alexander-myltsev
Copy link
Contributor Author

Glad to contribute :)

Regarding the test https://github.com/lampepfl/dotty/blob/master/tests/pending/run/classof.scala. I think it does not cover the case when an object of a class that is generated in ClassOf phase has same value of toString as classof.check expects, but not a class that is expected. For example, I might return some object of a class from Dotty that has boolean output of toString but is not java.lang.Boolean.TYPE under the hood.

Another question is that piece of code (https://github.com/lampepfl/dotty/blob/0d32755206e0f477c49e86b529e66e1154d7027f/src/dotty/tools/dotc/core/Definitions.scala#L274-282):

  lazy val BoxedBooleanModule = ctx.requiredModule("java.lang.Boolean")
  lazy val BoxedByteModule    = ctx.requiredModule("java.lang.Byte")
  lazy val BoxedShortModule   = ctx.requiredModule("java.lang.Short")
  lazy val BoxedCharModule    = ctx.requiredModule("java.lang.Character")
  lazy val BoxedIntModule     = ctx.requiredModule("java.lang.Integer")
  lazy val BoxedLongModule    = ctx.requiredModule("java.lang.Long")
  lazy val BoxedFloatModule   = ctx.requiredModule("java.lang.Float")
  lazy val BoxedDoubleModule  = ctx.requiredModule("java.lang.Double")
  lazy val BoxedVoidModule    = ctx.requiredModule("java.lang.Void")

Is there a better way to do it? I tried to use lazy val BoxedBooleanModule = BoxedBooleanClass.linkedClass but things do not work.

Ooops.. All tests should pass, right? I broke tests?

@DarkDimius
Copy link
Contributor

Ooops.. All tests should pass, right? I broke tests?

The broken test is the one where typer inferred Class[Int] and this type was needed for typechecking, and you've replaced it by Class[Integer]. Those classes are different before erasure, but are the same after. The solution is to add ensureConforms(tree.tpe) in all branches handling primitives.

@alexander-myltsev
Copy link
Contributor Author

Should cases as follows be covered?:

    println(classOf[Any])  // current: class java.lang.Object
    println(classOf[AnyRef])  // current: class java.lang.Object
    println(classOf[Null])  // current: class scala.runtime.Null$
    println(classOf[Nothing])  // current: class scala.runtime.Nothing$

case defn.FloatClass => TYPE(defn.BoxedFloatModule)
case defn.DoubleClass => TYPE(defn.BoxedDoubleModule)
case defn.UnitClass => TYPE(defn.BoxedVoidModule)
case _ => Literal(Constant(TypeErasure.erasure(tp)))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you write Literal(Constant(TypeErasure.erasure(tp, semiEraseVCs = false))) here, you should be able to remove the special case for value classes above.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we actually currently have a single place that uses semiEraseVCs = false?

If we do not, I'd prefer to leave as is, as this code is simple and easy to comprehend. Instead I'd better remove semiEraseVCs flag from erasure, as it makes it more complicated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we do: https://github.com/lampepfl/dotty/blob/master/src/dotty/tools/dotc/transform/Erasure.scala#L274

I don't think that semiEraseVCs is more confusing than a special case.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(It would probably help if semiEraseVCs was documented in TypeErasure#erasure, currently it's only documented for the class TypeErasure: https://github.com/lampepfl/dotty/blob/master/src/dotty/tools/dotc/core/TypeErasure.scala#L260-L262)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't work. The output is as follows:

println(classOf[Unit]) // class scala.runtime.BoxedUnit instead of void
println(classOf[Boolean]) // class java.lang.Boolean instead of boolean
println(classOf[Byte]) // class java.lang.Byte instead of byte
println(classOf[Short]) // class java.lang.Short instead of short
println(classOf[Char]) // class java.lang.Character instead of char
println(classOf[Int]) // class java.lang.Integer instead of int
println(classOf[Long]) // class java.lang.Long instead of long
println(classOf[Float]) // class java.lang.Float instead of float
println(classOf[Double]) // class java.lang.Double instead of double

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DarkDimius : So what you're saying is that semiEraseVCs = false should be the default, I guess we could do that yeah, it just involves adding semiEraseVCs = true in a lot of places in Erasure and TypeErasure, because most of the time when you erase a type you want to semi-erase it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alexander-myltsev : I didn't say that you should remove the special cases for primitive classes, but the special case for value classes: if (ValueClasses.isDerivedValueClass(claz)) { ...}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@smarter I am not speaking about erasure. I am speaking about this phase. This phase should for a classOf[Meter] generate a tree that is either Literal(Constant(ClassInfo(Meter)) or Literal(Constant(TypeRef(Meter)), but not Literal(Constant(ErasedValueType(Meter)). The last one is not expected to reach backend and is not guaranteed to be handled by it in any reasonable manner.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DarkDimius: I agree. But this phase uses TypeErasure.erasure where the default is semiEraseVCs = true, and what I was saying is that I agree that it makes sense for the default to be semiEraseVCs = false so that any phase can use TypeErasure.erasure without worrying about semi-erasure.

@alexander-myltsev
Copy link
Contributor Author

@smarter thanks for meaningful remarks

All should be fixed now

@alexander-myltsev alexander-myltsev force-pushed the am-579-implement_class_of branch from c0b83f8 to 12caa2f Compare June 22, 2015 11:53
@smarter
Copy link
Member

smarter commented Jun 22, 2015

@DarkDimius
Copy link
Contributor

For dotty it is, for scalac it isn't.

@smarter
Copy link
Member

smarter commented Jun 22, 2015

But this code is in DottyBackendInterface, can this interface be used by scalac too?

@DarkDimius
Copy link
Contributor

That's the code that handles annotations. Annotations do contain trees, but they are special in many ways and their handling is very ad-hoc.

DarkDimius added a commit that referenced this pull request Jun 23, 2015
@DarkDimius DarkDimius merged commit 0fba875 into scala:master Jun 23, 2015
@alexander-myltsev alexander-myltsev deleted the am-579-implement_class_of branch June 23, 2015 12:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants