Skip to content

Change pattern matcher #2822

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 26 commits into from
Closed
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion compiler/src/dotty/tools/dotc/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ class Compiler {
new CrossCastAnd, // Normalize selections involving intersection types.
new Splitter), // Expand selections involving union types into conditionals
List(new VCInlineMethods, // Inlines calls to value class methods
new IsInstanceOfEvaluator, // Issues warnings when unreachable statements are present in match/if expressions
new SeqLiterals, // Express vararg arguments as arrays
new InterceptedMethods, // Special handling of `==`, `|=`, `getClass` methods
new Getters, // Replace non-private vals and vars with getter defs (fields are added later)
Expand Down
20 changes: 20 additions & 0 deletions compiler/src/dotty/tools/dotc/ast/TreeInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,26 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
case _ =>
false
}

/** Structural tree comparison (since == on trees is reference equality).
* For the moment, only Ident, Select, Literal, Apply and TypeApply are supported
*/
implicit class StructuralEqDeco(t1: Tree) {
def === (t2: Tree)(implicit ctx: Context): Boolean = (t1, t2) match {
case (t1: Ident, t2: Ident) =>
t1.symbol == t2.symbol
case (t1 @ Select(q1, _), t2 @ Select(q2, _)) =>
t1.symbol == t2.symbol && q1 === q2
case (Literal(c1), Literal(c2)) =>
c1 == c2
case (Apply(f1, as1), Apply(f2, as2)) =>
f1 === f2 && as1.corresponds(as2)(_ === _)
case (TypeApply(f1, ts1), TypeApply(f2, ts2)) =>
f1 === f2 && ts1.tpes.corresponds(ts2.tpes)(_ =:= _)
case _ =>
false
}
}
}

object TreeInfo {
Expand Down
39 changes: 34 additions & 5 deletions compiler/src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import Denotations._, Decorators._, DenotTransformers._
import collection.mutable
import util.{Property, SourceFile, NoSource}
import typer.ErrorReporting._
import NameKinds.TempResultName
import NameKinds.{TempResultName, OuterSelectName}

import scala.annotation.tailrec
import scala.io.Codec
Expand Down Expand Up @@ -601,7 +601,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
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 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)

Expand Down Expand Up @@ -682,6 +682,12 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
def select(name: Name)(implicit ctx: Context): Select =
Select(tree, name)

/** A select node with the given selector name such that the designated
* member satisfies predicate `p`. Useful for disambiguating overloaded members.
*/
def select(name: Name, p: Symbol => Boolean)(implicit ctx: Context): Select =
select(tree.tpe.member(name).suchThat(p).symbol)

/** A select node with the given type */
def select(tp: NamedType)(implicit ctx: Context): Select =
untpd.Select(tree, tp.name).withType(tp)
Expand Down Expand Up @@ -751,9 +757,20 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
def ensureApplied(implicit ctx: Context): Tree =
if (tree.tpe.widen.isParameterless) tree else tree.appliedToNone

/** `tree.isInstanceOf[tp]` */
def isInstance(tp: Type)(implicit ctx: Context): Tree =
tree.select(defn.Any_isInstanceOf).appliedToType(tp)
/** `tree == that` */
def equal(that: Tree)(implicit ctx: Context) =
applyOverloaded(tree, nme.EQ, that :: Nil, Nil, defn.BooleanType)

/** `tree.isInstanceOf[tp]`, with special treatment of singleton types */
def isInstance(tp: Type)(implicit ctx: Context): Tree = tp match {
case tp: SingletonType =>
if (tp.widen.derivesFrom(defn.ObjectClass))
tree.ensureConforms(defn.ObjectType).select(defn.Object_eq).appliedTo(singleton(tp))
else
singleton(tp).equal(tree)
case _ =>
tree.select(defn.Any_isInstanceOf).appliedToType(tp)
}

/** tree.asInstanceOf[`tp`] */
def asInstance(tp: Type)(implicit ctx: Context): Tree = {
Expand All @@ -770,6 +787,11 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
else if (!ctx.erasedTypes) asInstance(tp)
else Erasure.Boxing.adaptToType(tree, tp)

/** `tree ne null` (might need a cast to be type correct) */
def testNotNull(implicit ctx: Context): Tree =
tree.ensureConforms(defn.ObjectType)
.select(defn.Object_ne).appliedTo(Literal(Constant(null)))

/** If inititializer tree is `_', the default value of its type,
* otherwise the tree itself.
*/
Expand Down Expand Up @@ -800,6 +822,13 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
}
else Assign(tree, rhs)

/** A synthetic select with that will be turned into an outer path by ExplicitOuter.
* @param levels How many outer levels to select
* @param tp The type of the destination of the outer path.
*/
def outerSelect(levels: Int, tp: Type)(implicit ctx: Context): Tree =
untpd.Select(tree, OuterSelectName(EmptyTermName, levels)).withType(tp)

// --- Higher order traversal methods -------------------------------

