-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Conversation
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.
@odersky please review. |
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), |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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)
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 |
There was a problem hiding this comment.
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]
There was a problem hiding this comment.
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 OrType
s.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed. Thanks.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's the code that backs the materializeClassTag
macro in Scala: https://github.com/scala/scala/blob/2.11.x/src/compiler/scala/reflect/reify/package.scala#L49-L72
@odersky please review. |
import ast.tpd._ | ||
|
||
private var classTagCache: Symbol = null | ||
private var typeTagCache: Symbol = null |
There was a problem hiding this comment.
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.
LGTM |
ClassTags: New phase which synthesises class tags.
No description provided.