Skip to content

Commit eed1a73

Browse files
committed
wip
1 parent cb15213 commit eed1a73

9 files changed

+178
-18
lines changed

compiler/src/dotty/tools/dotc/core/TypeComparer.scala

+83
Original file line numberDiff line numberDiff line change
@@ -2130,6 +2130,89 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
21302130
true
21312131
}
21322132
}
2133+
2134+
def notIntersection(tp: Type, pt: Type): Boolean =
2135+
trace(i"notIntersection($tp, $pt)")
2136+
{
2137+
import typer.Inferencing._
2138+
2139+
def incompatibleClasses: Boolean = {
2140+
import Flags._
2141+
val tpClassSym = tp.classSymbol
2142+
val ptClassSym = pt.classSymbol
2143+
println(i"tpClassSym=$tpClassSym, fin=${tpClassSym.is(Final)}")
2144+
println(i"ptClassSym=$ptClassSym, fin=${ptClassSym.is(Final)}")
2145+
tpClassSym.exists && ptClassSym.exists && {
2146+
println("here")
2147+
if (tpClassSym.is(Final)) !tpClassSym.derivesFrom(ptClassSym)
2148+
else if (ptClassSym.is(Final)) !ptClassSym.derivesFrom(tpClassSym)
2149+
else if (!tpClassSym.is(Flags.Trait) && !ptClassSym.is(Flags.Trait))
2150+
!(tpClassSym.derivesFrom(ptClassSym) || ptClassSym.derivesFrom(tpClassSym))
2151+
else false
2152+
}
2153+
}
2154+
2155+
def loop(tp: Type): Boolean =
2156+
trace.force(i"loop($tp) // ${tp.toString}")
2157+
{
2158+
if (constrainPatternType(pt, tp)) true
2159+
else if (incompatibleClasses) {
2160+
// println("incompatible classes")
2161+
false
2162+
}
2163+
else tp match {
2164+
case _: ConstantType =>
2165+
// constants cannot possibly intersect with types that aren't their supertypes
2166+
false
2167+
case tp: SingletonType => loop(tp.underlying)
2168+
case tp: TypeRef if tp.symbol.isClass => loop(tp.firstParent)
2169+
case tp @ AppliedType(tycon: TypeRef, _) if tycon.symbol.isClass =>
2170+
val ptClassSym = pt.classSymbol
2171+
def firstParentSharedWithPt(tp: Type, tpClassSym: ClassSymbol): Symbol =
2172+
trace.force(i"f($tp)")
2173+
{
2174+
var parents = tpClassSym.info.parents
2175+
// println(i"parents of $tpClassSym = $parents%, %")
2176+
parents match {
2177+
case first :: rest =>
2178+
if (first.classSymbol == defn.ObjectClass) parents = rest
2179+
case _ => ;
2180+
}
2181+
parents match {
2182+
case first :: _ =>
2183+
val firstClassSym = first.classSymbol.asClass
2184+
val res = if (ptClassSym.derivesFrom(firstClassSym)) firstClassSym
2185+
else firstParentSharedWithPt(first, firstClassSym)
2186+
res
2187+
case _ => NoSymbol
2188+
}
2189+
}
2190+
val sym = firstParentSharedWithPt(tycon, tycon.symbol.asClass)
2191+
// println(i"sym=$sym ; tyconsym=${tycon.symbol}")
2192+
if (!sym.exists) true
2193+
else !(sym == tycon.symbol) && loop(tp.baseType(sym))
2194+
case tp: TypeProxy =>
2195+
loop(tp.superType)
2196+
case _ => false
2197+
}
2198+
}
2199+
2200+
pt match {
2201+
case AndType(pt1, pt2) =>
2202+
notIntersection(tp, pt1) && notIntersection(tp, pt2)
2203+
case OrType(pt1, pt2) =>
2204+
either(notIntersection(tp, pt1), notIntersection(tp, pt2))
2205+
case _ =>
2206+
tp match {
2207+
case OrType(tp1, tp2) =>
2208+
either(notIntersection(tp1, pt), notIntersection(tp2, pt))
2209+
case AndType(tp1, tp2) =>
2210+
notIntersection(tp1, pt) && notIntersection(tp2, pt)
2211+
case _ =>
2212+
loop(tp)
2213+
}
2214+
}
2215+
}
21332216
}
21342217

