Skip to content

Commit fec0de1

Browse files
committed
Synthesize classTags in Typer.
Now diagnoses missing ClassTags of abstract types as implicit failures. Also: Simpler API of tpd.clsOf.
1 parent 2a5e4bc commit fec0de1

File tree

8 files changed

+55
-54
lines changed

8 files changed

+55
-54
lines changed

src/dotty/DottyPredef.scala

Lines changed: 5 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,13 @@
11
package dotty
22

3-
import scala.reflect.ClassTag
43
import scala.reflect.runtime.universe.TypeTag
54
import scala.Predef.???
65

7-
abstract class I1 {
8-
implicit def classTag[T]: ClassTag[T] = ???
6+
/** unimplemented implicit for TypeTag */
7+
object DottyPredef {
98
implicit def typeTag[T]: TypeTag[T] = ???
10-
implicit val DoubleClassTag: ClassTag[Double] = ClassTag.Double
11-
}
12-
abstract class I2 extends I1 {
13-
implicit val FloatClassTag: ClassTag[Double] = ClassTag.Double
14-
}
15-
abstract class I3 extends I2 {
16-
implicit val LongClassTag: ClassTag[Long] = ClassTag.Long
17-
}
18-
abstract class I4 extends I3 {
19-
implicit val IntClassTag: ClassTag[Int] = ClassTag.Int
20-
}
21-
abstract class I5 extends I4 {
22-
implicit val ShortClassTag: ClassTag[Short] = ClassTag.Short
23-
}
24-
abstract class I6 extends I5 {
25-
implicit val ByteClassTag: ClassTag[Byte] = ClassTag.Byte
26-
implicit val CharClassTag: ClassTag[Char] = ClassTag.Char
27-
implicit val BooleanClassTag: ClassTag[Boolean] = ClassTag.Boolean
28-
implicit val UnitClassTag: ClassTag[Unit] = ClassTag.Unit
29-
implicit val NullClassTag: ClassTag[Null] = ClassTag.Null
30-
}
31-
32-
/** implicits for ClassTag and TypeTag. Should be implemented with macros */
33-
object DottyPredef extends I6 {
349

35-
/** ClassTags for final classes */
36-
implicit val NothingClassTag: ClassTag[Nothing] = ClassTag.Nothing
10+
// not yet:
11+
// def classOf[T](implicit ctag: ClassTag[T]): Class[T] =
12+
// ctag.runtimeClass
3713
}

src/dotty/tools/dotc/Compiler.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ class Compiler {
5959
new SeqLiterals,
6060
new InterceptedMethods,
6161
new Getters,
62-
new ClassTags,
6362
new ElimByName,
6463
new AugmentScala2Traits,
6564
new ResolveSuper),

src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -777,27 +777,6 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
777777
}
778778
else Assign(tree, rhs)
779779

780-
/** A tree in place of this tree that represents the class of type `tp`.
781-
* Contains special handling if the class is a primitive value class
782-
* and invokes a `default` method otherwise.
783-
*/
784-
def clsOf(tp: Type, default: => Tree)(implicit ctx: Context): Tree = {
785-
def TYPE(module: TermSymbol) =
786-
ref(module).select(nme.TYPE_).ensureConforms(tree.tpe).withPos(tree.pos)
787-
defn.scalaClassName(tp) match {
788-
case tpnme.Boolean => TYPE(defn.BoxedBooleanModule)
789-
case tpnme.Byte => TYPE(defn.BoxedByteModule)
790-
case tpnme.Short => TYPE(defn.BoxedShortModule)
791-
case tpnme.Char => TYPE(defn.BoxedCharModule)
792-
case tpnme.Int => TYPE(defn.BoxedIntModule)
793-
case tpnme.Long => TYPE(defn.BoxedLongModule)
794-
case tpnme.Float => TYPE(defn.BoxedFloatModule)
795-
case tpnme.Double => TYPE(defn.BoxedDoubleModule)
796-
case tpnme.Unit => TYPE(defn.BoxedUnitModule)
797-
case _ => default
798-
}
799-
}
800-
801780
// --- Higher order traversal methods -------------------------------
802781

803782
/** Apply `f` to each subtree of this tree */
@@ -842,6 +821,23 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
842821
}
843822
}
844823