/** Apply `f` to each subtree of this tree */
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/config/Printers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,6 @@ object Printers {
val pickling: Printer = noPrinter
val inlining: Printer = noPrinter
val exhaustivity: Printer = noPrinter
val patmatch: Printer = noPrinter
val simplify: Printer = noPrinter
}
8 changes: 7 additions & 1 deletion compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -251,9 +251,11 @@ class Definitions {
lazy val Any_getClass = enterMethod(AnyClass, nme.getClass_, MethodType(Nil, ClassClass.typeRef.appliedTo(TypeBounds.empty)), Final)
lazy val Any_isInstanceOf = enterT1ParameterlessMethod(AnyClass, nme.isInstanceOf_, _ => BooleanType, Final)
lazy val Any_asInstanceOf = enterT1ParameterlessMethod(AnyClass, nme.asInstanceOf_, TypeParamRef(_, 0), Final)
lazy val Any_typeTest = enterT1ParameterlessMethod(AnyClass, nme.isInstanceOfPM, _ => BooleanType, Final)
// generated by pattern matcher, eliminated by erasure

def AnyMethods = List(Any_==, Any_!=, Any_equals, Any_hashCode,
Any_toString, Any_##, Any_getClass, Any_isInstanceOf, Any_asInstanceOf)
Any_toString, Any_##, Any_getClass, Any_isInstanceOf, Any_asInstanceOf, Any_typeTest)

lazy val ObjectClass: ClassSymbol = {
val cls = ctx.requiredClass("java.lang.Object")
Expand Down Expand Up @@ -371,6 +373,10 @@ class Definitions {
def Seq_apply(implicit ctx: Context) = Seq_applyR.symbol
lazy val Seq_headR = SeqClass.requiredMethodRef(nme.head)
def Seq_head(implicit ctx: Context) = Seq_headR.symbol
lazy val Seq_dropR = SeqClass.requiredMethodRef(nme.drop)
def Seq_drop(implicit ctx: Context) = Seq_dropR.symbol
lazy val Seq_lengthCompareR = SeqClass.requiredMethodRef(nme.lengthCompare)
def Seq_lengthCompare(implicit ctx: Context) = Seq_lengthCompareR.symbol

lazy val ArrayType: TypeRef = ctx.requiredClassRef("scala.Array")
def ArrayClass(implicit ctx: Context) = ArrayType.symbol.asClass
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/core/StdNames.scala
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,7 @@ object StdNames {
val isDefined: N = "isDefined"
val isEmpty: N = "isEmpty"
val isInstanceOf_ : N = "isInstanceOf"
val isInstanceOfPM: N = "$isInstanceOf$"
val java: N = "java"
val key: N = "key"
val lang: N = "lang"
Expand Down
18 changes: 11 additions & 7 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -214,12 +214,16 @@ object Types {
case _ => NoType
}

/** Is this type guaranteed not to have `null` as a value?
* For the moment this is only true for modules, but it could
* be refined later.
*/
final def isNotNull(implicit ctx: Context): Boolean =
classSymbol is ModuleClass
/** Is this type guaranteed not to have `null` as a value? */
final def isNotNull(implicit ctx: Context): Boolean = this match {
case tp: ConstantType => tp.value.value != null
case tp: ClassInfo => !tp.cls.isNullableClass && tp.cls != defn.NothingClass
case tp: TypeBounds => tp.lo.isNotNull
case tp: TypeProxy => tp.underlying.isNotNull
case AndType(tp1, tp2) => tp1.isNotNull || tp2.isNotNull
case OrType(tp1, tp2) => tp1.isNotNull && tp2.isNotNull
case _ => false
}

/** Is this type produced as a repair for an error? */
final def isError(implicit ctx: Context): Boolean = stripTypeVar match {
Expand Down Expand Up @@ -3747,7 +3751,7 @@ object Types {
if (underlying1 eq underlying) tp
else derivedAnnotatedType(tp, underlying1, mapOver(annot))

case tp @ WildcardType =>
case tp: WildcardType =>
derivedWildcardType(tp, mapOver(tp.optBounds))

case tp: JavaArrayType =>
Expand Down
7 changes: 4 additions & 3 deletions compiler/src/dotty/tools/dotc/transform/Erasure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,9 @@ class Erasure extends Phase with DenotTransformer { thisTransformer =>
i"The type $tp - ${tp.toString} of class ${tp.getClass} of tree $tree : ${tree.tpe} / ${tree.getClass} is illegal after erasure, phase = ${ctx.phase.prev}")
}

object Erasure extends TypeTestsCasts{

object Erasure {
import tpd._
import TypeTestsCasts._

object Boxing {

Expand Down Expand Up @@ -172,7 +172,8 @@ object Erasure extends TypeTestsCasts{
}

def constant(tree: Tree, const: Tree)(implicit ctx: Context) =
if (isPureExpr(tree)) const else Block(tree :: Nil, const)
(if (isPureExpr(tree)) const else Block(tree :: Nil, const))
.withPos(tree.pos)

final def box(tree: Tree, target: => String = "")(implicit ctx: Context): Tree = ctx.traceIndented(i"boxing ${tree.showSummary}: ${tree.tpe} into $target") {
tree.tpe.widen match {
Expand Down
Loading