aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorodersky <odersky@gmail.com>2016-09-04 19:32:13 +0300
committerGitHub <noreply@github.com>2016-09-04 19:32:13 +0300
commita0e7adb070ee9c73c0cca081196198296cbd63ab (patch)
tree955c80e27562ed452f92226f534ead57089db812 /src
parent1650add0d7c1f3108fcacd15bb989ebd42234888 (diff)
parent2dfe4db8b3babefeba83eb30ffdc92a5d84665bb (diff)
downloaddotty-a0e7adb070ee9c73c0cca081196198296cbd63ab.tar.gz
dotty-a0e7adb070ee9c73c0cca081196198296cbd63ab.tar.bz2
dotty-a0e7adb070ee9c73c0cca081196198296cbd63ab.zip
Merge pull request #1482 from dotty-staging/fix-asapplicable-safe
More tweaks to type inference
Diffstat (limited to 'src')
-rw-r--r--src/dotty/tools/dotc/core/Constraint.scala3
-rw-r--r--src/dotty/tools/dotc/core/OrderingConstraint.scala44
-rw-r--r--src/dotty/tools/dotc/core/TyperState.scala34
-rw-r--r--src/dotty/tools/dotc/typer/Inferencing.scala3
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala6
5 files changed, 65 insertions, 25 deletions
diff --git a/src/dotty/tools/dotc/core/Constraint.scala b/src/dotty/tools/dotc/core/Constraint.scala
index 436b035dc..99b4af0a9 100644
--- a/src/dotty/tools/dotc/core/Constraint.scala
+++ b/src/dotty/tools/dotc/core/Constraint.scala
@@ -143,6 +143,9 @@ abstract class Constraint extends Showable {
/** The uninstantiated typevars of this constraint */
def uninstVars: collection.Seq[TypeVar]
+ /** The weakest constraint that subsumes both this constraint and `other` */
+ def & (other: Constraint)(implicit ctx: Context): Constraint
+
/** Check that no constrained parameter contains itself as a bound */
def checkNonCyclic()(implicit ctx: Context): Unit
diff --git a/src/dotty/tools/dotc/core/OrderingConstraint.scala b/src/dotty/tools/dotc/core/OrderingConstraint.scala
index b0170b67c..e7e388be9 100644
--- a/src/dotty/tools/dotc/core/OrderingConstraint.scala
+++ b/src/dotty/tools/dotc/core/OrderingConstraint.scala
@@ -15,11 +15,13 @@ import annotation.tailrec
object OrderingConstraint {
+ type ArrayValuedMap[T] = SimpleMap[GenericType, Array[T]]
+
/** The type of `OrderingConstraint#boundsMap` */
- type ParamBounds = SimpleMap[GenericType, Array[Type]]
+ type ParamBounds = ArrayValuedMap[Type]
/** The type of `OrderingConstraint#lowerMap`, `OrderingConstraint#upperMap` */
- type ParamOrdering = SimpleMap[GenericType, Array[List[PolyParam]]]
+ type ParamOrdering = ArrayValuedMap[List[PolyParam]]
/** A new constraint with given maps */
private def newConstraint(boundsMap: ParamBounds, lowerMap: ParamOrdering, upperMap: ParamOrdering)(implicit ctx: Context) : OrderingConstraint = {
@@ -495,6 +497,44 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
}
}
+ def & (other: Constraint)(implicit ctx: Context) = {
+ def merge[T](m1: ArrayValuedMap[T], m2: ArrayValuedMap[T], join: (T, T) => T): ArrayValuedMap[T] = {
+ var merged = m1
+ def mergeArrays(xs1: Array[T], xs2: Array[T]) = {
+ val xs = xs1.clone
+ for (i <- xs.indices) xs(i) = join(xs1(i), xs2(i))
+ xs
+ }
+ m2.foreachBinding { (poly, xs2) =>
+ merged = merged.updated(poly,
+ if (m1.contains(poly)) mergeArrays(m1(poly), xs2) else xs2)
+ }
+ merged
+ }
+
+ def mergeParams(ps1: List[PolyParam], ps2: List[PolyParam]) =
+ (ps1 /: ps2)((ps1, p2) => if (ps1.contains(p2)) ps1 else p2 :: ps1)
+
+ def mergeEntries(e1: Type, e2: Type): Type = e1 match {
+ case e1: TypeBounds =>
+ e2 match {
+ case e2: TypeBounds => e1 & e2
+ case _ if e1 contains e2 => e2
+ case _ => mergeError
+ }
+ case _ if e1 eq e2 => e1
+ case _ => mergeError
+ }
+
+ def mergeError = throw new AssertionError(i"cannot merge $this with $other")
+
+ val that = other.asInstanceOf[OrderingConstraint]
+ new OrderingConstraint(
+ merge(this.boundsMap, that.boundsMap, mergeEntries),
+ merge(this.lowerMap, that.lowerMap, mergeParams),
+ merge(this.upperMap, that.upperMap, mergeParams))
+ }
+
override def checkClosed()(implicit ctx: Context): Unit = {
def isFreePolyParam(tp: Type) = tp match {
case PolyParam(binder: GenericType, _) => !contains(binder)
diff --git a/src/dotty/tools/dotc/core/TyperState.scala b/src/dotty/tools/dotc/core/TyperState.scala
index 69c35faf5..7b8867ccc 100644
--- a/src/dotty/tools/dotc/core/TyperState.scala
+++ b/src/dotty/tools/dotc/core/TyperState.scala
@@ -59,18 +59,10 @@ class TyperState(r: Reporter) extends DotClass with Showable {
/** Commit state so that it gets propagated to enclosing context */
def commit()(implicit ctx: Context): Unit = unsupported("commit")
- /** The typer state has already been committed */
- def isCommitted: Boolean = false
-
- /** Optionally, if this is a mutable typerstate, it's creator state */
- def parent: Option[TyperState] = None
-
/** The closest ancestor of this typer state (including possibly this typer state itself)
* which is not yet committed, or which does not have a parent.
*/
- def uncommittedAncestor: TyperState =
- if (!isCommitted || !parent.isDefined) this
- else parent.get.uncommittedAncestor
+ def uncommittedAncestor: TyperState = this
/** Make type variable instances permanent by assigning to `inst` field if
* type variable instantiation cannot be retracted anymore. Then, remove
@@ -96,7 +88,8 @@ extends TyperState(r) {
override def reporter = myReporter
- private var myConstraint: Constraint = previous.constraint
+ private val previousConstraint = previous.constraint
+ private var myConstraint: Constraint = previousConstraint
override def constraint = myConstraint
override def constraint_=(c: Constraint)(implicit ctx: Context) = {
@@ -109,7 +102,6 @@ extends TyperState(r) {
override def ephemeral = myEphemeral
override def ephemeral_=(x: Boolean): Unit = { myEphemeral = x }
-
override def fresh(isCommittable: Boolean): TyperState =
new MutableTyperState(this, new StoreReporter(reporter), isCommittable)
@@ -120,6 +112,11 @@ extends TyperState(r) {
isCommittable &&
(!previous.isInstanceOf[MutableTyperState] || previous.isGlobalCommittable)
+ private var isCommitted = false
+
+ override def uncommittedAncestor: TyperState =
+ if (isCommitted) previous.uncommittedAncestor else this
+
/** Commit typer state so that its information is copied into current typer state
* In addition (1) the owning state of undetermined or temporarily instantiated
* type variables changes from this typer state to the current one. (2) Variables
@@ -128,25 +125,20 @@ extends TyperState(r) {
*/
override def commit()(implicit ctx: Context) = {
val targetState = ctx.typerState
- assert(targetState eq previous)
assert(isCommittable)
- targetState.constraint = constraint
+ targetState.constraint =
+ if (targetState.constraint eq previousConstraint) constraint
+ else targetState.constraint & constraint
constraint foreachTypeVar { tvar =>
if (tvar.owningState eq this)
tvar.owningState = targetState
}
- targetState.ephemeral = ephemeral
+ targetState.ephemeral |= ephemeral
targetState.gc()
reporter.flush()
- myIsCommitted = true
+ isCommitted = true
}
- private var myIsCommitted = false
-
- override def isCommitted: Boolean = myIsCommitted
-
- override def parent = Some(previous)
-
override def gc()(implicit ctx: Context): Unit = {
val toCollect = new mutable.ListBuffer[GenericType]
constraint foreachTypeVar { tvar =>
diff --git a/src/dotty/tools/dotc/typer/Inferencing.scala b/src/dotty/tools/dotc/typer/Inferencing.scala
index 7c61f8c23..719e8d7fc 100644
--- a/src/dotty/tools/dotc/typer/Inferencing.scala
+++ b/src/dotty/tools/dotc/typer/Inferencing.scala
@@ -78,7 +78,8 @@ object Inferencing {
def apply(x: Boolean, tp: Type): Boolean = tp.dealias match {
case _: WildcardType | _: ProtoType =>
false
- case tvar: TypeVar if !tvar.isInstantiated =>
+ case tvar: TypeVar
+ if !tvar.isInstantiated && ctx.typerState.constraint.contains(tvar) =>
force.appliesTo(tvar) && {
val direction = instDirection(tvar.origin)
if (direction != 0) {
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index f0086b0ab..fdcfe347b 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -895,7 +895,11 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
}
def typedSeqLiteral(tree: untpd.SeqLiteral, pt: Type)(implicit ctx: Context): SeqLiteral = track("typedSeqLiteral") {
- val proto1 = pt.elemType orElse WildcardType
+ val proto1 = pt.elemType match {
+ case NoType => WildcardType
+ case bounds: TypeBounds => WildcardType(bounds)
+ case elemtp => elemtp
+ }
val elems1 = tree.elems mapconserve (typed(_, proto1))
val proto2 = // the computed type of the `elemtpt` field
if (!tree.elemtpt.isEmpty) WildcardType