824+
/** A tree that represents the class of the erasure of type `tp`. */
825+
def clsOf(tp: Type)(implicit ctx: Context): Tree = {
826+
def TYPE(module: TermSymbol) = ref(module).select(nme.TYPE_)
827+
defn.scalaClassName(tp) match {
828+
case tpnme.Boolean => TYPE(defn.BoxedBooleanModule)
829+
case tpnme.Byte => TYPE(defn.BoxedByteModule)
830+
case tpnme.Short => TYPE(defn.BoxedShortModule)
831+
case tpnme.Char => TYPE(defn.BoxedCharModule)
832+
case tpnme.Int => TYPE(defn.BoxedIntModule)
833+
case tpnme.Long => TYPE(defn.BoxedLongModule)
834+
case tpnme.Float => TYPE(defn.BoxedFloatModule)
835+
case tpnme.Double => TYPE(defn.BoxedDoubleModule)
836+
case tpnme.Unit => TYPE(defn.BoxedUnitModule)
837+
case _ => Literal(Constant(TypeErasure.erasure(tp)))
838+
}
839+
}
840+
845841
def applyOverloaded(receiver: Tree, method: TermName, args: List[Tree], targs: List[Type], expectedType: Type, isAnnotConstructor: Boolean = false)(implicit ctx: Context): Tree = {
846842
val typer = ctx.typer
847843
val proto = new FunProtoTyped(args, expectedType, typer)

src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,9 @@ class Definitions {
419419
lazy val LanguageModuleRef = ctx.requiredModule("dotty.language")
420420
def LanguageModuleClass(implicit ctx: Context) = LanguageModuleRef.symbol.moduleClass.asClass
421421
lazy val NonLocalReturnControlType: TypeRef = ctx.requiredClassRef("scala.runtime.NonLocalReturnControl")
422+
lazy val ClassTagType = ctx.requiredClassRef("scala.reflect.ClassTag")
423+
def ClassTagClass(implicit ctx: Context) = ClassTagType.symbol.asClass
424+
def ClassTagModule(implicit ctx: Context) = ClassTagClass.companionModule
422425

423426
// Annotation base classes
424427
lazy val AnnotationType = ctx.requiredClassRef("scala.annotation.Annotation")

src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,8 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
290290
ConstantType(Constant(readName().toString))
291291
case NULLconst =>
292292
ConstantType(Constant(null))
293+
case CLASSconst =>
294+
ConstantType(Constant(readType()))
293295
case BYNAMEtype =>
294296
ExprType(readType())
295297
}

src/dotty/tools/dotc/transform/ClassOf.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class ClassOf extends MiniPhaseTransform {
3131
override def transformTypeApply(tree: TypeApply)(implicit ctx: Context, info: TransformerInfo): Tree =
3232
if (tree.symbol eq classOfMethod) {
3333
val targ = tree.args.head.tpe
34-
tree.clsOf(targ, Literal(Constant(TypeErasure.erasure(targ))))
34+
clsOf(targ).ensureConforms(tree.tpe).withPos(tree.pos)
3535
}
3636
else tree
3737
}

src/dotty/tools/dotc/transform/GetClass.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import ast.tpd
55
import core.Contexts.Context
66
import core.StdNames.nme
77
import core.Phases.Phase
8+
import TypeUtils._
89
import TreeTransforms.{MiniPhaseTransform, TransformerInfo}
910

1011
/** Rewrite `getClass` calls as follow:
@@ -24,7 +25,8 @@ class GetClass extends MiniPhaseTransform {
2425
override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo): Tree = {
2526
import ast.Trees._
2627
tree match {
27-
case Apply(Select(qual, nme.getClass_), Nil) => tree.clsOf(qual.tpe.widen, tree)
28+
case Apply(Select(qual, nme.getClass_), Nil) if qual.tpe.widen.isPrimitiveValueType =>
29+
clsOf(qual.tpe.widen).withPos(tree.pos)
2830
case _ => tree
2931
}
3032
}

src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1472,7 +1472,9 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
14721472
case ambi: AmbiguousImplicits =>
14731473
implicitArgError(s"ambiguous implicits: ${ambi.explanation} of $where")
14741474
case failure: SearchFailure =>
1475-
implicitArgError(d"no implicit argument of type $formal found for $where" + failure.postscript)
1475+
val arg = synthesizedClassTag(formal)
1476+
if (!arg.isEmpty) arg
1477+
else implicitArgError(d"no implicit argument of type $formal found for $where" + failure.postscript)
14761478
}
14771479
}
14781480
if (errors.nonEmpty) {
@@ -1533,6 +1535,27 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
15331535
}
15341536
}
15351537

1538+
/** If `formal` is of the form ClassTag[T], where `T` is a class type,
1539+
* synthesize a class tag for `T`.
1540+
*/
1541+
def synthesizedClassTag(formal: Type): Tree = {
1542+
if (formal.isRef(defn.ClassTagClass))
1543+
formal.argTypes match {
1544+
case arg :: Nil =>
1545+
arg.underlyingClassRef(refinementOK = false) match {
1546+
case tref: TypeRef =>
1547+
return ref(defn.ClassTagModule)
1548+
.select(nme.apply)
1549+
.appliedToType(arg)
1550+
.appliedTo(clsOf(tref))
1551+
.withPos(tree.pos.endPos)
1552+
case _ =>
1553+
}
1554+
case _ =>
1555+
}
1556+
EmptyTree
1557+
}
1558+
15361559
/** Adapt an expression of constant type to a different constant type `tpe`. */
15371560
def adaptConstant(tree: Tree, tpe: ConstantType): Tree = {
15381561
def lit = Literal(tpe.value).withPos(tree.pos)

0 commit comments

Comments
 (0)