Skip to content

Commit a679471

Browse files
committed
wip
1 parent 0b2fa94 commit a679471

File tree

9 files changed

+178
-18
lines changed

9 files changed

+178
-18
lines changed

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

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2091,6 +2091,89 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] {
20912091
true
20922092
}
20932093
}
2094+
2095+
def notIntersection(tp: Type, pt: Type): Boolean =
2096+
trace(i"notIntersection($tp, $pt)")
2097+
{
2098+
import typer.Inferencing._
2099+
2100+
def incompatibleClasses: Boolean = {
2101+
import Flags._
2102+
val tpClassSym = tp.classSymbol
2103+
val ptClassSym = pt.classSymbol
2104+
println(i"tpClassSym=$tpClassSym, fin=${tpClassSym.is(Final)}")
2105+
println(i"ptClassSym=$ptClassSym, fin=${ptClassSym.is(Final)}")
2106+
tpClassSym.exists && ptClassSym.exists && {
2107+
println("here")
2108+
if (tpClassSym.is(Final)) !tpClassSym.derivesFrom(ptClassSym)
2109+
else if (ptClassSym.is(Final)) !ptClassSym.derivesFrom(tpClassSym)
2110+
else if (!tpClassSym.is(Flags.Trait) && !ptClassSym.is(Flags.Trait))
2111+
!(tpClassSym.derivesFrom(ptClassSym) || ptClassSym.derivesFrom(tpClassSym))
2112+
else false
2113+
}
2114+
}
2115+
2116+
def loop(tp: Type): Boolean =
2117+
trace.force(i"loop($tp) // ${tp.toString}")
2118+
{
2119+
if (constrainPatternType(pt, tp)) true
2120+
else if (incompatibleClasses) {
2121+
// println("incompatible classes")
2122+
false
2123+
}
2124+
else tp match {
2125+
case _: ConstantType =>
2126+
// constants cannot possibly intersect with types that aren't their supertypes
2127+
false
2128+
case tp: SingletonType => loop(tp.underlying)
2129+
case tp: TypeRef if tp.symbol.isClass => loop(tp.firstParent)
2130+
case tp @ AppliedType(tycon: TypeRef, _) if tycon.symbol.isClass =>
2131+
val ptClassSym = pt.classSymbol
2132+
def firstParentSharedWithPt(tp: Type, tpClassSym: ClassSymbol): Symbol =
2133+
trace.force(i"f($tp)")
2134+
{
2135+
var parents = tpClassSym.info.parents
2136+
// println(i"parents of $tpClassSym = $parents%, %")
2137+
parents match {
2138+
case first :: rest =>
2139+
if (first.classSymbol == defn.ObjectClass) parents = rest
2140+
case _ => ;
2141+
}
2142+
parents match {
2143+
case first :: _ =>
2144+
val firstClassSym = first.classSymbol.asClass
2145+
val res = if (ptClassSym.derivesFrom(firstClassSym)) firstClassSym
2146+
else firstParentSharedWithPt(first, firstClassSym)
2147+
res
2148+
case _ => NoSymbol
2149+
}
2150+
}
2151+
val sym = firstParentSharedWithPt(tycon, tycon.symbol.asClass)
2152+
// println(i"sym=$sym ; tyconsym=${tycon.symbol}")
2153+
if (!sym.exists) true
2154+
else !(sym == tycon.symbol) && loop(tp.baseType(sym))
2155+
case tp: TypeProxy =>
2156+
loop(tp.superType)
2157+
case _ => false
2158+
}
2159+
}
2160+
2161+
pt match {
2162+
case AndType(pt1, pt2) =>
2163+
notIntersection(tp, pt1) && notIntersection(tp, pt2)
2164+
case OrType(pt1, pt2) =>
2165+
either(notIntersection(tp, pt1), notIntersection(tp, pt2))
2166+
case _ =>
2167+
tp match {
2168+
case OrType(tp1, tp2) =>
2169+
either(notIntersection(tp1, pt), notIntersection(tp2, pt))
2170+
case AndType(tp1, tp2) =>
2171+
notIntersection(tp1, pt) && notIntersection(tp2, pt)
2172+
case _ =>
2173+
loop(tp)
2174+
}
2175+
}
2176+
}
20942177
}
20952178

20962179
object TypeComparer {

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

Lines changed: 2 additions & 1 deletion
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

Lines changed: 16 additions & 13 deletions
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

Lines changed: 4 additions & 3 deletions
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

Lines changed: 1 addition & 1 deletion
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
}
Lines changed: 22 additions & 0 deletions
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+
}
Lines changed: 22 additions & 0 deletions
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

Lines changed: 16 additions & 0 deletions
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
}
Lines changed: 12 additions & 0 deletions
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)