aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2014-08-17 13:00:59 +0200
committerMartin Odersky <odersky@gmail.com>2014-08-17 13:00:59 +0200
commit58d4706463b08f2e448c3021adad809e6046e0fe (patch)
treeacee1e319a6c4ffcb9feef976cdfdd78a2568ea6
parentf91f030290ac817888a6249d91118f42b560ab87 (diff)
downloaddotty-58d4706463b08f2e448c3021adad809e6046e0fe.tar.gz
dotty-58d4706463b08f2e448c3021adad809e6046e0fe.tar.bz2
dotty-58d4706463b08f2e448c3021adad809e6046e0fe.zip
Split Nullarify functionality to ElimByName, Erasure
New phase ElimByName elimintaes by-name parameters. All other occurrences of parameterless methods and ExprTypes are eliminated in erasure. The reason for the split like this is that it is very hard for Nullarify to determine when to insert ()'s. The logic for this is fragile because we need to look at previous denotations which might not exist (before splitter) or might result from a merge between parameterless and nullary methods. In Erasure the same is much simpler to achieve.
-rw-r--r--src/dotty/tools/dotc/Compiler.scala3
-rw-r--r--src/dotty/tools/dotc/ElimLocals.scala2
-rw-r--r--src/dotty/tools/dotc/ast/TreeInfo.scala2
-rw-r--r--src/dotty/tools/dotc/ast/tpd.scala35
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala4
-rw-r--r--src/dotty/tools/dotc/core/transform/Erasure.scala13
-rw-r--r--src/dotty/tools/dotc/transform/ElimByName.scala113
-rw-r--r--src/dotty/tools/dotc/transform/ElimRepeated.scala2
-rw-r--r--src/dotty/tools/dotc/transform/Erasure.scala49
-rw-r--r--src/dotty/tools/dotc/transform/ExtensionMethods.scala2
-rw-r--r--src/dotty/tools/dotc/transform/Nullarify.scala147
-rw-r--r--src/dotty/tools/dotc/transform/SymUtils.scala25
-rw-r--r--src/dotty/tools/dotc/transform/TypeTestsCasts.scala2
-rw-r--r--src/dotty/tools/dotc/transform/TypeUtils.scala7
-rw-r--r--src/dotty/tools/dotc/typer/Checking.scala7
-rw-r--r--test/dotc/tests.scala2
-rw-r--r--tests/pos/Patterns.scala6
17 files changed, 207 insertions, 214 deletions
diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala
index cae8c5782..7bf387549 100644
--- a/src/dotty/tools/dotc/Compiler.scala
+++ b/src/dotty/tools/dotc/Compiler.scala
@@ -28,7 +28,8 @@ class Compiler {
List(new PatternMatcher,
// new LazyValTranformContext().transformer, // disabled, awaiting fixes
new Splitter),
- List(new Nullarify,
+ List(new ElimByName),
+ List(
new TypeTestsCasts,
new InterceptedMethods,
new Literalize),
diff --git a/src/dotty/tools/dotc/ElimLocals.scala b/src/dotty/tools/dotc/ElimLocals.scala
index 98da95f61..b5843375a 100644
--- a/src/dotty/tools/dotc/ElimLocals.scala
+++ b/src/dotty/tools/dotc/ElimLocals.scala
@@ -11,7 +11,7 @@ import Flags.Local
/** Widens all private[this] and protected[this] qualifiers to just private/protected */
class ElimLocals extends MiniPhaseTransform with SymTransformer { thisTransformer =>
- override def name = "elimlocals"
+ override def name = "elimLocals"
def transformSym(ref: SymDenotation)(implicit ctx: Context) =
dropLocal(ref)
diff --git a/src/dotty/tools/dotc/ast/TreeInfo.scala b/src/dotty/tools/dotc/ast/TreeInfo.scala
index ca2259930..881cc3f6e 100644
--- a/src/dotty/tools/dotc/ast/TreeInfo.scala
+++ b/src/dotty/tools/dotc/ast/TreeInfo.scala
@@ -409,7 +409,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
/** Strips layers of `.asInstanceOf[T]` / `_.$asInstanceOf[T]()` from an expression */
def stripCast(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = {
- def isCast(sel: tpd.Tree) = defn.asInstanceOfMethods contains sel.symbol
+ def isCast(sel: tpd.Tree) = sel.symbol == defn.Any_asInstanceOf
unsplice(tree) match {
case TypeApply(sel @ Select(inner, _), _) if isCast(sel) =>
stripCast(inner)
diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala
index b1e4a0cd3..87cbbc249 100644
--- a/src/dotty/tools/dotc/ast/tpd.scala
+++ b/src/dotty/tools/dotc/ast/tpd.scala
@@ -169,7 +169,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
ta.assignType(untpd.ValDef(Modifiers(sym), sym.name, TypeTree(sym.info), rhs), sym)
def SyntheticValDef(name: TermName, rhs: Tree)(implicit ctx: Context): ValDef =
- ValDef(ctx.newSymbol(ctx.owner, name, Synthetic, rhs.tpe, coord = rhs.pos), rhs)
+ ValDef(ctx.newSymbol(ctx.owner, name, Synthetic, rhs.tpe.widen, coord = rhs.pos), rhs)
def DefDef(sym: TermSymbol, rhs: Tree = EmptyTree)(implicit ctx: Context): DefDef =
ta.assignType(DefDef(sym, Function.const(rhs) _), sym)
@@ -348,21 +348,16 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
}
}
- override def Apply(tree: Tree)(fun: Tree, args: List[Tree])(implicit ctx: Context): Apply = {
- val tree1 = untpd.cpy.Apply(tree)(fun, args)
- tree match {
- case tree: Apply if (fun.tpe.widen eq tree.fun.tpe.widen) && sameTypes(args, tree.args) => tree1.withTypeUnchecked(tree.tpe)
- case _ => ta.assignType(tree1, fun, args)
- }
- }
+ override def Apply(tree: Tree)(fun: Tree, args: List[Tree])(implicit ctx: Context): Apply =
+ ta.assignType(untpd.cpy.Apply(tree)(fun, args), fun, args)
+ // Note: Reassigning the original type if `fun` and `args` have the same types as before
+ // does not work here: The computed type depends on the widened function type, not
+ // the function type itself. A treetransform may keep the function type the
+ // same but its widened type might change.
- override def TypeApply(tree: Tree)(fun: Tree, args: List[Tree])(implicit ctx: Context): TypeApply = {
- val tree1 = untpd.cpy.TypeApply(tree)(fun, args)
- tree match {
- case tree: TypeApply if (fun.tpe.widen eq tree.fun.tpe.widen) && sameTypes(args, tree.args) => tree1.withTypeUnchecked(tree.tpe)
- case _ => ta.assignType(tree1, fun, args)
- }
- }
+ override def TypeApply(tree: Tree)(fun: Tree, args: List[Tree])(implicit ctx: Context): TypeApply =
+ ta.assignType(untpd.cpy.TypeApply(tree)(fun, args), fun, args)
+ // Same remark as for Apply
override def Literal(tree: Tree)(const: Constant)(implicit ctx: Context): Literal =
ta.assignType(untpd.cpy.Literal(tree)(const))
@@ -403,13 +398,9 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
}
}
- override def Closure(tree: Tree)(env: List[Tree], meth: Tree, tpt: Tree)(implicit ctx: Context): Closure = {
- val tree1 = untpd.cpy.Closure(tree)(env, meth, tpt)
- tree match {
- case tree: Closure if (meth.tpe.widen eq tree.meth.tpe.widen) && (tpt eq tree.tpt) => tree1.withTypeUnchecked(tree.tpe)
- case _ => ta.assignType(tree1, meth, tpt)
- }
- }
+ override def Closure(tree: Tree)(env: List[Tree], meth: Tree, tpt: Tree)(implicit ctx: Context): Closure =
+ ta.assignType(untpd.cpy.Closure(tree)(env, meth, tpt), meth, tpt)
+ // Same remark as for Apply
override def Match(tree: Tree)(selector: Tree, cases: List[CaseDef])(implicit ctx: Context): Match = {
val tree1 = untpd.cpy.Match(tree)(selector, cases)
diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala
index 82ed3ce1d..9018d4015 100644
--- a/src/dotty/tools/dotc/core/Definitions.scala
+++ b/src/dotty/tools/dotc/core/Definitions.scala
@@ -417,10 +417,6 @@ class Definitions {
lazy val PhantomClasses = Set[Symbol](AnyClass, AnyValClass, NullClass, NothingClass)
- lazy val asInstanceOfMethods = Set[Symbol](Any_asInstanceOf)
- lazy val isInstanceOfMethods = Set[Symbol](Any_isInstanceOf)
- lazy val typeTestsOrCasts = asInstanceOfMethods ++ isInstanceOfMethods
-
lazy val RootImports = List[Symbol](JavaLangPackageVal, ScalaPackageVal, ScalaPredefModule, DottyPredefModule)
lazy val overriddenBySynthetic = Set[Symbol](Any_equals, Any_hashCode, Any_toString, Product_canEqual)
diff --git a/src/dotty/tools/dotc/core/transform/Erasure.scala b/src/dotty/tools/dotc/core/transform/Erasure.scala
index 19662d22a..be7df46a9 100644
--- a/src/dotty/tools/dotc/core/transform/Erasure.scala
+++ b/src/dotty/tools/dotc/core/transform/Erasure.scala
@@ -104,12 +104,14 @@ class Erasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wildcard
* - For a typeref P.C where C refers to a nested class, |P|.C.
* - For a typeref P.C where C refers to an alias type, the erasure of C's alias.
* - For a typeref P.C where C refers to an abstract type, the erasure of C's upper bound.
- * - For T1 & T2, erasure(T1) (??)
+ * - For T1 & T2, the merge of |T1| and |T2| (see mergeAnd)
* - For T1 | T2, the first base class in the linearization of T which is also a base class of T2
+ * - For => T, ()T
* - For a method type (Fs)scala.Unit, (|Fs|)scala.Unit.
* - For any other uncurried method type (Fs)T, (|Fs|)|T|.
* - For a curried method type (Fs1)(Fs2)T, (|Fs1|,Es2)ET where (Es2)ET = |(Fs2)T|.
- * - For a polymorphic type, the erasure of its result type.
+ * - For a polymorphic type [Ts](Ps)T, |(Ps)T|
+ * _ For a polymorphic type [Ts]T where T is not a method type, ()|T|
* - For the class info type of java.lang.Object, the same type without any parents.
* - For a class info type of a value class, the same type without any parents.
* - For any other class info type with parents Ps, the same type with
@@ -133,6 +135,8 @@ class Erasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wildcard
else tp.derivedSelect(this(tp.prefix))
case _: ThisType | _: ConstantType =>
tp
+ case ExprType(rt) =>
+ MethodType(Nil, Nil, this(rt))
case tp: TypeProxy =>
this(tp.underlying)
case AndType(tp1, tp2) =>
@@ -149,7 +153,10 @@ class Erasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wildcard
tp.derivedMethodType(tp.paramNames, formals, rt)
}
case tp: PolyType =>
- this(tp.resultType)
+ this(tp.resultType) match {
+ case rt: MethodType => rt
+ case rt => MethodType(Nil, Nil, rt)
+ }
case tp @ ClassInfo(pre, cls, classParents, decls, _) =>
if (cls is Package) tp
else {
diff --git a/src/dotty/tools/dotc/transform/ElimByName.scala b/src/dotty/tools/dotc/transform/ElimByName.scala
new file mode 100644
index 000000000..80edf8819
--- /dev/null
+++ b/src/dotty/tools/dotc/transform/ElimByName.scala
@@ -0,0 +1,113 @@
+package dotty.tools.dotc
+package transform
+
+import TreeTransforms._
+import core.DenotTransformers._
+import core.Symbols._
+import core.Contexts._
+import core.Types._
+import core.Flags._
+import core.Decorators._
+import SymUtils._
+import core.StdNames.nme
+import ast.Trees._
+
+/** This phase eliminates ExprTypes `=> T` and PolyTypes over value types `[X]T`.
+ * They are expressed in terms of nullary method or function types. More precisely:
+ *
+ * For types:
+ *
+ * => T ==> () => T if T is the type of a parameter
+ * ==> ()T otherwise
+ * [X]T ==> [X]()T
+ *
+ * For definitions:
+ *
+ * def f: R ==> def f(): R
+ * def f[X]: R ==> def f[X](): R
+ * (x: => T) ==> (x: () => T)
+ *
+ * For terms:
+ *
+ * f ==> f() if f had type => T and is not a parameter
+ * x ==> x.apply() if x is a parameter that had type => T
+ * e.apply() ==> e if e.apply() is an argument to a call-by-name parameter
+ * expr ==> () => expr if other expr is an argument to a call-by-name parameter
+ *
+ */
+class ElimByName extends MiniPhaseTransform with InfoTransformer { thisTransformer =>
+ import ast.tpd._
+
+ override def name: String = "elimByName"
+
+ override def runsAfterGroupsOf: Set[String] = Set("splitter")
+ // assumes idents and selects have symbols; interferes with splitter distribution
+ // that's why it's "after group".
+
+ override def treeTransformPhase = thisTransformer.next
+
+ /** The info of the tree's symbol at phase Nullarify (i.e. before transformation) */
+ private def originalDenotation(tree: Tree)(implicit ctx: Context) =
+ tree.symbol.denot(ctx.withPhase(thisTransformer))
+
+ override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo): Tree =
+ ctx.traceIndented(s"transforming ${tree.show} at phase ${ctx.phase}", show = true) {
+
+ def transformArg(arg: Tree, formal: Type): Tree = formal match {
+ case _: ExprType =>
+ arg match {
+ case Apply(Select(qual, nme.apply), Nil) if qual.tpe derivesFrom defn.FunctionClass(0) =>
+ qual
+ case _ =>
+ val meth = ctx.newSymbol(
+ ctx.owner, nme.ANON_FUN, Synthetic, MethodType(Nil, Nil, arg.tpe.widen))
+ Closure(meth, _ => arg)
+ }
+ case _ =>
+ arg
+ }
+
+ /** Given that `info` is the possibly curried) method type of the
+ * tree's symbol, the method type that corresponds to the current application.
+ */
+ def matchingMethType(info: Type, tree: Tree): Type = tree match {
+ case Apply(fn, _) => matchingMethType(info.resultType, fn)
+ case _ => info
+ }
+
+ val origMethType = originalDenotation(tree.fun).info match {
+ case pt: PolyType => pt.resultType
+ case mt => mt
+ }
+
+ val MethodType(_, formals) = matchingMethType(origMethType, tree.fun)
+ val args1 = tree.args.zipWithConserve(formals)(transformArg)
+ cpy.Apply(tree)(tree.fun, args1)
+ }
+
+ override def transformIdent(tree: Ident)(implicit ctx: Context, info: TransformerInfo): Tree = {
+ val origDenot = originalDenotation(tree)
+ if ((origDenot is Param) && (origDenot.info.isInstanceOf[ExprType]))
+ tree.select(defn.Function0_apply).appliedToNone
+ else tree
+ }
+
+ def elimByNameParams(tp: Type)(implicit ctx: Context): Type = tp match {
+ case tp: PolyType =>
+ tp.derivedPolyType(tp.paramNames, tp.paramBounds, elimByNameParams(tp.resultType))
+ case tp: MethodType =>
+ tp.derivedMethodType(tp.paramNames, tp.paramTypes mapConserve transformParamInfo,
+ elimByNameParams(tp.resultType))
+ case _ =>
+ tp
+ }
+
+ def transformParamInfo(tp: Type)(implicit ctx: Context) = tp match {
+ case ExprType(rt) => defn.FunctionType(Nil, rt)
+ case _ => tp
+ }
+
+ def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type =
+ if (sym is Param) transformParamInfo(tp)
+ else elimByNameParams(tp)
+}
diff --git a/src/dotty/tools/dotc/transform/ElimRepeated.scala b/src/dotty/tools/dotc/transform/ElimRepeated.scala
index 3635a8741..04ca77a2d 100644
--- a/src/dotty/tools/dotc/transform/ElimRepeated.scala
+++ b/src/dotty/tools/dotc/transform/ElimRepeated.scala
@@ -23,7 +23,7 @@ import TypeUtils._
class ElimRepeated extends MiniPhaseTransform with InfoTransformer { thisTransformer =>
import ast.tpd._
- override def name = "elimrepeated"
+ override def name = "elimRepeated"
def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type =
elimRepeated(tp)
diff --git a/src/dotty/tools/dotc/transform/Erasure.scala b/src/dotty/tools/dotc/transform/Erasure.scala
index f02846735..e85161f2d 100644
--- a/src/dotty/tools/dotc/transform/Erasure.scala
+++ b/src/dotty/tools/dotc/transform/Erasure.scala
@@ -30,7 +30,7 @@ class Erasure extends Phase with DenotTransformer { thisTransformer =>
override def name: String = "erasure"
/** List of names of phases that should precede this phase */
- override def runsAfter: Set[String] = Set("typeTestsCasts", "intercepted", "splitter", "nullarify")
+ override def runsAfter: Set[String] = Set("typeTestsCasts"/*, "intercepted"*/, "splitter", "elimRepeated")
def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = ref match {
case ref: SymDenotation =>
@@ -100,8 +100,6 @@ object Erasure {
EmptyTree
}
- def isErasedValueType(tpe: Type)(implicit ctx: Context): Boolean = tpe.isInstanceOf[ErasedValueType]
-
def constant(tree: Tree, const: Tree)(implicit ctx: Context) =
if (isPureExpr(tree)) Block(tree :: Nil, const) else const
@@ -169,25 +167,32 @@ object Erasure {
/** Adaptation of an expression `e` to an expected type `PT`, applying the following
* rewritings exhaustively as long as the type of `e` is not a subtype of `PT`.
*
+ * e -> e() if `e` appears not as the function part of an application
* e -> box(e) if `e` is of erased value type
* e -> unbox(e, PT) otherwise, if `PT` is an erased value type
* e -> box(e) if `e` is of primitive type and `PT` is not a primitive type
* e -> unbox(e, PT) if `PT` is a primitive type and `e` is not of primitive type
* e -> cast(e, PT) otherwise
*/
- def adaptToType(tree: Tree, pt: Type)(implicit ctx: Context): Tree =
- if (tree.tpe <:< pt)
- tree
- else if (tree.tpe.widen.isErasedValueType)
- adaptToType(box(tree), pt)
- else if (pt.isErasedValueType)
- adaptToType(unbox(tree, pt), pt)
- else if (tree.tpe.widen.isPrimitiveValueType && !pt.isPrimitiveValueType)
- adaptToType(box(tree), pt)
- else if (pt.isPrimitiveValueType && !tree.tpe.widen.isPrimitiveValueType)
- adaptToType(unbox(tree, pt), pt)
- else
- cast(tree, pt)
+ def adaptToType(tree: Tree, pt: Type)(implicit ctx: Context): Tree = {
+ def makeConformant(tpw: Type): Tree = tpw match {
+ case MethodType(Nil, _) =>
+ adaptToType(tree.appliedToNone, pt)
+ case _ =>
+ if (tpw.isErasedValueType)
+ adaptToType(box(tree), pt)
+ else if (pt.isErasedValueType)
+ adaptToType(unbox(tree, pt), pt)
+ else if (tpw.isPrimitiveValueType && !pt.isPrimitiveValueType)
+ adaptToType(box(tree), pt)
+ else if (pt.isPrimitiveValueType && !tpw.isPrimitiveValueType)
+ adaptToType(unbox(tree, pt), pt)
+ else
+ cast(tree, pt)
+ }
+ if ((pt eq AnyFunctionProto) || tree.tpe <:< pt) tree
+ else makeConformant(tree.tpe.widen)
+ }
}
class Typer extends typer.ReTyper with NoChecking {
@@ -278,7 +283,7 @@ object Erasure {
Nil
}
val allArgs = args ++ contextArgs(tree)
- val fun1 = typedExpr(fun, WildcardType)
+ val fun1 = typedExpr(fun, AnyFunctionProto)
fun1.tpe.widen match {
case mt: MethodType =>
val allArgs1 = allArgs.zipWithConserve(mt.paramTypes)(typedExpr)
@@ -296,10 +301,12 @@ object Erasure {
block // optimization, no checking needed, as block symbols do not change.
override def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(implicit ctx: Context) = {
- val tpt1 = // keep UnitTypes intact in result position
- if (ddef.tpt.typeOpt isRef defn.UnitClass) untpd.TypeTree(defn.UnitType) withPos ddef.tpt.pos
- else ddef.tpt
- val ddef1 = untpd.cpy.DefDef(ddef)(tparams = Nil, tpt = tpt1)
+ val ddef1 = untpd.cpy.DefDef(ddef)(
+ tparams = Nil,
+ vparamss = if (ddef.vparamss.isEmpty) Nil :: Nil else ddef.vparamss,
+ tpt = // keep UnitTypes intact in result position
+ if (ddef.tpt.typeOpt isRef defn.UnitClass) untpd.TypeTree(defn.UnitType) withPos ddef.tpt.pos
+ else ddef.tpt)
super.typedDefDef(ddef1, sym)
}
diff --git a/src/dotty/tools/dotc/transform/ExtensionMethods.scala b/src/dotty/tools/dotc/transform/ExtensionMethods.scala
index 42e10b126..82db07809 100644
--- a/src/dotty/tools/dotc/transform/ExtensionMethods.scala
+++ b/src/dotty/tools/dotc/transform/ExtensionMethods.scala
@@ -29,7 +29,7 @@ class ExtensionMethods extends MacroTransform with DenotTransformer with FullPar
/** the following two members override abstract members in Transform */
val name: String = "extmethods"
- override def runsAfter: Set[String] = Set("elimrepeated") // TODO: add tailrec
+ override def runsAfter: Set[String] = Set("elimRepeated") // TODO: add tailrec
override def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = ref match {
case ref: ClassDenotation if ref is ModuleClass =>
diff --git a/src/dotty/tools/dotc/transform/Nullarify.scala b/src/dotty/tools/dotc/transform/Nullarify.scala
deleted file mode 100644
index 554a51efb..000000000
--- a/src/dotty/tools/dotc/transform/Nullarify.scala
+++ /dev/null
@@ -1,147 +0,0 @@
-package dotty.tools.dotc
-package transform
-
-import TreeTransforms._
-import core.DenotTransformers._
-import core.Symbols._
-import core.Contexts._
-import core.Types._
-import core.Flags._
-import core.Decorators._
-import core.StdNames.nme
-import ast.Trees._
-
-/** This phase eliminates ExprTypes `=> T` and PolyTypes over value types `[X]T`.
- * They are expressed in terms of nullary method or function types. More precisely:
- *
- * For types:
- *
- * => T ==> () => T if T is the type of a parameter
- * ==> ()T otherwise
- * [X]T ==> [X]()T
- *
- * For definitions:
- *
- * def f: R ==> def f(): R
- * def f[X]: R ==> def f[X](): R
- * (x: => T) ==> (x: () => T)
- *
- * For terms:
- *
- * f ==> f() if f had type => T and is not a parameter
- * x ==> x.apply() if x is a parameter that had type => T
- * e.apply() ==> e if e.apply() is an argument to a call-by-name parameter
- * expr ==> () => expr if other expr is an argument to a call-by-name parameter
- *
- */
-class Nullarify extends MiniPhaseTransform with InfoTransformer {
- import ast.tpd._
-
- override def name: String = "nullarify"
-
- override def runsAfterGroupsOf: Set[String] = Set("splitter")
- // assumes idents and selects have symbols; interferes with splitter distribution
- // that's why it's "after group".
-
- override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo): Tree =
- ctx.traceIndented(s"transforming ${tree.show} at phase ${ctx.phase}", show = true) {
-
- def transformArg(arg: Tree, formal: Type): Tree = formal match {
- case _: ExprType =>
- arg match {
- case Apply(Select(qual, nme.apply), Nil) if qual.tpe <:< defn.FunctionClass(0).typeRef => qual
- case _ =>
- val meth = ctx.newSymbol(ctx.owner, nme.ANON_FUN, Synthetic,
- MethodType(Nil, Nil, arg.tpe.widen))
- Closure(meth, _ => arg)
- }
- case _ =>
- arg
- }
-
- // Compute the method type tree had before this phase is run.
- // This is needed to find out which parameters are by-name.
- val funType = tree.fun.symbol.info match {
- case info: PolyType => info.resultType
- case info => info
- }
- def methType(info: Type, tree: Tree): Type = tree match {
- case Apply(fn, args) => methType(info.resultType, fn)
- case _ => info
- }
- val MethodType(_, formals) = methType(funType, tree.fun)
-
- val args1 = tree.args.zipWithConserve(formals)(transformArg)
- cpy.Apply(tree)(tree.fun, args1) withType nullarify(tree.tpe)
- }
-
- /** Insert () or .apply() if the term refers to something that was converted to a
- * nullary method. Also, transform its type.
- */
- def insertParens(tree: Tree)(implicit ctx: Context): Tree = {
- val tp1 = transformInfo(tree.tpe, tree.symbol)
- val tree1 = tree.withType(tp1)
- val origType = tree.tpe.widenSingleton
- def result(implicit ctx: Context) = {
- tp1.widen match {
- case MethodType(Nil, _) if origType.widenExpr.isInstanceOf[ValueType] =>
- tree1.appliedToNone
- case _ =>
- origType match {
- case _: ExprType => // it's a by-name parameter
- tree1.select(defn.Function0_apply).appliedToNone
- case _ =>
- tree1
- }
- }
- }
- result(ctx.withPhase(ctx.phase.next))
- }
-
- override def transformIdent(tree: Ident)(implicit ctx: Context, info: TransformerInfo): Tree =
- insertParens(tree)
-
- override def transformSelect(tree: Select)(implicit ctx: Context, info: TransformerInfo): Tree =
- insertParens(tree)
-
- override def transformTypeApply(tree: TypeApply)(implicit ctx: Context, info: TransformerInfo): Tree =
- insertParens(tree)
-
- override def transformDefDef(tree: DefDef)(implicit ctx: Context, info: TransformerInfo): Tree = {
- val vparamss1 =
- if (tree.vparamss.isEmpty) Nil :: Nil
- else tree.vparamss nestedMap { vparam =>
- val tp = vparam.tpt.tpe
- val tp1 = nullarifyParam(tp)
- if (tp eq tp1) vparam
- else cpy.ValDef(vparam)(tpt = vparam.tpt.withType(tp1))
- }
- cpy.DefDef(tree)(vparamss = vparamss1)
- }
-
- def nullarify(tp: Type)(implicit ctx: Context): Type = tp match {
- case ExprType(rt) =>
- MethodType(Nil, Nil, rt)
- case pt: PolyType =>
- val rt = pt.resultType match {
- case mt: MethodType => nullarify(mt)
- case rt => MethodType(Nil, Nil, rt)
- }
- pt.derivedPolyType(pt.paramNames, pt.paramBounds, rt)
- case mt: MethodType =>
- mt.derivedMethodType(mt.paramNames, mt.paramTypes mapConserve nullarifyParam,
- nullarify(mt.resultType))
- case _ =>
- tp
- }
-
- def nullarifyParam(tp: Type)(implicit ctx: Context) = tp match {
- case ExprType(rt) => defn.FunctionType(Nil, rt)
- case _ => tp
- }
-
- def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type =
- if (defn.typeTestsOrCasts contains sym) tp
- else if (sym is Param) nullarifyParam(tp)
- else nullarify(tp)
-}
diff --git a/src/dotty/tools/dotc/transform/SymUtils.scala b/src/dotty/tools/dotc/transform/SymUtils.scala
new file mode 100644
index 000000000..e5dfd4d4e
--- /dev/null
+++ b/src/dotty/tools/dotc/transform/SymUtils.scala
@@ -0,0 +1,25 @@
+package dotty.tools.dotc
+package transform
+
+import core._
+import core.transform.Erasure.ErasedValueType
+import Types._
+import Contexts._
+import Symbols._
+import Decorators._
+import StdNames.nme
+import NameOps._
+import language.implicitConversions
+
+object SymUtils {
+ implicit def decorateSymUtils(sym: Symbol): SymUtils = new SymUtils(sym)
+}
+
+/** A decorator that provides methods on symbols
+ * that are needed in the transformer pipeline.
+ */
+class SymUtils(val self: Symbol) extends AnyVal {
+
+ def isTypeTestOrCast(implicit ctx: Context): Boolean =
+ self == defn.Any_asInstanceOf || self == defn.Any_isInstanceOf
+}
diff --git a/src/dotty/tools/dotc/transform/TypeTestsCasts.scala b/src/dotty/tools/dotc/transform/TypeTestsCasts.scala
index 93acc8e86..8d420546f 100644
--- a/src/dotty/tools/dotc/transform/TypeTestsCasts.scala
+++ b/src/dotty/tools/dotc/transform/TypeTestsCasts.scala
@@ -89,7 +89,7 @@ class TypeTestsCasts extends MiniPhaseTransform {
if (sym eq defn.Any_isInstanceOf)
transformIsInstanceOf(qual, tree.args.head.tpe)
- else if (defn.asInstanceOfMethods contains sym)
+ else if (sym eq defn.Any_asInstanceOf)
transformAsInstanceOf(tree.args.head.tpe)
else tree
diff --git a/src/dotty/tools/dotc/transform/TypeUtils.scala b/src/dotty/tools/dotc/transform/TypeUtils.scala
index d07930661..a07ac9041 100644
--- a/src/dotty/tools/dotc/transform/TypeUtils.scala
+++ b/src/dotty/tools/dotc/transform/TypeUtils.scala
@@ -16,8 +16,8 @@ object TypeUtils {
}
-/** A decorator that provides methods for type transformations
- * that are needed in the transofmer pipeline (not needed right now)
+/** A decorator that provides methods on types
+ * that are needed in the transformer pipeline.
*/
class TypeUtils(val self: Type) extends AnyVal {
@@ -26,5 +26,4 @@ class TypeUtils(val self: Type) extends AnyVal {
def isPrimitiveValueType(implicit ctx: Context): Boolean =
self.classSymbol.isPrimitiveValueClass
-
- }
+}
diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala
index eb202cc15..22129bde2 100644
--- a/src/dotty/tools/dotc/typer/Checking.scala
+++ b/src/dotty/tools/dotc/typer/Checking.scala
@@ -202,14 +202,15 @@ trait Checking {
def checkLegalPrefix(tp: Type, selector: Name, pos: Position)(implicit ctx: Context): Unit =
if (!tp.isLegalPrefixFor(selector)) ctx.error(d"$tp is not a valid prefix for '# $selector'", pos)
- /** Check that `tp` is a class type with a stable prefix. Also, if `isFirst` is
- * false check that `tp` is a trait.
+ /** 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.
* @return `tp` itself if it is a class or trait ref, ObjectClass.typeRef if not.
*/
def checkClassTypeWithStablePrefix(tp: Type, pos: Position, traitReq: Boolean)(implicit ctx: Context): Type =
tp.underlyingClassRef match {
case tref: TypeRef =>
- checkStable(tref.prefix, pos)
+ if (ctx.phase <= ctx.refchecksPhase) checkStable(tref.prefix, pos)
if (traitReq && !(tref.symbol is Trait)) ctx.error(d"$tref is not a trait", pos)
tp
case _ =>
diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala
index 795e11c75..f973bd1e0 100644
--- a/test/dotc/tests.scala
+++ b/test/dotc/tests.scala
@@ -14,7 +14,7 @@ class tests extends CompilerTest {
"-pagewidth", "160")
implicit val defaultOptions = noCheckOptions ++ List(
- "-Ycheck:splitter"
+ "-Ycheck:elimByName"
)
val twice = List("#runs", "2", "-YnoDoubleBindings")
diff --git a/tests/pos/Patterns.scala b/tests/pos/Patterns.scala
index 4470eb232..f601b95a8 100644
--- a/tests/pos/Patterns.scala
+++ b/tests/pos/Patterns.scala
@@ -1,4 +1,4 @@
-object Patterns {
+object Patterns {/*
('1', "1") match {
case (digit, str) => true
case _ => false
@@ -25,7 +25,7 @@ object Patterns {
def len[T](xs: List[T]): Int = xs match {
case _ :: xs1 => 1 + len(xs1)
case Nil => 0
- }
+ }*/
final def sameLength[T](xs: List[T], ys: List[T]): Boolean = xs match {
case _ :: xs1 =>
@@ -35,4 +35,4 @@ object Patterns {
}
case _ => ys.isEmpty
}
-} \ No newline at end of file
+}