aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/core/Types.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2015-05-18 13:02:20 +0200
committerMartin Odersky <odersky@gmail.com>2015-05-21 17:41:15 +0200
commit110a438c000cd77caff28ebe9725d2a00f8060d6 (patch)
tree1f0e05eda844b515ffe7140b7d2d204d4b45f6f9 /src/dotty/tools/dotc/core/Types.scala
parentd5975dc740bd55ea72477e9f726882edcd18dbe3 (diff)
downloaddotty-110a438c000cd77caff28ebe9725d2a00f8060d6.tar.gz
dotty-110a438c000cd77caff28ebe9725d2a00f8060d6.tar.bz2
dotty-110a438c000cd77caff28ebe9725d2a00f8060d6.zip
Implement type beta reduction in lookupRefined
lookupRefined now reduces fully instantiated lambdas.
Diffstat (limited to 'src/dotty/tools/dotc/core/Types.scala')
-rw-r--r--src/dotty/tools/dotc/core/Types.scala58
1 files changed, 44 insertions, 14 deletions
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 237d498b0..6e18f4a50 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -792,43 +792,73 @@ object Types {
// ----- Normalizing typerefs over refined types ----------------------------
- /** If this is a refinement type that has a refinement for `name` (which might be followed
+ /** If this normalizes* to a refinement type that has a refinement for `name` (which might be followed
* by other refinements), and the refined info is a type alias, return the alias,
* otherwise return NoType. Used to reduce types of the form
*
* P { ... type T = / += / -= U ... } # T
*
* to just U. Does not perform the reduction if the resulting type would contain
- * a reference to the "this" of the current refined type. But does follow
- * aliases in order to avoid such references. Example:
+ * a reference to the "this" of the current refined type, except in the following situation
*
- * Lambda$I { type $hk$Arg0 = String, type Apply = Lambda$I{...}.$hk$Arg0 } # Apply
+ * (1) The "this" reference can be avoided by following an alias. Example:
*
- * Here, the refinement for `Apply` has a refined this node, yet dereferencing ones more
- * yields `String` as the result of lookupRefined.
+ * P { type T = String, type R = P{...}.T } # R --> String
+ *
+ * (2) The refinement is a fully instantiated type lambda, and the projected name is "Apply".
+ * In this case the rhs of the apply is returned with all references to lambda argument types
+ * substituted by their definitions.
+ *
+ * (*) normalizes means: follow instantiated typevars and aliases.
*/
def lookupRefined(name: Name)(implicit ctx: Context): Type = {
- def loop(pre: Type): Type = pre.stripTypeVar match {
+ def loop(pre: Type, resolved: List[Name]): Type = pre.stripTypeVar match {
case pre: RefinedType =>
- if (pre.refinedName ne name) loop(pre.parent)
- else pre.refinedInfo match {
+ object instantiate extends TypeMap {
+ var isSafe = true
+ def apply(tp: Type): Type = tp match {
+ case TypeRef(SkolemType(`pre`), name) if name.isLambdaArgName =>
+ val TypeAlias(alias) = member(name).info
+ alias
+ case tp: TypeVar if !tp.inst.exists =>
+ isSafe = false
+ tp
+ case _ =>
+ mapOver(tp)
+ }
+ }
+ def betaReduce(tp: Type) = {
+ val lam = pre.parent.LambdaClass(forcing = false)
+ if (lam.exists && lam.typeParams.forall(tparam => resolved.contains(tparam.name))) {
+ val reduced = instantiate(tp)
+ if (instantiate.isSafe) reduced else NoType
+ }
+ else NoType
+ }
+ pre.refinedInfo match {
case TypeAlias(alias) =>
- if (!pre.refinementRefersToThis) alias
+ if (pre.refinedName ne name) loop(pre.parent, pre.refinedName :: resolved)
+ else if (!pre.refinementRefersToThis) alias
else alias match {
- case TypeRef(SkolemType(`pre`), aliasName) => lookupRefined(aliasName )
- case _ => NoType
+ case TypeRef(SkolemType(`pre`), aliasName) => lookupRefined(aliasName) // (1)
+ case _ => if (name == tpnme.Apply) betaReduce(alias) else NoType // (2)
}
- case _ => loop(pre.parent)
+ case _ => loop(pre.parent, resolved)
}
case SkolemType(binder) =>
binder.lookupRefined(name)
case pre: WildcardType =>
WildcardType
+ case pre: TypeRef =>
+ pre.info match {
+ case TypeAlias(alias) => loop(alias, resolved)
+ case _ => NoType
+ }
case _ =>
NoType
}
- loop(this)
+ loop(this, Nil)
}
/** The type <this . name> , reduced if possible */