21352218
object TypeComparer {

compiler/src/dotty/tools/dotc/reporting/trace.scala

+2-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ abstract class TraceSyntax {
9595

9696
def doApply[T](leading: => String, trailing: Any => String, log: String => Unit)(op: => T)(implicit ctx: Context): T =
9797
if (ctx.mode.is(Mode.Printing)) op
98-
else {
98+
else
99+
{
99100
var finalized = false
100101
def finalize(result: Any, note: String) =
101102
if (!finalized) {

compiler/src/dotty/tools/dotc/typer/Applications.scala

+16-13
Original file line numberDiff line numberDiff line change
@@ -1090,12 +1090,13 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
10901090
* - If a type proxy P is not a reference to a class, P's supertype is in G
10911091
*/
10921092
def isSubTypeOfParent(subtp: Type, tp: Type)(implicit ctx: Context): Boolean =
1093-
if (constrainPatternType(subtp, tp)) true
1094-
else tp match {
1095-
case tp: TypeRef if tp.symbol.isClass => isSubTypeOfParent(subtp, tp.firstParent)
1096-
case tp: TypeProxy => isSubTypeOfParent(subtp, tp.superType)
1097-
case _ => false
1098-
}
1093+
ctx.typeComparer.notIntersection(tp, subtp)
1094+
// if (constrainPatternType(subtp, tp, termPattern = true)) true
1095+
// else tp match {
1096+
// case tp: TypeRef if tp.symbol.isClass => isSubTypeOfParent(subtp, tp.firstParent)
1097+
// case tp: TypeProxy => isSubTypeOfParent(subtp, tp.superType)
1098+
// case _ => false
1099+
// }
10991100

11001101
unapplyFn.tpe.widen match {
11011102
case mt: MethodType if mt.paramInfos.length == 1 =>
@@ -1106,17 +1107,19 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
11061107
unapp.println(i"case 1 $unapplyArgType ${ctx.typerState.constraint}")
11071108
fullyDefinedType(unapplyArgType, "pattern selector", tree.span)
11081109
selType
1109-
} else if (isSubTypeOfParent(unapplyArgType, selType)(ctx.addMode(Mode.GADTflexible))) {
1110+
} else {
1111+
isSubTypeOfParent(unapplyArgType, selType)(ctx.addMode(Mode.GADTflexible))
11101112
val patternBound = maximizeType(unapplyArgType, tree.span, fromScala2x)
11111113
if (patternBound.nonEmpty) unapplyFn = addBinders(unapplyFn, patternBound)
11121114
unapp.println(i"case 2 $unapplyArgType ${ctx.typerState.constraint}")
11131115
unapplyArgType
1114-
} else {
1115-
unapp.println("Neither sub nor super")
1116-
unapp.println(TypeComparer.explained(implicit ctx => unapplyArgType <:< selType))
1117-
errorType(
1118-
ex"Pattern type $unapplyArgType is neither a subtype nor a supertype of selector type $selType",
1119-
tree.sourcePos)
1116+
// } else {
1117+
// unapp.println("Neither sub nor super")
1118+
// unapp.println(TypeComparer.explained(implicit ctx => unapplyArgType <:< selType))
1119+
// errorType(
1120+
// ex"Pattern type $unapplyArgType is neither a subtype nor a supertype of selector type $selType",
1121+
// tree.sourcePos)
1122+
// }
11201123
}
11211124
val dummyArg = dummyTreeOfType(ownType)
11221125
val unapplyApp = typedExpr(untpd.TypedSplice(Apply(unapplyFn, dummyArg :: Nil)))

compiler/src/dotty/tools/dotc/typer/Inferencing.scala

+4-3
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ object Inferencing {
208208

209209
val widePt = if (ctx.scala2Mode || refinementIsInvariant(tp)) pt else widenVariantParams(pt)
210210
val narrowTp = SkolemType(tp)
211-
trace(i"constraining pattern type $narrowTp <:< $widePt", gadts, res => s"$res\n${ctx.gadt.debugBoundsDescription}") {
211+
trace(i"constraining pattern type $narrowTp <:< $widePt", gadts, res => s"$res\ngadt = ${ctx.gadt.debugBoundsDescription}") {
212212
narrowTp <:< widePt
213213
}
214214
}
@@ -290,7 +290,7 @@ object Inferencing {
290290
* @return The list of type symbols that were created
291291
* to instantiate undetermined type variables that occur non-variantly
292292
*/
293-
def maximizeType(tp: Type, span: Span, fromScala2x: Boolean)(implicit ctx: Context): List[Symbol] = Stats.track("maximizeType") {
293+
def maximizeType(tp: Type, span: Span, fromScala2x: Boolean, f: TypeVar => TypeVar = null)(implicit ctx: Context): List[Symbol] = Stats.track("maximizeType") {
294294
val vs = variances(tp)
295295
val patternBound = new mutable.ListBuffer[Symbol]
296296
vs foreachBinding { (tvar, v) =>
@@ -304,7 +304,8 @@ object Inferencing {
304304
// since the symbols we're creating may have inter-dependencies in their bounds,
305305
// we add them to the GADT constraint later, simultaneously
306306
val wildCard = ctx.newPatternBoundSymbol(UniqueName.fresh(tvar.origin.paramName), bounds, span, addToGadt = false)
307-
tvar.instantiateWith(wildCard.typeRef)
307+
tvar.instantiateWith(wildCard.typeRef) // these ones are in GADT constraint
308+
if (f ne null) f(tvar).instantiateWith(wildCard.typeRef) // these ones are in the result type
308309
patternBound += wildCard
309310
}
310311
}

compiler/src/dotty/tools/dotc/typer/Typer.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -604,7 +604,7 @@ class Typer extends Namer
604604
def handlePattern: Tree = {
605605
val tpt1 = typedTpt
606606
if (!ctx.isAfterTyper && pt != defn.ImplicitScrutineeTypeRef)
607-
constrainPatternType(tpt1.tpe, pt)(ctx.addMode(Mode.GADTflexible))
607+
ctx.addMode(Mode.GADTflexible).typeComparer.notIntersection(pt, tpt1.tpe)
608608
// special case for an abstract type that comes with a class tag
609609
tryWithClassTag(ascription(tpt1, isWildcard = true), pt)
610610
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
object Test {
2+
trait Expr[+T]
3+
trait IntExpr extends Expr[Int]
4+
class Const[+T] extends Expr[T]
5+
final class Fin
6+
7+
def foo1[T](x: Unit | Const[T]): T = x match {
8+
case _: IntExpr => 0
9+
}
10+
11+
def bar1[T](x: Const[T]): T = x match {
12+
case _: (Unit | IntExpr) => 0
13+
}
14+
15+
def foo2[T](x: Fin | Const[T]): T = x match {
16+
case _: IntExpr => 0
17+
}
18+
19+
def bar2[T](x: Const[T]): T = x match {
20+
case _: (Fin | IntExpr) => 0
21+
}
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
object Test {
2+
trait Expr[T]
3+
trait IntExpr extends Expr[Int]
4+
class Const[T] extends Expr[T]
5+
final class Fin
6+
7+
def foo1[T](x: Unit | Const[T]): T = x match {
8+
case _: IntExpr => 0
9+
}
10+
11+
def bar1[T](x: Const[T]): T = x match {
12+
case _: (Unit | IntExpr) => 0
13+
}
14+
15+
def foo2[T](x: Fin | Const[T]): T = x match {
16+
case _: IntExpr => 0
17+
}
18+
19+
def bar2[T](x: Const[T]): T = x match {
20+
case _: (Fin | IntExpr) => 0
21+
}
22+
}

tests/pos/precise-pattern-type.scala

+16
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,20 @@ object `precise-pattern-type` {
1313
case Select(q) =>
1414
q.tpe.isType
1515
}
16+
17+
trait O {
18+
type ThisTree <: Tree[Type]
19+
val tree: ThisTree
20+
def test = tree match {
21+
case Select(q) => q.tpe.isType
22+
case tree1: Select[t] => (tree1 : Select[Type]).qual.tpe.isType
23+
}
24+
}
25+
26+
trait OO {
27+
type ThisTree[T >: Null] <: Tree[T]
28+
def foo(t: ThisTree[Type]) = t match {
29+
case Select(q) => q.tpe.isType
30+
}
31+
}
1632
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
object Test {
2+
enum Expr[+T] {
3+
case BoolLit(b: Boolean) extends Expr[Boolean]
4+
def eval: T = {
5+
def go[TT](self: this.type & Expr[TT]): TT = self match {
6+
case BoolLit(b) => b
7+
}
8+
9+
go(this)
10+
}
11+
}
12+
}

0 commit comments

Comments
 (0)