diff options
-rw-r--r-- | src/dotty/tools/dotc/transform/IsInstanceOfEvaluator.scala | 63 | ||||
-rw-r--r-- | tests/disabled/pos-scala2/i1059.scala (renamed from tests/pos-scala2/i1059.scala) | 0 | ||||
-rw-r--r-- | tests/disabled/pos/t3480.scala (renamed from tests/pos/t3480.scala) | 0 | ||||
-rw-r--r-- | tests/neg/i1255.scala | 6 | ||||
-rw-r--r-- | tests/pos/t1168.scala | 2 | ||||
-rw-r--r-- | tests/run/t6637.scala | 3 |
6 files changed, 44 insertions, 30 deletions
diff --git a/src/dotty/tools/dotc/transform/IsInstanceOfEvaluator.scala b/src/dotty/tools/dotc/transform/IsInstanceOfEvaluator.scala index 8b1baa11a..14c3dea71 100644 --- a/src/dotty/tools/dotc/transform/IsInstanceOfEvaluator.scala +++ b/src/dotty/tools/dotc/transform/IsInstanceOfEvaluator.scala @@ -5,7 +5,7 @@ import dotty.tools.dotc.util.Positions._ import TreeTransforms.{MiniPhaseTransform, TransformerInfo} import core._ import Contexts.Context, Types._, Constants._, Decorators._, Symbols._ -import TypeUtils._, TypeErasure._ +import TypeUtils._, TypeErasure._, Flags._ /** Implements partial evaluation of `sc.isInstanceOf[Sel]` according to: @@ -25,10 +25,11 @@ import TypeUtils._, TypeErasure._ * * 1. evalTypeApply will establish the matrix and choose the appropriate * handling for the case: - * 2. a) handleStaticallyKnown - * b) falseIfUnrelated with `scrutinee <:< selector` - * c) handleFalseUnrelated - * d) leave as is (aka `happens`) + * 2. a) Sel/sc is a value class or scrutinee is `Any` + * b) handleStaticallyKnown + * c) falseIfUnrelated with `scrutinee <:< selector` + * d) handleFalseUnrelated + * e) leave as is (aka `happens`) * 3. Rewrite according to step taken in `2` */ class IsInstanceOfEvaluator extends MiniPhaseTransform { thisTransformer => @@ -43,43 +44,43 @@ class IsInstanceOfEvaluator extends MiniPhaseTransform { thisTransformer => * the correct warnings, or an error if statically known to be false in * match */ - def handleStaticallyKnown(tree: Select, scrutinee: Type, selector: Type, inMatch: Boolean, pos: Position): Tree = { + def handleStaticallyKnown(select: Select, scrutinee: Type, selector: Type, inMatch: Boolean, pos: Position): Tree = { val scrutineeSubSelector = scrutinee <:< selector if (!scrutineeSubSelector && inMatch) { ctx.error( s"this case is unreachable due to `${selector.show}` not being a subclass of `${scrutinee.show}`", Position(pos.start - 5, pos.end - 5) ) - rewrite(tree, to = false) + rewrite(select, to = false) } else if (!scrutineeSubSelector && !inMatch) { ctx.warning( s"this will always yield false since `${scrutinee.show}` is not a subclass of `${selector.show}` (will be optimized away)", pos ) - rewrite(tree, to = false) + rewrite(select, to = false) } else if (scrutineeSubSelector && !inMatch) { ctx.warning( s"this will always yield true if the scrutinee is non-null, since `${scrutinee.show}` is a subclass of `${selector.show}` (will be optimized away)", pos ) - rewrite(tree, to = true) - } else /* if (scrutineeSubSelector && inMatch) */ rewrite(tree, to = true) + rewrite(select, to = true) + } else /* if (scrutineeSubSelector && inMatch) */ rewrite(select, to = true) } /** Rewrites cases with unrelated types */ - def handleFalseUnrelated(tree: Select, scrutinee: Type, selector: Type, inMatch: Boolean) = + def handleFalseUnrelated(select: Select, scrutinee: Type, selector: Type, inMatch: Boolean) = if (inMatch) { ctx.error( s"will never match since `${selector.show}` is not a subclass of `${scrutinee.show}`", - Position(tree.pos.start - 5, tree.pos.end - 5) + Position(select.pos.start - 5, select.pos.end - 5) ) - rewrite(tree, to = false) + rewrite(select, to = false) } else { ctx.warning( s"will always yield false since `${scrutinee.show}` is not a subclass of `${selector.show}`", - tree.pos + select.pos ) - rewrite(tree, to = false) + rewrite(select, to = false) } /** Rewrites the select to a boolean if `to` is false or if the qualifier @@ -106,25 +107,30 @@ class IsInstanceOfEvaluator extends MiniPhaseTransform { thisTransformer => val scrutinee = erasure(s.qualifier.tpe.widen) val selector = erasure(tree.args.head.tpe.widen) - val scTrait = scrutinee.typeSymbol is Flags.Trait + val scTrait = scrutinee.typeSymbol is Trait val scClass = scrutinee.typeSymbol.isClass && - !(scrutinee.typeSymbol is Flags.Trait) && - !(scrutinee.typeSymbol is Flags.Module) + !(scrutinee.typeSymbol is Trait) && + !(scrutinee.typeSymbol is Module) - val scClassNonFinal = scClass && !scrutinee.typeSymbol.is(Flags.Final) - val scFinalClass = scClass && (scrutinee.typeSymbol is Flags.Final) + val scClassNonFinal = scClass && !(scrutinee.typeSymbol is Final) + val scFinalClass = scClass && (scrutinee.typeSymbol is Final) - val selTrait = selector.typeSymbol is Flags.Trait + val selTrait = selector.typeSymbol is Trait val selClass = selector.typeSymbol.isClass && - !(selector.typeSymbol is Flags.Trait) && - !(selector.typeSymbol is Flags.Module) + !(selector.typeSymbol is Trait) && + !(selector.typeSymbol is Module) - val selClassNonFinal = scClass && !(selector.typeSymbol is Flags.Final) - val selFinalClass = scClass && (selector.typeSymbol is Flags.Final) + val selClassNonFinal = scClass && !(selector.typeSymbol is Final) + val selFinalClass = scClass && (selector.typeSymbol is Final) // Cases --------------------------------- + val valueClassesOrAny = + ValueClasses.isDerivedValueClass(scrutinee.typeSymbol) || + ValueClasses.isDerivedValueClass(selector.typeSymbol) || + scrutinee == defn.ObjectType + val knownStatically = scFinalClass val falseIfUnrelated = @@ -137,13 +143,16 @@ class IsInstanceOfEvaluator extends MiniPhaseTransform { thisTransformer => (scTrait && selClassNonFinal) || (scTrait && selTrait) - val inMatch = s.qualifier.symbol is Flags.Case + val inMatch = s.qualifier.symbol is Case - if (knownStatically) + if (valueClassesOrAny) tree + else if (knownStatically) handleStaticallyKnown(s, scrutinee, selector, inMatch, tree.pos) else if (falseIfUnrelated && scrutinee <:< selector) + // scrutinee is a subtype of the selector, safe to rewrite rewrite(s, to = true) else if (falseIfUnrelated && !(selector <:< scrutinee)) + // selector and scrutinee are unrelated handleFalseUnrelated(s, scrutinee, selector, inMatch) else if (happens) tree else tree diff --git a/tests/pos-scala2/i1059.scala b/tests/disabled/pos-scala2/i1059.scala index cd23e1916..cd23e1916 100644 --- a/tests/pos-scala2/i1059.scala +++ b/tests/disabled/pos-scala2/i1059.scala diff --git a/tests/pos/t3480.scala b/tests/disabled/pos/t3480.scala index ba2e1a4b8..ba2e1a4b8 100644 --- a/tests/pos/t3480.scala +++ b/tests/disabled/pos/t3480.scala diff --git a/tests/neg/i1255.scala b/tests/neg/i1255.scala new file mode 100644 index 000000000..3bb7e8f25 --- /dev/null +++ b/tests/neg/i1255.scala @@ -0,0 +1,6 @@ +object Test { + def foo(x: Option[Int]) = x match { + case Some(_: Double) => true // error + case None => true + } +} diff --git a/tests/pos/t1168.scala b/tests/pos/t1168.scala index f43436812..08f1b5cd9 100644 --- a/tests/pos/t1168.scala +++ b/tests/pos/t1168.scala @@ -1,6 +1,6 @@ object Test extends App { - trait SpecialException {} + trait SpecialException extends Throwable {} try { throw new Exception diff --git a/tests/run/t6637.scala b/tests/run/t6637.scala index 7f9c3cd61..052e7f5d6 100644 --- a/tests/run/t6637.scala +++ b/tests/run/t6637.scala @@ -1,7 +1,6 @@ - object Test extends dotty.runtime.LegacyApp { try { - class A ; class B ; List().head.isInstanceOf[A with B] + List().head } catch { case _ :java.util.NoSuchElementException => println("ok") } |