diff options
-rw-r--r-- | src/dotty/tools/dotc/Compiler.scala | 3 | ||||
-rw-r--r-- | src/dotty/tools/dotc/ElimLocals.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/ast/TreeInfo.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/ast/tpd.scala | 35 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Definitions.scala | 4 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/transform/Erasure.scala | 13 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/ElimByName.scala | 113 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/ElimRepeated.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/Erasure.scala | 49 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/ExtensionMethods.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/Nullarify.scala | 147 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/SymUtils.scala | 25 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/TypeTestsCasts.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/TypeUtils.scala | 7 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Checking.scala | 7 | ||||
-rw-r--r-- | test/dotc/tests.scala | 2 | ||||
-rw-r--r-- | tests/pos/Patterns.scala | 6 |
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 +} |