summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2016-05-27 17:58:17 +1000
committerJason Zaugg <jzaugg@gmail.com>2016-05-27 17:58:17 +1000
commit6b2037a2161de650fdbb010ba1da23d843247234 (patch)
treea6cffc611df52861a7917493c88a67d9e58ad72c /src
parent79ec0f31e611d37d5c50a966a4cd6bf24d96cda6 (diff)
parentbf478084fdf65c7bd156e2e6f04a96bfadf6986b (diff)
downloadscala-6b2037a2161de650fdbb010ba1da23d843247234.tar.gz
scala-6b2037a2161de650fdbb010ba1da23d843247234.tar.bz2
scala-6b2037a2161de650fdbb010ba1da23d843247234.zip
Merge pull request #5102 from milessabin/2.12.x
SI-2712 Add support for partial unification of type constructors
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala3
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala40
-rw-r--r--src/reflect/scala/reflect/internal/settings/MutableSettings.scala1
-rw-r--r--src/reflect/scala/reflect/runtime/Settings.scala1
4 files changed, 39 insertions, 6 deletions
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index c55693d60e..4d236b226d 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -30,7 +30,7 @@ trait ScalaSettings extends AbsScalaSettings
protected def defaultClasspath = sys.env.getOrElse("CLASSPATH", ".")
/** Enabled under -Xexperimental. */
- protected def experimentalSettings = List[BooleanSetting](YmethodInfer, overrideObjects, overrideVars)
+ protected def experimentalSettings = List[BooleanSetting](YpartialUnification)
/** Enabled under -Xfuture. */
protected def futureSettings = List[BooleanSetting]()
@@ -201,6 +201,7 @@ trait ScalaSettings extends AbsScalaSettings
val etaExpandKeepsStar = BooleanSetting ("-Yeta-expand-keeps-star", "Eta-expand varargs methods to T* rather than Seq[T]. This is a temporary option to ease transition.").withDeprecationMessage(removalIn212)
val inferByName = BooleanSetting ("-Yinfer-by-name", "Allow inference of by-name types. This is a temporary option to ease transition. See SI-7899.").withDeprecationMessage(removalIn212)
val YdisableFlatCpCaching = BooleanSetting ("-YdisableFlatCpCaching", "Do not cache flat classpath representation of classpath elements from jars across compiler instances.")
+ val YpartialUnification = BooleanSetting ("-Ypartial-unification", "Enable partial unification in type constructor inference")
val exposeEmptyPackage = BooleanSetting ("-Yexpose-empty-package", "Internal only: expose the empty package.").internalOnly()
val Ydelambdafy = ChoiceSetting ("-Ydelambdafy", "strategy", "Strategy used for translating lambdas into JVM code.", List("inline", "method"), "method")
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index de82a6a0b2..a649f6f926 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -3131,13 +3131,43 @@ trait Types
*/
def unifyFull(tpe: Type): Boolean = {
def unifySpecific(tp: Type) = {
- sameLength(typeArgs, tp.typeArgs) && {
- val lhs = if (isLowerBound) tp.typeArgs else typeArgs
- val rhs = if (isLowerBound) typeArgs else tp.typeArgs
+ val tpTypeArgs = tp.typeArgs
+ val arityDelta = compareLengths(typeArgs, tpTypeArgs)
+ if (arityDelta == 0) {
+ val lhs = if (isLowerBound) tpTypeArgs else typeArgs
+ val rhs = if (isLowerBound) typeArgs else tpTypeArgs
// This is a higher-kinded type var with same arity as tp.
// If so (see SI-7517), side effect: adds the type constructor itself as a bound.
- isSubArgs(lhs, rhs, params, AnyDepth) && { addBound(tp.typeConstructor); true }
- }
+ isSubArgs(lhs, rhs, params, AnyDepth) && {addBound(tp.typeConstructor); true}
+ } else if (settings.YpartialUnification && arityDelta < 0 && typeArgs.nonEmpty) {
+ // Simple algorithm as suggested by Paul Chiusano in the comments on SI-2712
+ //
+ // https://issues.scala-lang.org/browse/SI-2712?focusedCommentId=61270
+ //
+ // Treat the type constructor as curried and partially applied, we treat a prefix
+ // as constants and solve for the suffix. For the example in the ticket, unifying
+ // M[A] with Int => Int this unifies as,
+ //
+ // M[t] = [t][Int => t] --> abstract on the right to match the expected arity
+ // A = Int --> capture the remainder on the left
+ //
+ // A more "natural" unifier might be M[t] = [t][t => t]. There's lots of scope for
+ // experimenting with alternatives here.
+ val numCaptured = tpTypeArgs.length - typeArgs.length
+ val (captured, abstractedArgs) = tpTypeArgs.splitAt(numCaptured)
+
+ val (lhs, rhs) =
+ if (isLowerBound) (abstractedArgs, typeArgs)
+ else (typeArgs, abstractedArgs)
+
+ isSubArgs(lhs, rhs, params, AnyDepth) && {
+ val tpSym = tp.typeSymbolDirect
+ val abstractedTypeParams = tpSym.typeParams.drop(numCaptured).map(_.cloneSymbol(tpSym))
+
+ addBound(PolyType(abstractedTypeParams, appliedType(tp.typeConstructor, captured ++ abstractedTypeParams.map(_.tpeHK))))
+ true
+ }
+ } else false
}
// The type with which we can successfully unify can be hidden
// behind singleton types and type aliases.
diff --git a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala
index e75b3dff3d..5a2c802476 100644
--- a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala
+++ b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala
@@ -53,6 +53,7 @@ abstract class MutableSettings extends AbsSettings {
def printtypes: BooleanSetting
def uniqid: BooleanSetting
def verbose: BooleanSetting
+ def YpartialUnification: BooleanSetting
def Yrecursion: IntSetting
def maxClassfileName: IntSetting
diff --git a/src/reflect/scala/reflect/runtime/Settings.scala b/src/reflect/scala/reflect/runtime/Settings.scala
index b1d7fde1b4..3b33f089e1 100644
--- a/src/reflect/scala/reflect/runtime/Settings.scala
+++ b/src/reflect/scala/reflect/runtime/Settings.scala
@@ -47,6 +47,7 @@ private[reflect] class Settings extends MutableSettings {
val printtypes = new BooleanSetting(false)
val uniqid = new BooleanSetting(false)
val verbose = new BooleanSetting(false)
+ val YpartialUnification = new BooleanSetting(false)
val Yrecursion = new IntSetting(0)
val maxClassfileName = new IntSetting(255)