From 0db8ad3fac21398f5ec0bd06aca5bf7500c351ed Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Wed, 17 Mar 2021 10:33:36 +0100 Subject: [PATCH 1/2] Fix #9166: Harden check for values in patterns based on class inheritance info --- .../src/dotty/tools/dotc/typer/Typer.scala | 23 +++++++++++++++---- tests/neg/i9166.scala | 6 +++++ 2 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 tests/neg/i9166.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 85780105840c..07d584872380 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -3808,10 +3808,25 @@ class Typer extends Namer mapOver(tp) } - if tree.symbol.isOneOf(Module | Enum) - && !(tree.tpe frozen_<:< pt) // fast track - && !(tree.tpe frozen_<:< approx(pt)) - then + val sym = tree.tpe.widen.classSymbol + + // Is it certain that a value of `tree.tpe` is never a subtype of `pt`? + // It is true if either + // - the class of `tree.tpe` and class of `pt` cannot have common subclass, or + // - `tree` is an object or enum value, which cannot possibly be a subtype of `pt` + val isDefiniteNotSubtype = { + val clsA = tree.tpe.widenDealias.classSymbol + val clsB = pt.dealias.classSymbol + clsA.exists && clsB.exists + && clsA != defn.NullClass + && (!clsA.isNumericValueClass && !clsB.isNumericValueClass) // approximation for numeric conversion and boxing + && !clsA.asClass.mayHaveCommonChild(clsB.asClass) + || tree.symbol.isOneOf(Module | Enum) + && !(tree.tpe frozen_<:< pt) // fast track + && !(tree.tpe frozen_<:< approx(pt)) + } + + if isDefiniteNotSubtype then // We could check whether `equals` is overriden. // Reasons for not doing so: // - it complicates the protocol diff --git a/tests/neg/i9166.scala b/tests/neg/i9166.scala new file mode 100644 index 000000000000..7bbf2871eed3 --- /dev/null +++ b/tests/neg/i9166.scala @@ -0,0 +1,6 @@ +object UnitTest extends App { + def foo(m: Unit) = m match { + case runtime.BoxedUnit.UNIT => println("ok") // error + } + foo(()) +} From 5dd58bfa711438a63cb4e8b282b9d2a9314352fa Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Wed, 17 Mar 2021 14:39:00 +0100 Subject: [PATCH 2/2] Remove unused variable --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 07d584872380..84c7def6cbdf 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -3808,8 +3808,6 @@ class Typer extends Namer mapOver(tp) } - val sym = tree.tpe.widen.classSymbol - // Is it certain that a value of `tree.tpe` is never a subtype of `pt`? // It is true if either // - the class of `tree.tpe` and class of `pt` cannot have common subclass, or