Skip to content

ClassTags: New phase which synthesises class tags. #563

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
merged 10 commits into from
May 15, 2015

Conversation

DarkDimius
Copy link
Contributor

No description provided.

ref       => moduleClass
origClass => value class
The restriction here is used to make sure that the latest scope is being updated.
Previous was to harsh and allowed only typer to call normalizeToClassRefs
Allows entering new symbols in future scope of a denotation.
Only past scope is already frozen, and we should be free to modify future one.
@DarkDimius
Copy link
Contributor Author

@odersky please review.

DarkDimius referenced this pull request May 13, 2015
Merge with fullNameSeparated. Take into account that static nested
classes are separated only with a single '$' from the enclosing object.
Previous scheme took the module class as owner, which led to a double '$$'.
@@ -55,7 +55,8 @@ class Compiler {
new Literalize,
new Getters,
new ElimByName,
new ResolveSuper),
new ResolveSuper,
new ClassTags),
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we swap RresolveSuper and ClassTags. ResolveSuper - erasure - Mixin are sort of a unit that should stay together.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ClassTags could go anywhere after ExtensionMethods. It could even be in the same group.
I'm fine with moving it.
Can you explain why you want ResolveSuper - erasure - Mixin to be same unit? We should not rely on this, as there are phases that want to go in between(think class specialization, which changes superclasses)

@odersky
Copy link
Contributor

odersky commented May 13, 2015

Otherwise LGTM

override def transformTypeApply(tree: tpd.TypeApply)(implicit ctx: Context, info: TransformerInfo): tpd.Tree =
if (tree.fun.symbol eq classTagCache) {
val tp = tree.args.head.tpe
val claz = tp.classSymbol
Copy link
Member

Choose a reason for hiding this comment

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

Will this do the right thing for:

scala> reflect.classTag[Array[Int]]
res2: scala.reflect.ClassTag[Array[Int]] = Array[int]

Copy link
Member

Choose a reason for hiding this comment

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

Is it possible to get NoSymbol back here? classSymbol seems to return that for some OrTypes.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for Array example, It's indeed not handled correctly.
classSymbol for OrTypes is bugged, see comment https://github.com/lampepfl/dotty/blob/master/src/dotty/tools/dotc/core/Types.scala#L308. It should not return NoSymbol.
Though this code will not work for some AndTypes.

It seems that classSymbol.orElse(classSymbols.head) should do it correctly.

Copy link
Contributor

Choose a reason for hiding this comment

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

On Thu, May 14, 2015 at 9:07 AM, Dmitry Petrashko [email protected]
wrote:

In src/dotty/tools/dotc/transform/ClassTags.scala
#563 (comment):

  • override def prepareForUnit(tree: tpd.Tree)(implicit ctx: Context): TreeTransform = {
  • val predefClass = defn.DottyPredefModule.moduleClass.asClass
  • classTagCache = ctx.requiredMethod(predefClass, names.classTag)
  • typeTagCache = ctx.requiredMethod(predefClass, names.typeTag)
  • scala2ClassTagModule = ctx.requiredModule("scala.reflect.ClassTag")
  • this
  • }
  • override def phaseName: String = "classTags"
  • override def transformTypeApply(tree: tpd.TypeApply)(implicit ctx: Context, info: TransformerInfo): tpd.Tree =
  • if (tree.fun.symbol eq classTagCache) {
  •  val tp = tree.args.head.tpe
    
  •  val claz = tp.classSymbol
    

Thanks for Array example, It's indeed not handled correctly.
classSymbol for OrTypes is bugged, see comment
https://github.com/lampepfl/dotty/blob/master/src/dotty/tools/dotc/core/Types.scala#L308.
It should not return NoSymbol.
Though this code will not work for some AndTypes.

It seems that classSymbol.orElse(classSymbols.head) should do it
correctly.

That will return a symbol. but how do you know it's the right one? We are
missing a spec here. I think the most robust would be to take the
classSymbol of the erased type. That has a simple spec and it is likely to
be the one we will want in the end.


Reply to this email directly or view it on GitHub
https://github.com/lampepfl/dotty/pull/563/files#r30301852.

Martin Odersky
EPFL

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Indeed. Thanks.

Copy link
Member

Choose a reason for hiding this comment

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

In Scala, give a value class Meter, classTag[Meter] and classOf[Meter] return Meter.class, not the underlying type.

So I think using Scala erasure might be a little bit too simple. You could instead use the java erasure, which, after my fix for @smarter's recent bug report, does not unwrap value classes.

Here's a few test cases:

object Test { 
  type T = String
  type U

  def test = {

    val a /* : Class[T]                  */ = classOf[T]                        // [Ljava/lang/String;
    val b /* : ClassTag[T]               */ = reflect.classTag[T]               // ClassTag(classOf[java.lang.String])

//  val c /* :                           */ = classOf[T with U]                 // error: class type required but Test.T with Test.U found
    val d /* : ClassTag[T with U]        */ = reflect.classTag[T with U]        // ClassTag(classOf[java.lang.String])

    val e /* : Class[Array[T with U]]    */ = classOf[Array[T with U]]          // [Ljava/lang/String;
    val f /* : ClassTag[Array[T with U]] */ = reflect.classTag[Array[T with U]] // ClassTag(arrayClass(classOf[java.lang.String]))

    val g /* : Class[Meter]              */ = classOf[Meter]                    // [LMeter;
    val h /* : ClassTag[Meter]           */ = reflect.classTag[Meter]           // ClassTag(classOf[Meter])
  }
}

class Meter(val i: Int) extends AnyVal

Copy link
Member

Choose a reason for hiding this comment

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

@DarkDimius
Copy link
Contributor Author

@odersky please review.

import ast.tpd._

private var classTagCache: Symbol = null
private var typeTagCache: Symbol = null
Copy link
Contributor

Choose a reason for hiding this comment

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

I usually use myClassTag/myTypeTag for private variables, includes variables serving as a cache.

@odersky
Copy link
Contributor

odersky commented May 15, 2015

LGTM

DarkDimius added a commit that referenced this pull request May 15, 2015
ClassTags: New phase which synthesises class tags.
@DarkDimius DarkDimius merged commit 0679784 into scala:master May 15, 2015
@allanrenucci allanrenucci deleted the classtags branch December 14, 2017 16:58
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