Skip to content

Commit c469970

Browse files
committed
wip
1 parent d1fa5d7 commit c469970

9 files changed

+199
-49
lines changed

compiler/src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -851,6 +851,10 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
851851
/** tree.asInstanceOf[`tp`] */
852852
def asInstance(tp: Type)(implicit ctx: Context): Tree = {
853853
assert(tp.isValueType, i"bad cast: $tree.asInstanceOf[$tp]")
854+
// println(i"asInstance : $tp")
855+
// val ex = new RuntimeException
856+
// ex.printStackTrace(java.lang.System.out)
857+
// java.lang.System.out.flush()
854858
tree.select(defn.Any_asInstanceOf).appliedToType(tp)
855859
}
856860

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

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -713,15 +713,18 @@ object Contexts {
713713
def addBound(sym: Symbol, bound: Type, isUpper: Boolean)(implicit ctx: Context): Boolean
714714
def bounds(sym: Symbol)(implicit ctx: Context): TypeBounds
715715
def contains(sym: Symbol)(implicit ctx: Context): Boolean
716+
def approximation(sym: Symbol, fromBelow: Boolean)(implicit ctx: Context): Type
716717
def debugBoundsDescription(implicit ctx: Context): String
717718
def fresh: GADTMap
719+
def restore(other: GADTMap): Unit
720+
def isEmpty: Boolean
718721
}
719722

