aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc
diff options
context:
space:
mode:
authorDmitry Petrashko <dark@d-d.me>2016-03-02 10:16:05 +0100
committerDmitry Petrashko <dark@d-d.me>2016-03-02 10:16:05 +0100
commitae624660d3cc31e9956d7e537c7a5c7925afda68 (patch)
tree12e28b3db9125c3afbb03c6331326f6fab29ae13 /src/dotty/tools/dotc
parent0ae3ef2010b90bf06d76a768b0f0c5aa56c1180a (diff)
parent1d2fe4823bc4c8a69351d49229556ac3a1532778 (diff)
downloaddotty-ae624660d3cc31e9956d7e537c7a5c7925afda68.tar.gz
dotty-ae624660d3cc31e9956d7e537c7a5c7925afda68.tar.bz2
dotty-ae624660d3cc31e9956d7e537c7a5c7925afda68.zip
Merge pull request #1111 from dotty-staging/fix-#1099
Special case pattern matching against abstract types with class tags
Diffstat (limited to 'src/dotty/tools/dotc')
-rw-r--r--src/dotty/tools/dotc/Compiler.scala1
-rw-r--r--src/dotty/tools/dotc/ast/Desugar.scala44
-rw-r--r--src/dotty/tools/dotc/ast/tpd.scala38
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala5
-rw-r--r--src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala2
-rw-r--r--src/dotty/tools/dotc/transform/ClassOf.scala11
-rw-r--r--src/dotty/tools/dotc/transform/ClassTags.scala68
-rw-r--r--src/dotty/tools/dotc/transform/GetClass.scala4
-rw-r--r--src/dotty/tools/dotc/typer/Applications.scala4
-rw-r--r--src/dotty/tools/dotc/typer/Checking.scala13
-rw-r--r--src/dotty/tools/dotc/typer/Namer.scala3
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala91
12 files changed, 141 insertions, 143 deletions
diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala
index d526903b8..f12ab66c5 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/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala
index e9c641282..8ba155097 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]
@@ -256,10 +269,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
}
diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala
index 8e52d695b..7cd469d7a 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 c5d42a472..f16f25b23 100644
--- a/src/dotty/tools/dotc/core/Definitions.scala
+++ b/src/dotty/tools/dotc/core/Definitions.scala
@@ -221,6 +221,8 @@ class Definitions {
lazy val Predef_conformsR = ScalaPredefModule.requiredMethodRef("$conforms")
def Predef_conforms(implicit ctx: Context) = Predef_conformsR.symbol
+ lazy val Predef_classOfR = ScalaPredefModule.requiredMethodRef("classOf")
+ def Predef_classOf(implicit ctx: Context) = Predef_classOfR.symbol
lazy val ScalaRuntimeModuleRef = ctx.requiredModuleRef("scala.runtime.ScalaRunTime")
def ScalaRuntimeModule(implicit ctx: Context) = ScalaRuntimeModuleRef.symbol
@@ -419,6 +421,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 81d19f7e4..16caac02e 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 51a68f903..e7b6977c7 100644
--- a/src/dotty/tools/dotc/transform/ClassOf.scala
+++ b/src/dotty/tools/dotc/transform/ClassOf.scala
@@ -21,17 +21,10 @@ class ClassOf extends MiniPhaseTransform {
override def phaseName: String = "classOf"
- private var classOfMethod: TermSymbol = _
-
- override def prepareForUnit(tree: tpd.Tree)(implicit ctx: Context): TreeTransform = {
- classOfMethod = defn.ScalaPredefModule.requiredMethod(nme.classOf)
- this
- }
-
override def transformTypeApply(tree: TypeApply)(implicit ctx: Context, info: TransformerInfo): Tree =
- if (tree.symbol eq classOfMethod) {
+ if (tree.symbol eq defn.Predef_classOf) {
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/ClassTags.scala b/src/dotty/tools/dotc/transform/ClassTags.scala
deleted file mode 100644
index 8fd25f785..000000000
--- a/src/dotty/tools/dotc/transform/ClassTags.scala
+++ /dev/null
@@ -1,68 +0,0 @@
-package dotty.tools.dotc
-package transform
-
-import core._
-import TreeTransforms._
-import Contexts.Context
-import Flags._
-import SymUtils._
-import Symbols._
-import SymDenotations._
-import Types._
-import Decorators._
-import DenotTransformers._
-import StdNames._
-import NameOps._
-import ast.Trees._
-import dotty.tools.dotc.ast.tpd
-import dotty.tools.dotc.core.Constants.Constant
-import util.Positions._
-import Names._
-import collection.mutable
-
-/** This phase replaces calls to DottyPredef.classTag by code that synthesizes appropriate ClassTag
- */
-class ClassTags extends MiniPhaseTransform with IdentityDenotTransformer { thisTransform =>
- import ast.tpd._
-
- private var classTagCache: Symbol = null
- private var typeTagCache: Symbol = null
- private var scala2ClassTagModule: Symbol = null
-
-
- override def prepareForUnit(tree: tpd.Tree)(implicit ctx: Context): TreeTransform = {
- classTagCache = defn.DottyPredefModule.requiredMethod(nme.classTag)
- typeTagCache = defn.DottyPredefModule.requiredMethod(nme.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 defn = ctx.definitions
- val (elemType, ndims) = tp match {
- case defn.MultiArrayOf(elem, ndims) => (elem, ndims)
- case _ => (tp, 0)
- }
-
- val claz = tp.classSymbol
- val elemClaz = elemType.classSymbol
- assert(!claz.isPrimitiveValueClass) // should be inserted by typer
- val elemTag =
- if (elemClaz.isPrimitiveValueClass || elemClaz == defn.NothingClass || elemClaz == defn.NullClass)
- ref(defn.DottyPredefModule).select(s"${elemClaz.name}ClassTag".toTermName)
- else if (ValueClasses.isDerivedValueClass(elemClaz))
- ref(claz.companionModule)
- else if (elemClaz eq defn.AnyClass)
- ref(scala2ClassTagModule).select(nme.Any)
- else {
- val erazedTp = TypeErasure.erasure(elemType).classSymbol.typeRef
- ref(scala2ClassTagModule).select(nme.apply)
- .appliedToType(erazedTp).appliedTo(Literal(Constant(erazedTp)))
- }
- (1 to ndims).foldLeft(elemTag)((arr, level) => Select(arr, nme.wrap).ensureApplied).ensureConforms(tree.tpe)
- } else tree
-}
diff --git a/src/dotty/tools/dotc/transform/GetClass.scala b/src/dotty/tools/dotc/transform/GetClass.scala
index 9d182382d..f25fd6f64 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/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala
index 098385d4b..3b8c56ea6 100644
--- a/src/dotty/tools/dotc/typer/Applications.scala
+++ b/src/dotty/tools/dotc/typer/Applications.scala
@@ -617,6 +617,10 @@ trait Applications extends Compatibility { self: Typer =>
case pt: PolyType =>
if (typedArgs.length <= pt.paramBounds.length && !isNamed)
typedArgs = typedArgs.zipWithConserve(pt.paramBounds)(adaptTypeArg)
+ if (typedFn.symbol == defn.Predef_classOf && typedArgs.nonEmpty) {
+ val arg = typedArgs.head
+ checkClassType(arg.tpe, arg.pos, traitReq = false, stablePrefixReq = false)
+ }
case _ =>
}
assignType(cpy.TypeApply(tree)(typedFn, typedArgs), typedFn, typedArgs)
diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala
index b71a3ab2a..0ca121925 100644
--- a/src/dotty/tools/dotc/typer/Checking.scala
+++ b/src/dotty/tools/dotc/typer/Checking.scala
@@ -394,16 +394,17 @@ trait Checking {
ctx.error(i"$tp cannot be instantiated since it${rstatus.msg}", pos)
}
- /** Check that `tp` is a class type with a stable prefix. Also, if `traitReq` is
- * true check that `tp` is a trait.
- * Stability checking is disabled in phases after RefChecks.
+ /** Check that `tp` is a class type.
+ * Also, if `traitReq` is true, check that `tp` is a trait.
+ * Also, if `stablePrefixReq` is true and phase is not after RefChecks,
+ * check that class prefix is stable.
* @return `tp` itself if it is a class or trait ref, ObjectType if not.
*/
- def checkClassTypeWithStablePrefix(tp: Type, pos: Position, traitReq: Boolean)(implicit ctx: Context): Type =
+ def checkClassType(tp: Type, pos: Position, traitReq: Boolean, stablePrefixReq: Boolean)(implicit ctx: Context): Type =
tp.underlyingClassRef(refinementOK = false) match {
case tref: TypeRef =>
- if (ctx.phase <= ctx.refchecksPhase) checkStable(tref.prefix, pos)
if (traitReq && !(tref.symbol is Trait)) ctx.error(d"$tref is not a trait", pos)
+ if (stablePrefixReq && ctx.phase <= ctx.refchecksPhase) checkStable(tref.prefix, pos)
tp
case _ =>
ctx.error(d"$tp is not a class type", pos)
@@ -506,7 +507,7 @@ trait NoChecking extends Checking {
override def checkNonCyclic(sym: Symbol, info: TypeBounds, reportErrors: Boolean)(implicit ctx: Context): Type = info
override def checkValue(tree: Tree, proto: Type)(implicit ctx: Context): tree.type = tree
override def checkStable(tp: Type, pos: Position)(implicit ctx: Context): Unit = ()
- override def checkClassTypeWithStablePrefix(tp: Type, pos: Position, traitReq: Boolean)(implicit ctx: Context): Type = tp
+ override def checkClassType(tp: Type, pos: Position, traitReq: Boolean, stablePrefixReq: Boolean)(implicit ctx: Context): Type = tp
override def checkImplicitParamsNotSingletons(vparamss: List[List[ValDef]])(implicit ctx: Context): Unit = ()
override def checkFeasible(tp: Type, pos: Position, where: => String = "")(implicit ctx: Context): Type = tp
override def checkNoDoubleDefs(cls: Symbol)(implicit ctx: Context): Unit = ()
diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala
index 13ed96249..de27333d5 100644
--- a/src/dotty/tools/dotc/typer/Namer.scala
+++ b/src/dotty/tools/dotc/typer/Namer.scala
@@ -603,7 +603,8 @@ class Namer { typer: Typer =>
val ptype = parentType(parent)(ctx.superCallContext)
if (cls.isRefinementClass) ptype
else {
- val pt = checkClassTypeWithStablePrefix(ptype, parent.pos, traitReq = parent ne parents.head)
+ val pt = checkClassType(ptype, parent.pos,
+ traitReq = parent ne parents.head, stablePrefixReq = true)
if (pt.derivesFrom(cls)) {
val addendum = parent match {
case Select(qual: Super, _) if ctx.scala2Mode =>
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index fc2bf2381..84344dbb1 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -383,7 +383,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
case TypeApplications.EtaExpansion(tycon) => tpt1 = tpt1.withType(tycon)
case _ =>
}
- checkClassTypeWithStablePrefix(tpt1.tpe, tpt1.pos, traitReq = false)
+ checkClassType(tpt1.tpe, tpt1.pos, traitReq = false, stablePrefixReq = true)
assignType(cpy.New(tree)(tpt1), tpt1)
// todo in a later phase: checkInstantiatable(cls, tpt1.pos)
}
@@ -400,30 +400,53 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
}
def typedTyped(tree: untpd.Typed, pt: Type)(implicit ctx: Context): Tree = track("typedTyped") {
- def regularTyped(isWildcard: Boolean) = {
- val tpt1 =
- if (untpd.isWildcardStarArg(tree))
- TypeTree(defn.SeqType.appliedTo(pt :: Nil))
- else
- checkSimpleKinded(typedType(tree.tpt))
- val expr1 =
- if (isWildcard) tree.expr withType tpt1.tpe
- else typed(tree.expr, tpt1.tpe.widenSkolem)
- assignType(cpy.Typed(tree)(expr1, tpt1), tpt1)
- }
- tree.expr match {
+ /* Handles three cases:
+ * @param ifPat how to handle a pattern (_: T)
+ * @param ifExpr how to handle an expression (e: T)
+ * @param wildName what name `w` to use in the rewriting of
+ * (x: T) to (x @ (w: T)). This is either `_` or `_*`.
+ */
+ def cases(ifPat: => Tree, ifExpr: => Tree, wildName: TermName) = tree.expr match {
case id: untpd.Ident if (ctx.mode is Mode.Pattern) && isVarPattern(id) =>
- if (id.name == nme.WILDCARD || id.name == nme.WILDCARD_STAR) regularTyped(isWildcard = true)
+ if (id.name == nme.WILDCARD || id.name == nme.WILDCARD_STAR) ifPat
else {
import untpd._
- val name = if (untpd.isWildcardStarArg(tree)) nme.WILDCARD_STAR else nme.WILDCARD
- typed(Bind(id.name, Typed(Ident(name), tree.tpt)).withPos(id.pos), pt)
+ typed(Bind(id.name, Typed(Ident(wildName), tree.tpt)).withPos(id.pos), pt)
}
- case _ =>
- if (untpd.isWildcardStarArg(tree))
- seqToRepeated(typedExpr(tree.expr, defn.SeqType))
- else
- regularTyped(isWildcard = false)
+ case _ => ifExpr
+ }
+ def ascription(tpt: Tree, isWildcard: Boolean) = {
+ val expr1 =
+ if (isWildcard) tree.expr.withType(tpt.tpe)
+ else typed(tree.expr, tpt.tpe.widenSkolem)
+ assignType(cpy.Typed(tree)(expr1, tpt), tpt)
+ }
+ if (untpd.isWildcardStarArg(tree))
+ cases(
+ ifPat = ascription(TypeTree(defn.SeqType.appliedTo(pt :: Nil)), isWildcard = true),
+ ifExpr = seqToRepeated(typedExpr(tree.expr, defn.SeqType)),
+ wildName = nme.WILDCARD_STAR)
+ else {
+ def typedTpt = checkSimpleKinded(typedType(tree.tpt))
+ def handlePattern: Tree = {
+ val tpt1 = typedTpt
+ // special case for an abstract type that comes with a class tag
+ tpt1.tpe.dealias match {
+ case tref: TypeRef if !tref.symbol.isClass && !ctx.isAfterTyper =>
+ inferImplicit(defn.ClassTagType.appliedTo(tref),
+ EmptyTree, tpt1.pos)(ctx.retractMode(Mode.Pattern)) match {
+ case SearchSuccess(arg, _, _) =>
+ return typed(untpd.Apply(untpd.TypedSplice(arg), tree.expr), pt)
+ case _ =>
+ }
+ case _ =>
+ }
+ ascription(tpt1, isWildcard = true)
+ }
+ cases(
+ ifPat = handlePattern,
+ ifExpr = ascription(typedTpt, isWildcard = false),
+ wildName = nme.WILDCARD)
}
}
@@ -1477,7 +1500,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) {
@@ -1538,6 +1563,28 @@ 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 =>
+ val tp = fullyDefinedType(arg, "ClassTag argument", tree.pos)
+ tp.underlyingClassRef(refinementOK = false) match {
+ case tref: TypeRef =>
+ return ref(defn.ClassTagModule)
+ .select(nme.apply)
+ .appliedToType(tp)
+ .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)