diff options
author | odersky <odersky@gmail.com> | 2016-09-04 19:32:13 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-09-04 19:32:13 +0300 |
commit | a0e7adb070ee9c73c0cca081196198296cbd63ab (patch) | |
tree | 955c80e27562ed452f92226f534ead57089db812 /src | |
parent | 1650add0d7c1f3108fcacd15bb989ebd42234888 (diff) | |
parent | 2dfe4db8b3babefeba83eb30ffdc92a5d84665bb (diff) | |
download | dotty-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.scala | 3 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/OrderingConstraint.scala | 44 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/TyperState.scala | 34 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Inferencing.scala | 3 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Typer.scala | 6 |
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 |