From d1672ba39a0b890c98a2d4345325cb2bc90e972b Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 18 Feb 2016 14:03:35 +0100 Subject: [PATCH 01/10] Remove bogus test Tests failures were caused by previous incomplete implementation of classTag. --- test/dotc/tests.scala | 1 - tests/neg/arrayclone-new.scala | 38 ---------------------------------- 2 files changed, 39 deletions(-) delete mode 100644 tests/neg/arrayclone-new.scala diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala index 70af32bd3d53..cbbcd41bbfb7 100644 --- a/test/dotc/tests.scala +++ b/test/dotc/tests.scala @@ -174,7 +174,6 @@ class tests extends CompilerTest { @Test def neg_selfInheritance = compileFile(negDir, "selfInheritance", xerrors = 6) @Test def neg_selfreq = compileFile(negDir, "selfreq", xerrors = 2) @Test def neg_singletons = compileFile(negDir, "singletons", xerrors = 8) - @Test def neg_shadowedImplicits = compileFile(negDir, "arrayclone-new", xerrors = 2) @Test def neg_ski = compileFile(negDir, "ski", xerrors = 12) @Test def neg_traitParamsTyper = compileFile(negDir, "traitParamsTyper", xerrors = 5) @Test def neg_traitParamsMixin = compileFile(negDir, "traitParamsMixin", xerrors = 2) diff --git a/tests/neg/arrayclone-new.scala b/tests/neg/arrayclone-new.scala deleted file mode 100644 index 4e33a7d8cde6..000000000000 --- a/tests/neg/arrayclone-new.scala +++ /dev/null @@ -1,38 +0,0 @@ -// Run with -explaintypes to see information about shadowing failures -import scala.reflect.{ClassTag, classTag} - -object Test extends dotty.runtime.LegacyApp{ - ObjectArrayClone; - PolymorphicArrayClone; -} - -object ObjectArrayClone{ - val it : Array[String] = Array("1", "0"); - val cloned = it.clone(); - assert(cloned.sameElements(it)); - cloned(0) = "0"; - assert(it(0) == "1") -} - -object PolymorphicArrayClone{ - def testIt[T](it : Array[T], one : T, zero : T) = { - val cloned = it.clone(); - assert(cloned.sameElements(it)); - cloned(0) = zero; - assert(it(0) == one) - } - - testIt(Array("one", "two"), "one", "two"); - - class Mangler[T: ClassTag](ts : T*){ - // this will always be a BoxedAnyArray even after we've unboxed its contents. - val it = ts.toArray[T]; - } - - val mangled = new Mangler[Int](0, 1); - - val y : Array[Int] = mangled.it; // make sure it's unboxed - - testIt(mangled.it, 0, 1); -} - From ad0663764c6d74bafaf034bf23b9c37847b54be2 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 18 Feb 2016 14:07:03 +0100 Subject: [PATCH 02/10] Synthesize classTags in Typer. Now diagnoses missing ClassTags of abstract types as implicit failures. Also: Simpler API of tpd.clsOf. --- src/dotty/DottyPredef.scala | 34 +++-------------- src/dotty/tools/dotc/Compiler.scala | 1 - src/dotty/tools/dotc/ast/tpd.scala | 38 +++++++++---------- src/dotty/tools/dotc/core/Definitions.scala | 3 ++ .../tools/dotc/core/tasty/TreeUnpickler.scala | 2 + src/dotty/tools/dotc/transform/ClassOf.scala | 2 +- src/dotty/tools/dotc/transform/GetClass.scala | 4 +- src/dotty/tools/dotc/typer/Typer.scala | 25 +++++++++++- 8 files changed, 55 insertions(+), 54 deletions(-) diff --git a/src/dotty/DottyPredef.scala b/src/dotty/DottyPredef.scala index 0c2492c94725..007493fcb55a 100644 --- a/src/dotty/DottyPredef.scala +++ b/src/dotty/DottyPredef.scala @@ -1,37 +1,13 @@ package dotty -import scala.reflect.ClassTag import scala.reflect.runtime.universe.TypeTag import scala.Predef.??? -abstract class I1 { - implicit def classTag[T]: ClassTag[T] = ??? +/** unimplemented implicit for TypeTag */ +object DottyPredef { implicit def typeTag[T]: TypeTag[T] = ??? - implicit val DoubleClassTag: ClassTag[Double] = ClassTag.Double -} -abstract class I2 extends I1 { - implicit val FloatClassTag: ClassTag[Double] = ClassTag.Double -} -abstract class I3 extends I2 { - implicit val LongClassTag: ClassTag[Long] = ClassTag.Long -} -abstract class I4 extends I3 { - implicit val IntClassTag: ClassTag[Int] = ClassTag.Int -} -abstract class I5 extends I4 { - implicit val ShortClassTag: ClassTag[Short] = ClassTag.Short -} -abstract class I6 extends I5 { - implicit val ByteClassTag: ClassTag[Byte] = ClassTag.Byte - implicit val CharClassTag: ClassTag[Char] = ClassTag.Char - implicit val BooleanClassTag: ClassTag[Boolean] = ClassTag.Boolean - implicit val UnitClassTag: ClassTag[Unit] = ClassTag.Unit - implicit val NullClassTag: ClassTag[Null] = ClassTag.Null -} - -/** implicits for ClassTag and TypeTag. Should be implemented with macros */ -object DottyPredef extends I6 { - /** ClassTags for final classes */ - implicit val NothingClassTag: ClassTag[Nothing] = ClassTag.Nothing +// not yet: +// def classOf[T](implicit ctag: ClassTag[T]): Class[T] = +// ctag.runtimeClass } diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala index 99b7bd880fff..7c7648657d03 100644 --- a/src/dotty/tools/dotc/Compiler.scala +++ b/src/dotty/tools/dotc/Compiler.scala @@ -59,7 +59,6 @@ class Compiler { new SeqLiterals, new InterceptedMethods, new Getters, - new ClassTags, new ElimByName, new AugmentScala2Traits, new ResolveSuper), diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala index b78e4c79f3b2..a0400c1e84f8 100644 --- a/src/dotty/tools/dotc/ast/tpd.scala +++ b/src/dotty/tools/dotc/ast/tpd.scala @@ -777,27 +777,6 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { } else Assign(tree, rhs) - /** A tree in place of this tree that represents the class of type `tp`. - * Contains special handling if the class is a primitive value class - * and invokes a `default` method otherwise. - */ - def clsOf(tp: Type, default: => Tree)(implicit ctx: Context): Tree = { - def TYPE(module: TermSymbol) = - ref(module).select(nme.TYPE_).ensureConforms(tree.tpe).withPos(tree.pos) - defn.scalaClassName(tp) match { - case tpnme.Boolean => TYPE(defn.BoxedBooleanModule) - case tpnme.Byte => TYPE(defn.BoxedByteModule) - case tpnme.Short => TYPE(defn.BoxedShortModule) - case tpnme.Char => TYPE(defn.BoxedCharModule) - case tpnme.Int => TYPE(defn.BoxedIntModule) - case tpnme.Long => TYPE(defn.BoxedLongModule) - case tpnme.Float => TYPE(defn.BoxedFloatModule) - case tpnme.Double => TYPE(defn.BoxedDoubleModule) - case tpnme.Unit => TYPE(defn.BoxedUnitModule) - case _ => default - } - } - // --- Higher order traversal methods ------------------------------- /** Apply `f` to each subtree of this tree */ @@ -842,6 +821,23 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { } } + /** A tree that represents the class of the erasure of type `tp`. */ + def clsOf(tp: Type)(implicit ctx: Context): Tree = { + def TYPE(module: TermSymbol) = ref(module).select(nme.TYPE_) + defn.scalaClassName(tp) match { + case tpnme.Boolean => TYPE(defn.BoxedBooleanModule) + case tpnme.Byte => TYPE(defn.BoxedByteModule) + case tpnme.Short => TYPE(defn.BoxedShortModule) + case tpnme.Char => TYPE(defn.BoxedCharModule) + case tpnme.Int => TYPE(defn.BoxedIntModule) + case tpnme.Long => TYPE(defn.BoxedLongModule) + case tpnme.Float => TYPE(defn.BoxedFloatModule) + case tpnme.Double => TYPE(defn.BoxedDoubleModule) + case tpnme.Unit => TYPE(defn.BoxedUnitModule) + case _ => Literal(Constant(TypeErasure.erasure(tp))) + } + } + def applyOverloaded(receiver: Tree, method: TermName, args: List[Tree], targs: List[Type], expectedType: Type, isAnnotConstructor: Boolean = false)(implicit ctx: Context): Tree = { val typer = ctx.typer val proto = new FunProtoTyped(args, expectedType, typer) diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala index c5d42a4728e9..188a00fc2683 100644 --- a/src/dotty/tools/dotc/core/Definitions.scala +++ b/src/dotty/tools/dotc/core/Definitions.scala @@ -419,6 +419,9 @@ class Definitions { lazy val LanguageModuleRef = ctx.requiredModule("dotty.language") def LanguageModuleClass(implicit ctx: Context) = LanguageModuleRef.symbol.moduleClass.asClass lazy val NonLocalReturnControlType: TypeRef = ctx.requiredClassRef("scala.runtime.NonLocalReturnControl") + lazy val ClassTagType = ctx.requiredClassRef("scala.reflect.ClassTag") + def ClassTagClass(implicit ctx: Context) = ClassTagType.symbol.asClass + def ClassTagModule(implicit ctx: Context) = ClassTagClass.companionModule // Annotation base classes lazy val AnnotationType = ctx.requiredClassRef("scala.annotation.Annotation") diff --git a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 81d19f7e48eb..16caac02e20b 100644 --- a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -290,6 +290,8 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) { ConstantType(Constant(readName().toString)) case NULLconst => ConstantType(Constant(null)) + case CLASSconst => + ConstantType(Constant(readType())) case BYNAMEtype => ExprType(readType()) } diff --git a/src/dotty/tools/dotc/transform/ClassOf.scala b/src/dotty/tools/dotc/transform/ClassOf.scala index 51a68f9033e5..f8f4991c8d23 100644 --- a/src/dotty/tools/dotc/transform/ClassOf.scala +++ b/src/dotty/tools/dotc/transform/ClassOf.scala @@ -31,7 +31,7 @@ class ClassOf extends MiniPhaseTransform { override def transformTypeApply(tree: TypeApply)(implicit ctx: Context, info: TransformerInfo): Tree = if (tree.symbol eq classOfMethod) { val targ = tree.args.head.tpe - tree.clsOf(targ, Literal(Constant(TypeErasure.erasure(targ)))) + clsOf(targ).ensureConforms(tree.tpe).withPos(tree.pos) } else tree } diff --git a/src/dotty/tools/dotc/transform/GetClass.scala b/src/dotty/tools/dotc/transform/GetClass.scala index 9d182382d211..f25fd6f64128 100644 --- a/src/dotty/tools/dotc/transform/GetClass.scala +++ b/src/dotty/tools/dotc/transform/GetClass.scala @@ -5,6 +5,7 @@ import ast.tpd import core.Contexts.Context import core.StdNames.nme import core.Phases.Phase +import TypeUtils._ import TreeTransforms.{MiniPhaseTransform, TransformerInfo} /** Rewrite `getClass` calls as follow: @@ -24,7 +25,8 @@ class GetClass extends MiniPhaseTransform { override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo): Tree = { import ast.Trees._ tree match { - case Apply(Select(qual, nme.getClass_), Nil) => tree.clsOf(qual.tpe.widen, tree) + case Apply(Select(qual, nme.getClass_), Nil) if qual.tpe.widen.isPrimitiveValueType => + clsOf(qual.tpe.widen).withPos(tree.pos) case _ => tree } } diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 854bc2094dea..65980a0f810a 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -1454,7 +1454,9 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit case ambi: AmbiguousImplicits => implicitArgError(s"ambiguous implicits: ${ambi.explanation} of $where") case failure: SearchFailure => - implicitArgError(d"no implicit argument of type $formal found for $where" + failure.postscript) + val arg = synthesizedClassTag(formal) + if (!arg.isEmpty) arg + else implicitArgError(d"no implicit argument of type $formal found for $where" + failure.postscript) } } if (errors.nonEmpty) { @@ -1515,6 +1517,27 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit } } + /** If `formal` is of the form ClassTag[T], where `T` is a class type, + * synthesize a class tag for `T`. + */ + def synthesizedClassTag(formal: Type): Tree = { + if (formal.isRef(defn.ClassTagClass)) + formal.argTypes match { + case arg :: Nil => + arg.underlyingClassRef(refinementOK = false) match { + case tref: TypeRef => + return ref(defn.ClassTagModule) + .select(nme.apply) + .appliedToType(arg) + .appliedTo(clsOf(tref)) + .withPos(tree.pos.endPos) + case _ => + } + case _ => + } + EmptyTree + } + /** Adapt an expression of constant type to a different constant type `tpe`. */ def adaptConstant(tree: Tree, tpe: ConstantType): Tree = { def lit = Literal(tpe.value).withPos(tree.pos) From d90973664184c9b76933e49eb72e4bb4d50c54c1 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 18 Feb 2016 14:48:45 +0100 Subject: [PATCH 03/10] Make type fully defined before searching for a ClassTag for it --- src/dotty/tools/dotc/typer/Typer.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 65980a0f810a..4d0efe875da8 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -1524,11 +1524,12 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit if (formal.isRef(defn.ClassTagClass)) formal.argTypes match { case arg :: Nil => - arg.underlyingClassRef(refinementOK = false) match { + val tp = fullyDefinedType(arg, "ClassTag argument", tree.pos) + tp.underlyingClassRef(refinementOK = false) match { case tref: TypeRef => return ref(defn.ClassTagModule) .select(nme.apply) - .appliedToType(arg) + .appliedToType(tp) .appliedTo(clsOf(tref)) .withPos(tree.pos.endPos) case _ => From c5ac21b65f997d3dd4b491d9ba0f06cf65320e33 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 18 Feb 2016 17:23:50 +0100 Subject: [PATCH 04/10] Fix search of Array classTags. If a classtag for `T` is available, a classtag for `Array[T]` can also be generated. --- src/dotty/DottyPredef.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/dotty/DottyPredef.scala b/src/dotty/DottyPredef.scala index 007493fcb55a..9170da476f97 100644 --- a/src/dotty/DottyPredef.scala +++ b/src/dotty/DottyPredef.scala @@ -1,13 +1,13 @@ package dotty import scala.reflect.runtime.universe.TypeTag +import scala.reflect.ClassTag import scala.Predef.??? /** unimplemented implicit for TypeTag */ object DottyPredef { implicit def typeTag[T]: TypeTag[T] = ??? -// not yet: -// def classOf[T](implicit ctag: ClassTag[T]): Class[T] = -// ctag.runtimeClass + implicit def arrayTag[T](implicit ctag: ClassTag[T]): ClassTag[Array[T]] = + ctag.wrap } From 00c0f4e4b63b550fb3731dc4f7f22584ac911e81 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 18 Feb 2016 17:25:31 +0100 Subject: [PATCH 05/10] Fix desugaring of classes with context bounds Context bounds did not make it before into secondary constructors. Now the evidence parameters generated by context bounds get copied into secondary constructors. Without this fix, scala.collection.immutable.PagedSeq fails to compile in new classtag scheme. --- src/dotty/tools/dotc/ast/Desugar.scala | 44 ++++++++++++++++++-------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/src/dotty/tools/dotc/ast/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala index 87694843ad6a..b59121462f82 100644 --- a/src/dotty/tools/dotc/ast/Desugar.scala +++ b/src/dotty/tools/dotc/ast/Desugar.scala @@ -147,18 +147,7 @@ object desugar { tparam } - val meth1 = epbuf.toList match { - case Nil => - meth - case evidenceParams => - val vparamss1 = vparamss.reverse match { - case (vparams @ (vparam :: _)) :: rvparamss if vparam.mods is Implicit => - ((vparams ++ evidenceParams) :: rvparamss).reverse - case _ => - vparamss :+ evidenceParams - } - cpy.DefDef(meth)(tparams = tparams1, vparamss = vparamss1) - } + val meth1 = addEvidenceParams(cpy.DefDef(meth)(tparams = tparams1), epbuf.toList) /** The longest prefix of parameter lists in vparamss whose total length does not exceed `n` */ def takeUpTo(vparamss: List[List[ValDef]], n: Int): List[List[ValDef]] = vparamss match { @@ -204,6 +193,30 @@ object desugar { } } + // Add all evidence parameters in `params` as implicit parameters to `meth` */ + private def addEvidenceParams(meth: DefDef, params: List[ValDef])(implicit ctx: Context): DefDef = + params match { + case Nil => + meth + case evidenceParams => + val vparamss1 = meth.vparamss.reverse match { + case (vparams @ (vparam :: _)) :: rvparamss if vparam.mods is Implicit => + ((vparams ++ evidenceParams) :: rvparamss).reverse + case _ => + meth.vparamss :+ evidenceParams + } + cpy.DefDef(meth)(vparamss = vparamss1) + } + + /** The implicit evidence parameters of `meth`, as generated by `desugar.defDef` */ + private def evidenceParams(meth: DefDef)(implicit ctx: Context): List[ValDef] = + meth.vparamss.reverse match { + case (vparams @ (vparam :: _)) :: _ if vparam.mods is Implicit => + vparams.dropWhile(!_.name.startsWith(nme.EVIDENCE_PARAM_PREFIX)) + case _ => + Nil + } + /** Fill in empty type bounds with Nothing/Any. Expand private local type parameters as follows: * * class C[v T] @@ -255,10 +268,13 @@ object desugar { else constr1.vparamss.nestedMap(toDefParam) val constr = cpy.DefDef(constr1)(tparams = constrTparams, vparamss = constrVparamss) - // Add constructor type parameters to auxiliary constructors + // Add constructor type parameters and evidence implicit parameters + // to auxiliary constructors val normalizedBody = impl.body map { case ddef: DefDef if ddef.name.isConstructorName => - cpy.DefDef(ddef)(tparams = constrTparams) + addEvidenceParams( + cpy.DefDef(ddef)(tparams = constrTparams), + evidenceParams(constr1).map(toDefParam)) case stat => stat } From 7020e5c80893482962327e98769188c69156c792 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 18 Feb 2016 21:23:57 +0100 Subject: [PATCH 06/10] Handle classOf in terms of ClassTag Advantage: classOf is not magic anymore. It's also more flexible as it gives us an easy way to go from a ClassTag to a class. For the moment we leave the Classof phase in, in order to do the right thing if somebody references Predef.classOf explicitly (our improved classOf is in DottyPredef). Once we merge DottyPredef and Predef we can get rid of the phase. --- src/dotty/DottyPredef.scala | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/dotty/DottyPredef.scala b/src/dotty/DottyPredef.scala index 9170da476f97..0cc2fb5ef157 100644 --- a/src/dotty/DottyPredef.scala +++ b/src/dotty/DottyPredef.scala @@ -10,4 +10,7 @@ object DottyPredef { implicit def arrayTag[T](implicit ctag: ClassTag[T]): ClassTag[Array[T]] = ctag.wrap + + def classOf[T](implicit ctag: ClassTag[T]): Class[T] = + ctag.runtimeClass.asInstanceOf[Class[T]] } From 33b6b498a85b26ba96b4606cc6da13c95e8ce0ef Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 18 Feb 2016 21:24:43 +0100 Subject: [PATCH 07/10] Adaptations needed for new classOf handling. Previously, the implicit definitions were always ambiguous, which is surely not right. --- .../tools/backend/jvm/DottyBackendInterface.scala | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/src/dotty/tools/backend/jvm/DottyBackendInterface.scala index 5776cc8e234f..2e57b499650a 100644 --- a/src/dotty/tools/backend/jvm/DottyBackendInterface.scala +++ b/src/dotty/tools/backend/jvm/DottyBackendInterface.scala @@ -179,14 +179,14 @@ class DottyBackendInterface(outputDirectory: AbstractFile)(implicit ctx: Context implicit val ApplyTag: ClassTag[Apply] = ClassTag[Apply](classOf[Apply]) implicit val SelectTag: ClassTag[Select] = ClassTag[Select](classOf[Select]) implicit val TypeApplyTag: ClassTag[TypeApply] = ClassTag[TypeApply](classOf[TypeApply]) - implicit val ClassDefTag: ClassTag[ClassDef] = ClassTag[TypeDef](classOf[TypeDef]) + val ClassDefTag: ClassTag[ClassDef] = ClassTag[TypeDef](classOf[TypeDef]) // no implicit, it's an alias of TypeDefTag implicit val TryTag: ClassTag[Try] = ClassTag[Try](classOf[Try]) implicit val AssignTag: ClassTag[Assign] = ClassTag[Assign](classOf[Assign]) implicit val IdentTag: ClassTag[Ident] = ClassTag[Ident](classOf[Ident]) implicit val IfTag: ClassTag[If] = ClassTag[If](classOf[If]) - implicit val LabelDefTag: ClassTag[LabelDef] = ClassTag[LabelDef](classOf[LabelDef]) + val LabelDefTag: ClassTag[LabelDef] = ClassTag[LabelDef](classOf[LabelDef]) // no implicit, it's an alias of DefDefTag implicit val ValDefTag: ClassTag[ValDef] = ClassTag[ValDef](classOf[ValDef]) - implicit val ThrowTag: ClassTag[Throw] = ClassTag[Throw](classOf[Throw]) + val ThrowTag: ClassTag[Throw] = ClassTag[Throw](classOf[Throw]) // no implicit, it's an alias of ApplyTag implicit val ReturnTag: ClassTag[Return] = ClassTag[Return](classOf[Return]) implicit val LiteralTag: ClassTag[Literal] = ClassTag[Literal](classOf[Literal]) implicit val BlockTag: ClassTag[Block] = ClassTag[Block](classOf[Block]) @@ -197,12 +197,12 @@ class DottyBackendInterface(outputDirectory: AbstractFile)(implicit ctx: Context implicit val ThisTag: ClassTag[This] = ClassTag[This](classOf[This]) implicit val AlternativeTag: ClassTag[Alternative] = ClassTag[Alternative](classOf[Alternative]) implicit val DefDefTag: ClassTag[DefDef] = ClassTag[DefDef](classOf[DefDef]) - implicit val ModuleDefTag: ClassTag[ModuleDef] = ClassTag[ModuleDef](classOf[ModuleDef]) + val ModuleDefTag: ClassTag[ModuleDef] = ClassTag[ModuleDef](classOf[ModuleDef]) // no implicit, it's an alias of NullTag implicit val NameTag: ClassTag[Name] = ClassTag[Name](classOf[Name]) implicit val TemplateTag: ClassTag[Template] = ClassTag[Template](classOf[Template]) implicit val BindTag: ClassTag[Bind] = ClassTag[Bind](classOf[Bind]) implicit val NewTag: ClassTag[New] = ClassTag[New](classOf[New]) - implicit val ApplyDynamicTag: ClassTag[ApplyDynamic] = ClassTag[ApplyDynamic](classOf[ApplyDynamic]) + val ApplyDynamicTag: ClassTag[ApplyDynamic] = ClassTag[ApplyDynamic](classOf[ApplyDynamic]) // no implicit, it's an alias of NullTag implicit val SuperTag: ClassTag[Super] = ClassTag[Super](classOf[Super]) implicit val ConstantClassTag: ClassTag[Constant] = ClassTag[Constant](classOf[Constant]) implicit val ClosureTag: ClassTag[Closure] = ClassTag[Closure](classOf[Closure]) From caa1cecbe08ce4e3682d3f0439af8b5381247b46 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 18 Feb 2016 21:25:24 +0100 Subject: [PATCH 08/10] Neg tests for classOf Tests that classOf as is discriminating than the previous definition in Scala (which was not implemented in dotty so far). --- test/dotc/tests.scala | 1 + tests/neg/classOf.scala | 11 +++++++++++ 2 files changed, 12 insertions(+) create mode 100644 tests/neg/classOf.scala diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala index cbbcd41bbfb7..9d9c0e8e9b1a 100644 --- a/test/dotc/tests.scala +++ b/test/dotc/tests.scala @@ -144,6 +144,7 @@ class tests extends CompilerTest { @Test def neg_variancesConstr = compileFile(negDir, "variances-constr", xerrors = 2) @Test def neg_i871_missingReturnType = compileFile(negDir, "i871", xerrors = 2) @Test def neg_badAuxConstr = compileFile(negDir, "badAuxConstr", xerrors = 2) + @Test def neg_classOf = compileFile(negDir, "classOf", xerrors = 4) @Test def neg_typetest = compileFile(negDir, "typetest", xerrors = 1) @Test def neg_t1569_failedAvoid = compileFile(negDir, "t1569-failedAvoid", xerrors = 1) @Test def neg_clashes = compileFile(negDir, "clashes", xerrors = 2) diff --git a/tests/neg/classOf.scala b/tests/neg/classOf.scala new file mode 100644 index 000000000000..e13cf71c43a2 --- /dev/null +++ b/tests/neg/classOf.scala @@ -0,0 +1,11 @@ +object Test { + + class C { type I } + type A = C + + def f1[T] = classOf[T] // error + def f2[T <: String] = classOf[T] // error + val x = classOf[Test.type] // error + val y = classOf[C { type I = String }] // error + val z = classOf[A] // ok +} From b6decfaeddcac550517d4803ab88091a48fc5054 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 18 Feb 2016 23:00:34 +0100 Subject: [PATCH 09/10] Fix ClassTag.arrayTag Cannot simply use `wrap` as it does the wrong thing for Array[Unit] (what a mess!). --- src/dotty/DottyPredef.scala | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/dotty/DottyPredef.scala b/src/dotty/DottyPredef.scala index 0cc2fb5ef157..5fa3b0bf4115 100644 --- a/src/dotty/DottyPredef.scala +++ b/src/dotty/DottyPredef.scala @@ -2,14 +2,18 @@ package dotty import scala.reflect.runtime.universe.TypeTag import scala.reflect.ClassTag -import scala.Predef.??? +import scala.Predef.{???, implicitly} /** unimplemented implicit for TypeTag */ object DottyPredef { implicit def typeTag[T]: TypeTag[T] = ??? - implicit def arrayTag[T](implicit ctag: ClassTag[T]): ClassTag[Array[T]] = - ctag.wrap + implicit def arrayTag[T](implicit ctag: ClassTag[T]): ClassTag[Array[T]] = { + val ctag1 = + if (ctag == ClassTag.Unit) implicitly[ClassTag[scala.runtime.BoxedUnit]] + else ctag + ctag1.wrap.asInstanceOf[ClassTag[Array[T]]] + } def classOf[T](implicit ctag: ClassTag[T]): Class[T] = ctag.runtimeClass.asInstanceOf[Class[T]] From 2bbd181b944aca9b515a02d78ceb19c4bd9e36ef Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 18 Feb 2016 23:06:15 +0100 Subject: [PATCH 10/10] Document status of ClassOf phase --- src/dotty/tools/dotc/transform/ClassOf.scala | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/dotty/tools/dotc/transform/ClassOf.scala b/src/dotty/tools/dotc/transform/ClassOf.scala index f8f4991c8d23..93aca1b74ca9 100644 --- a/src/dotty/tools/dotc/transform/ClassOf.scala +++ b/src/dotty/tools/dotc/transform/ClassOf.scala @@ -15,6 +15,11 @@ import TreeTransforms.{MiniPhaseTransform, TransformerInfo, TreeTransform} * classOf[C] -> B.TYPE * For every non-primitive class D: * classOf[D] -> Literal(Constant(erasure(D))) + * + * NOTE: This is almost redundant since classOf now resolves + * to DottyPredef.classOf, which does not need the transform. The phase + * is kept in in order not to crash if someone calls Predef.classOf. + * Once we have merged Predef and DottyPredef, the phase can be dropped. */ class ClassOf extends MiniPhaseTransform { import tpd._