720723
final class SmartGADTMap private (
721-
private[this] var myConstraint: Constraint,
722-
private[this] var mapping: SimpleIdentityMap[Symbol, TypeVar],
723-
private[this] var reverseMapping: SimpleIdentityMap[TypeParamRef, Symbol],
724-
private[this] var boundCache: SimpleIdentityMap[Symbol, TypeBounds]
724+
private var myConstraint: Constraint,
725+
private var mapping: SimpleIdentityMap[Symbol, TypeVar],
726+
private var reverseMapping: SimpleIdentityMap[TypeParamRef, Symbol],
727+
private var boundCache: SimpleIdentityMap[Symbol, TypeBounds]
725728
) extends GADTMap with ConstraintHandling[Context] {
726729
import dotty.tools.dotc.config.Printers.{gadts, gadtsConstr}
727730

@@ -822,13 +825,30 @@ object Contexts {
822825

823826
override def contains(sym: Symbol)(implicit ctx: Context): Boolean = mapping(sym) ne null
824827

828+
override def approximation(sym: Symbol, fromBelow: Boolean)(implicit ctx: Context): Type = {
829+
val res = approximation(tvar(sym).origin, fromBelow = fromBelow)
830+
gadts.println(i"approximating $sym ~> $res")
831+
res
832+
}
833+
825834
override def fresh: GADTMap = new SmartGADTMap(
826835
myConstraint,
827836
mapping,
828837
reverseMapping,
829838
boundCache
830839
)
831840

841+
def restore(other: GADTMap): Unit = other match {
842+
case other: SmartGADTMap =>
843+
this.myConstraint = other.myConstraint
844+
this.mapping = other.mapping
845+
this.reverseMapping = other.reverseMapping
846+
this.boundCache = other.boundCache
847+
case _ => ;
848+
}
849+
850+
override def isEmpty: Boolean = mapping.size == 0
851+
832852
// ---- Private ----------------------------------------------------------
833853

834854
private[this] def tvar(sym: Symbol)(implicit ctx: Context): TypeVar = {
@@ -905,7 +925,12 @@ object Contexts {
905925
override def addBound(sym: Symbol, bound: Type, isUpper: Boolean)(implicit ctx: Context): Boolean = unsupported("EmptyGADTMap.addBound")
906926
override def bounds(sym: Symbol)(implicit ctx: Context): TypeBounds = null
907927
override def contains(sym: Symbol)(implicit ctx: Context) = false
928+
override def approximation(sym: Symbol, fromBelow: Boolean)(implicit ctx: Context): Type = unsupported("EmptyGADTMap.approximation")
908929
override def debugBoundsDescription(implicit ctx: Context): String = "EmptyGADTMap"
909930
override def fresh = new SmartGADTMap
931+
override def restore(other: GADTMap): Unit = {
932+
if (!other.isEmpty) sys.error("cannot restore a non-empty GADTMap")
933+
}
934+
override def isEmpty: Boolean = true
910935
}
911936
}

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ object Implicits {
305305
* @param level The level where the reference was found
306306
* @param tstate The typer state to be committed if this alternative is chosen
307307
*/
308-
case class SearchSuccess(tree: Tree, ref: TermRef, level: Int)(val tstate: TyperState) extends SearchResult with Showable
308+
case class SearchSuccess(tree: Tree, ref: TermRef, level: Int)(val tstate: TyperState, val gstate: GADTMap) extends SearchResult with Showable
309309

310310
/** A failed search */
311311
case class SearchFailure(tree: Tree) extends SearchResult {
@@ -867,6 +867,7 @@ trait Implicits { self: Typer =>
867867
result match {
868868
case result: SearchSuccess =>
869869
result.tstate.commit()
870+
ctx.gadt.restore(result.gstate)
870871
implicits.println(i"success: $result")
871872
implicits.println(i"committing ${result.tstate.constraint} yielding ${ctx.typerState.constraint} in ${ctx.typerState}")
872873
result
@@ -970,7 +971,7 @@ trait Implicits { self: Typer =>
970971
new ShadowedImplicit(ref, methPart(shadowing).tpe, pt, argument)))
971972
}
972973
else
973-
SearchSuccess(generated1, ref, cand.level)(ctx.typerState)
974+
SearchSuccess(generated1, ref, cand.level)(ctx.typerState, ctx.gadt)
974975
}}
975976

976977
/** Try to type-check implicit reference, after checking that this is not
@@ -981,7 +982,7 @@ trait Implicits { self: Typer =>
981982
if (history eq ctx.searchHistory)
982983
SearchFailure(new DivergingImplicit(cand.ref, pt, argument))
983984
else
984-
typedImplicit(cand, contextual)(nestedContext().setNewTyperState().setSearchHistory(history))
985+
typedImplicit(cand, contextual)(nestedContext().setNewTyperState().setFreshGADTBounds.setSearchHistory(history))
985986
}
986987

987988
/** Search a list of eligible implicit references */
@@ -1094,7 +1095,9 @@ trait Implicits { self: Typer =>
10941095
result match {
10951096
case _: SearchFailure =>
10961097
SearchSuccess(ref(defn.Not_value), defn.Not_value.termRef, 0)(
1097-
ctx.typerState.fresh().setCommittable(true))
1098+
ctx.typerState.fresh().setCommittable(true),
1099+
ctx.gadt
1100+
)
10981101
case _: SearchSuccess =>
10991102
NoMatchingImplicitsFailure
11001103
}
@@ -1157,6 +1160,7 @@ trait Implicits { self: Typer =>
11571160
val eligible =
11581161
if (contextual) ctx.implicits.eligible(wildProto)
11591162
else implicitScope(wildProto).eligible
1163+
// println(i"eligible: ${eligible.map(_.ref.show)}")
11601164
searchImplicits(eligible, contextual) match {
11611165
case result: SearchSuccess =>
11621166
if (contextual && ctx.mode.is(Mode.InlineableBody))

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

Lines changed: 78 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package dotty.tools
22
package dotc
33
package typer
44

5-
import dotty.tools.dotc.ast.{Trees, untpd, tpd, TreeTypeMap}
5+
import ast._
66
import Trees._
77
import core._
88
import Flags._
@@ -14,16 +14,16 @@ import StdNames._
1414
import transform.SymUtils._
1515
import Contexts.Context
1616
import Names.{Name, TermName}
17-
import NameKinds.{InlineAccessorName, InlineScrutineeName, InlineBinderName}
17+
import NameKinds.{InlineAccessorName, InlineBinderName, InlineScrutineeName}
1818
import ProtoTypes.selectionProto
1919
import SymDenotations.SymDenotation
2020
import Inferencing.fullyDefinedType
2121
import config.Printers.inlining
2222
import ErrorReporting.errorTree
23+
2324
import collection.mutable
2425
import reporting.trace
2526
import util.Positions.Position
26-
import ast.TreeInfo
2727

2828
object Inliner {
2929
import tpd._
@@ -692,7 +692,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
692692
bindingsBuf += ValDef(sym, constToLiteral(rhs))
693693
}
694694

695-
def searchImplicit(sym: TermSymbol, tpt: Tree) = {
695+
def searchImplicit(sym: TermSymbol, tpt: Tree)(implicit ctx: Context) = {
696696
val evTyper = new Typer
697697
val evidence = evTyper.inferImplicitArg(tpt.tpe, tpt.pos)(ctx.fresh.setTyper(evTyper))
698698
evidence.tpe match {
@@ -707,48 +707,70 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
707707
}
708708
}
709709

710-
pat match {
711-
case Typed(pat1, tpt) =>
712-
val getBoundVars = new TreeAccumulator[List[TypeSymbol]] {
713-
def apply(syms: List[TypeSymbol], t: Tree)(implicit ctx: Context) = {
714-
val syms1 = t match {
715-
case t: Bind if t.symbol.isType && t.name != tpnme.WILDCARD =>
716-
t.symbol.asType :: syms
717-
case _ =>
718-
syms
719-
}
720-
foldOver(syms1, t)
710+
import java.{lang => jl}
711+
def getBoundVarsMap(pat: Tree, tpt: Tree) = {
712+
// UnApply nodes with pattern bound variables translate to something like this
713+
// UnApply[t @ t](pats)(implicits): T[t]
714+
// Need to traverse any binds in type arguments of the UnAppyl to get the set of
715+
// all instantiable type variables. Test case is pos/inline-caseclass.scala.
716+
val allTpts = tpt :: (pat match {
717+
case UnApply(TypeApply(_, tpts), _, _) => tpts
718+
case _ => Nil
719+
})
720+
721+
val getBinds = new TreeAccumulator[Set[TypeSymbol]] {
722+
def apply(syms: Set[TypeSymbol], t: tpd.Tree)(implicit ctx: Context): Set[TypeSymbol] = {
723+
val syms1 = t match {
724+
case t: Bind if t.symbol.isType && t.name != tpnme.WILDCARD =>
725+
syms + t.symbol.asType
726+
case _ => syms
721727
}
728+
foldOver(syms1, t)
722729
}
723-
var boundVars = getBoundVars(Nil, tpt)
724-
// UnApply nodes with pattern bound variables translate to something like this
725-
// UnApply[t @ t](pats)(implicits): T[t]
726-
// Need to traverse any binds in type arguments of the UnAppyl to get the set of
727-
// all instantiable type variables. Test case is pos/inline-caseclass.scala.
728-
pat1 match {
729-
case UnApply(TypeApply(_, tpts), _, _) =>
730-
for (tpt <- tpts) boundVars = getBoundVars(boundVars, tpt)
731-
case _ =>
732-
}
733-
for (bv <- boundVars) {
734-
val TypeBounds(lo, hi) = bv.info.bounds
735-
ctx.gadt.addBound(bv, lo, isUpper = false)
736-
ctx.gadt.addBound(bv, hi, isUpper = true)
730+
}
731+
val binds = allTpts.foldLeft[Set[TypeSymbol]](Set.empty)(getBinds.apply(_, _))
732+
val getBoundVars = new TypeAccumulator[util.SimpleIdentityMap[TypeSymbol, jl.Boolean]] {
733+
def apply(syms: util.SimpleIdentityMap[TypeSymbol, jl.Boolean], t: Type) = {
734+
val syms1 = t match {
735+
case tr: TypeRef if tr.symbol.is(Case) && binds.contains(tr.symbol.asType) =>
736+
syms.updated[jl.Boolean](tr.typeSymbol.asType, variance >= 0)
737+
case _ =>
738+
syms
739+
}
740+
foldOver(syms1, t)
737741
}
742+
}
743+
getBoundVars(util.SimpleIdentityMap.Empty, tpt.tpe)
744+
}
745+
746+
def registerAsGadtSyms(map: util.SimpleIdentityMap[TypeSymbol, jl.Boolean])(implicit ctx: Context): Unit =
747+
map.foreachBinding { case (sym, _) =>
748+
val TypeBounds(lo, hi) = sym.info.bounds
749+
ctx.gadt.addBound(sym, lo, isUpper = false)
750+
ctx.gadt.addBound(sym, hi, isUpper = true)
751+
}
752+
753+
def addTypeBindings(map: util.SimpleIdentityMap[TypeSymbol, jl.Boolean])(implicit ctx: Context): Unit =
754+
map.foreachBinding { case (sym, fromBelow) =>
755+
sym.info = TypeAlias(ctx.gadt.approximation(sym, fromBelow = fromBelow))
756+
bindingsBuf += TypeDef(sym)
757+
}
758+
759+
pat match {
760+
case Typed(pat1, tpt) =>
761+
val boundVarsMap = getBoundVarsMap(pat1, tpt)
762+
registerAsGadtSyms(boundVarsMap)
738763
scrut <:< tpt.tpe && {
739-
for (bv <- boundVars) {
740-
bv.info = TypeAlias(ctx.gadt.bounds(bv).lo)
741-
// FIXME: This is very crude. We should approximate with lower or higher bound depending
742-
// on variance, and we should also take care of recursive bounds. Basically what
743-
// ConstraintHandler#approximation does. However, this only works for constrained paramrefs
744-
// not GADT-bound variables. Hopefully we will get some way to improve this when we
745-
// re-implement GADTs in terms of constraints.
746-
bindingsBuf += TypeDef(bv)
747-
}
764+
addTypeBindings(boundVarsMap)
748765
reducePattern(bindingsBuf, scrut, pat1)
749766
}
750767
case pat @ Bind(name: TermName, Typed(_, tpt)) if isImplicit =>
751-
searchImplicit(pat.symbol.asTerm, tpt)
768+
val boundVarsMap = getBoundVarsMap(tpt, tpt)
769+
registerAsGadtSyms(boundVarsMap)
770+
searchImplicit(pat.symbol.asTerm, tpt) && {
771+
addTypeBindings(boundVarsMap)
772+
true
773+
}
752774
case pat @ Bind(name: TermName, body) =>
753775
reducePattern(bindingsBuf, scrut, body) && {
754776
if (name != nme.WILDCARD) newBinding(pat.symbol.asTerm, ref(scrut))
@@ -906,7 +928,23 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
906928
matchBindingsBuf += binding
907929
rhsCtx.enter(binding.symbol)
908930
}
909-
typedExpr(rhs, pt)(rhsCtx)
931+
val rrhs = rhs match {
932+
case Block(stats, t) if t.pos.isSynthetic =>
933+
t match {
934+
case Typed(expr, _) =>
935+
untpd.Block(stats, expr)
936+
case TypeApply(Select(expr, n), _) if n == defn.Any_asInstanceOf.name =>
937+
untpd.Block(stats, expr)
938+
case _ =>
939+
rhs
940+
}
941+
case _ => rhs
942+
}
943+
// println(i"""pre=$rhs
944+
// |post=$rrhs""".stripMargin)
945+
// put caseBindings in a block to let typedExpr see them
946+
val Block(_, res) = typedExpr(untpd.Block(caseBindings, rrhs), pt)(rhsCtx)
947+
res
910948
case None =>
911949
def guardStr(guard: untpd.Tree) = if (guard.isEmpty) "" else i" if $guard"
912950
def patStr(cdef: untpd.CaseDef) = i"case ${cdef.pat}${guardStr(cdef.guard)}"

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,8 @@ object ProtoTypes {
563563
*/
564564
private def wildApprox(tp: Type, theMap: WildApproxMap, seen: Set[TypeParamRef])(implicit ctx: Context): Type = tp match {
565565
case tp: NamedType => // default case, inlined for speed
566-
if (tp.symbol.isStatic || (tp.prefix `eq` NoPrefix)) tp
566+
if (tp.isInstanceOf[TypeRef] && tp.symbol.is(Flags.Case) && !tp.symbol.isClass) WildcardType(tp.underlying.bounds)
567+
else if (tp.symbol.isStatic || (tp.prefix `eq` NoPrefix)) tp
567568
else tp.derivedSelect(wildApprox(tp.prefix, theMap, seen))
568569
case tp @ AppliedType(tycon, args) =>
569570
wildApprox(tycon, theMap, seen) match {
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
object `implicit-match-ambiguous-bind` {
2+
case class Box[T](value: T)
3+
implicit val ibox: Box[Int] = Box(0)
4+
implicit val sbox: Box[String] = Box("")
5+
inline def unbox = implicit match {
6+
case b: Box[t] => b.value // error
7+
}
8+
val unboxed = unbox
9+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
object `implicit-match-and-inline-match` {
2+
case class Box[T](value: T)
3+
implicit val ibox: Box[Int] = Box(0)
4+
5+
// this version does not currently work:
6+
//
7+
// object a {
8+
// import scala.typelevel.erasedValue
9+
// inline def isTheBoxInScopeAnInt = implicit match {
10+
// case _: Box[t] => inline (??? : t) match {
11+
// case _: Int => true
12+
// // case _ => false
13+
// }
14+
// }
15+
// val wellIsIt = isTheBoxInScopeAnInt
16+
// }
17+
18+
object b {
19+
inline def isTheBoxInScopeAnInt = implicit match {
20+
case _: Box[t] => inline 0 match {
21+
case _: t => true
22+
// case _ => false
23+
}
24+
}
25+
val wellIsIt = isTheBoxInScopeAnInt
26+
}
27+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
object `implicit-match-trivial` {
2+
object invariant {
3+
case class Box[T](value: T)
4+
implicit val box: Box[Int] = Box(0)
5+
inline def unbox <: Any = implicit match {
6+
case b: Box[t] => b.value : t
7+
}
8+
//val i: Int = unbox
9+
val i = unbox
10+
val i2: Int = i
11+
}
12+
13+
object covariant {
14+
case class Box[+T](value: T)
15+
implicit val box: Box[Int] = Box(0)
16+
inline def unbox <: Any = implicit match {
17+
case b: Box[t] => b.value
18+
}
19+
//val i: Int = unbox
20+
val i = unbox
21+
val i2: Int = i
22+
}
23+
24+
object contravariant {
25+
case class Eater[-T](eat: T => Unit)
26+
implicit val eater: Eater[Int] = Eater { i => ; }
27+
inline def uneater <: Nothing => Unit = implicit match {
28+
case b: Eater[t] => b.eat : (t => Unit)
29+
}
30+
// val eat: Int => Unit = uneater
31+
val eat = uneater
32+
val eat2: Int => Unit = eat
33+
}
34+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
object O {
2+
case class Box[+T](value: T)
3+
inline def specialize[T](box: Box[T]) <: Box[T] = inline box match {
4+
case box: Box[t] => box
5+
}
6+
7+
val ibox/*: Box[Int]*/ = specialize[Any](Box(0))
8+
}

0 commit comments

Comments
 (0)