summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2014-01-28 15:12:38 +0300
committerEugene Burmako <xeno.by@gmail.com>2014-02-14 14:16:43 +0100
commitdf061de3fb2bc9a96d7bc77dc45c09f10fdb8531 (patch)
tree3dca5fbbbfd91ecb0e9b8ac1667bf8046b58b0e4
parent202eb73b6cd6ebb3e20ff9f0a198c4ea83319851 (diff)
downloadscala-df061de3fb2bc9a96d7bc77dc45c09f10fdb8531.tar.gz
scala-df061de3fb2bc9a96d7bc77dc45c09f10fdb8531.tar.bz2
scala-df061de3fb2bc9a96d7bc77dc45c09f10fdb8531.zip
splits Type.normalize into dealias and etaExpand
normalize is a highly overloaded name and it also conflates two distinct operators, so how about we give our users self-explaning atomic tools instead.
-rw-r--r--src/reflect/scala/reflect/api/Types.scala25
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala42
-rw-r--r--test/files/run/reflection-idtc.check6
-rw-r--r--test/files/run/reflection-idtc.scala16
4 files changed, 74 insertions, 15 deletions
diff --git a/src/reflect/scala/reflect/api/Types.scala b/src/reflect/scala/reflect/api/Types.scala
index c45ef83a8a..e524af583b 100644
--- a/src/reflect/scala/reflect/api/Types.scala
+++ b/src/reflect/scala/reflect/api/Types.scala
@@ -76,6 +76,12 @@ trait Types {
/** The API of types.
* The main source of information about types is the [[scala.reflect.api.Types]] page.
* @group API
+ *
+ * @define dealiasWidenWarning Note that type aliases can hide beneath
+ * singleton types and singleton types can hide inside type aliases.
+ * Moreover, aliases might lurk in the upper bounds of abstract types.
+ * Therefore careful thought has to be applied to identify and carry out
+ * unwrapping logic specific to your use case.
*/
abstract class TypeApi {
/** The term symbol associated with the type, or `NoSymbol` for types
@@ -123,7 +129,7 @@ trait Types {
*/
def typeConstructor: Type
- /**
+ /** Reduce to beta eta-long normal form.
* Expands type aliases and converts higher-kinded TypeRefs to PolyTypes.
* Functions on types are also implemented as PolyTypes.
*
@@ -131,8 +137,18 @@ trait Types {
* TypeRef(pre, <List>, List()) is replaced by
* PolyType(X, TypeRef(pre, <List>, List(X)))
*/
+ @deprecated("Use `dealias` or `etaExpand` instead", "2.11.0")
def normalize: Type
+ /** Converts higher-kinded TypeRefs to PolyTypes.
+ * Functions on types are also implemented as PolyTypes.
+ *
+ * Example: (in the below, <List> is the type constructor of List)
+ * TypeRef(pre, <List>, List()) is replaced by
+ * PolyType(X, TypeRef(pre, <List>, List(X)))
+ */
+ def etaExpand: Type
+
/** Does this type conform to given type argument `that`? */
def <:< (that: Type): Boolean
@@ -205,9 +221,16 @@ trait Types {
* class Outer { class C ; val x: C }
* val o: Outer
* <o.x.type>.widen = o.C
+ *
+ * $dealiasWidenWarning
*/
def widen: Type
+ /** Expands type aliases arising from type members.
+ * $dealiasWidenWarning
+ */
+ def dealias: Type
+
/******************* helpers *******************/
/** Provides an alternate if type is NoType.
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index d8c7682910..ca99b1af74 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -194,6 +194,7 @@ trait Types
override def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]) = underlying.instantiateTypeParams(formals, actuals)
override def skolemizeExistential(owner: Symbol, origin: AnyRef) = underlying.skolemizeExistential(owner, origin)
override def normalize = maybeRewrap(underlying.normalize)
+ override def etaExpand = maybeRewrap(underlying.etaExpand)
override def dealias = maybeRewrap(underlying.dealias)
override def cloneInfo(owner: Symbol) = maybeRewrap(underlying.cloneInfo(owner))
override def atOwner(owner: Symbol) = maybeRewrap(underlying.atOwner(owner))
@@ -498,6 +499,8 @@ trait Types
*/
def normalize = this // @MAT
+ def etaExpand = this
+
/** Expands type aliases. */
def dealias = this
@@ -1589,20 +1592,27 @@ trait Types
} else if (flattened != parents) {
refinedType(flattened, if (typeSymbol eq NoSymbol) NoSymbol else typeSymbol.owner, decls, NoPosition)
} else if (isHigherKinded) {
- // MO to AM: This is probably not correct
- // If they are several higher-kinded parents with different bounds we need
- // to take the intersection of their bounds
- typeFun(
- typeParams,
- RefinedType(
- parents map {
- case TypeRef(pre, sym, List()) => TypeRef(pre, sym, dummyArgs)
- case p => p
- },
- decls,
- typeSymbol))
+ etaExpand
} else super.normalize
}
+
+ final override def etaExpand: Type = {
+ // MO to AM: This is probably not correct
+ // If they are several higher-kinded parents with different bounds we need
+ // to take the intersection of their bounds
+ // !!! inconsistent with TypeRef.etaExpand that uses initializedTypeParams
+ if (!isHigherKinded) this
+ else typeFun(
+ typeParams,
+ RefinedType(
+ parents map {
+ case TypeRef(pre, sym, List()) => TypeRef(pre, sym, dummyArgs)
+ case p => p
+ },
+ decls,
+ typeSymbol))
+ }
+
override def kind = "RefinedType"
}
@@ -2119,7 +2129,7 @@ trait Types
|| pre.isGround && args.forall(_.isGround)
)
- def etaExpand: Type = {
+ final override def etaExpand: Type = {
// must initialise symbol, see test/files/pos/ticket0137.scala
val tpars = initializedTypeParams
if (tpars.isEmpty) this
@@ -3119,9 +3129,13 @@ trait Types
if (instValid) inst
// get here when checking higher-order subtyping of the typevar by itself
// TODO: check whether this ever happens?
- else if (isHigherKinded) logResult("Normalizing HK $this")(typeFun(params, applyArgs(params map (_.typeConstructor))))
+ else if (isHigherKinded) etaExpand
else super.normalize
)
+ override def etaExpand: Type = (
+ if (!isHigherKinded) this
+ else logResult("Normalizing HK $this")(typeFun(params, applyArgs(params map (_.typeConstructor))))
+ )
override def typeSymbol = origin.typeSymbol
private def tparamsOfSym(sym: Symbol) = sym.info match {
diff --git a/test/files/run/reflection-idtc.check b/test/files/run/reflection-idtc.check
new file mode 100644
index 0000000000..9cdeb02f8c
--- /dev/null
+++ b/test/files/run/reflection-idtc.check
@@ -0,0 +1,6 @@
+[X]X
+Int
+===
+[X]Id[X]
+Id[Int]
+Int
diff --git a/test/files/run/reflection-idtc.scala b/test/files/run/reflection-idtc.scala
new file mode 100644
index 0000000000..bbe90f6826
--- /dev/null
+++ b/test/files/run/reflection-idtc.scala
@@ -0,0 +1,16 @@
+import scala.reflect.runtime.universe._
+import scala.reflect.runtime.{currentMirror => cm}
+import scala.tools.reflect.ToolBox
+
+object Test extends App {
+ val tb = cm.mkToolBox()
+ val idsym = tb.typecheck(q"type Id[X] = X").symbol.asType
+ val idTC1 = idsym.typeSignature
+ println(idTC1)
+ println(appliedType(idTC1, List(typeOf[Int])))
+ println("===")
+ val idTC2 = idsym.toType.etaExpand
+ println(idTC2)
+ println(appliedType(idTC2, List(typeOf[Int])))
+ println(appliedType(idTC2, List(typeOf[Int])).dealias)
+} \ No newline at end of file