Skip to content

Commit 70647c8

Browse files
committed
Implement type beta reduction in lookupRefined
lookupRefined now reduces fully instantiated lambdas.
1 parent aebb004 commit 70647c8

File tree

1 file changed

+44
-14
lines changed

1 file changed

+44
-14
lines changed

src/dotty/tools/dotc/core/Types.scala

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -792,43 +792,73 @@ object Types {
792792

793793
// ----- Normalizing typerefs over refined types ----------------------------
794794

795-
/** If this is a refinement type that has a refinement for `name` (which might be followed
795+
/** If this normalizes* to a refinement type that has a refinement for `name` (which might be followed
796796
* by other refinements), and the refined info is a type alias, return the alias,
797797
* otherwise return NoType. Used to reduce types of the form
798798
*
799799
* P { ... type T = / += / -= U ... } # T
800800
*
801801
* to just U. Does not perform the reduction if the resulting type would contain
802-
* a reference to the "this" of the current refined type. But does follow
803-
* aliases in order to avoid such references. Example:
802+
* a reference to the "this" of the current refined type, except in the following situation
804803
*
805-
* Lambda$I { type $hk$Arg0 = String, type Apply = Lambda$I{...}.$hk$Arg0 } # Apply
804+
* (1) The "this" reference can be avoided by following an alias. Example:
806805
*
807-
* Here, the refinement for `Apply` has a refined this node, yet dereferencing ones more
808-
* yields `String` as the result of lookupRefined.
806+
* P { type T = String, type R = P{...}.T } # R --> String
807+
*
808+
* (2) The refinement is a fully instantiated type lambda, and the projected name is "Apply".
809+
* In this case the rhs of the apply is returned with all references to lambda argument types
810+
* substituted by their definitions.
811+
*
812+
* (*) normalizes means: follow instantiated typevars and aliases.
809813
*/
810814
def lookupRefined(name: Name)(implicit ctx: Context): Type = {
811-
def loop(pre: Type): Type = pre.stripTypeVar match {
815+
def loop(pre: Type, resolved: List[Name]): Type = pre.stripTypeVar match {
812816
case pre: RefinedType =>
813-
if (pre.refinedName ne name) loop(pre.parent)
814-
else pre.refinedInfo match {
817+
object instantiate extends TypeMap {
818+
var isSafe = true
819+
def apply(tp: Type): Type = tp match {
820+
case TypeRef(SkolemType(`pre`), name) if name.isLambdaArgName =>
821+
val TypeAlias(alias) = member(name).info
822+
alias
823+
case tp: TypeVar if !tp.inst.exists =>
824+
isSafe = false
825+
tp
826+
case _ =>
827+
mapOver(tp)
828+
}
829+
}
830+
def betaReduce(tp: Type) = {
831+
val lam = pre.parent.LambdaClass(forcing = false)
832+
if (lam.exists && lam.typeParams.forall(tparam => resolved.contains(tparam.name))) {
833+
val reduced = instantiate(tp)
834+
if (instantiate.isSafe) reduced else NoType
835+
}
836+
else NoType
837+
}
838+
pre.refinedInfo match {
815839
case TypeAlias(alias) =>
816-
if (!pre.refinementRefersToThis) alias
840+
if (pre.refinedName ne name) loop(pre.parent, pre.refinedName :: resolved)
841+
else if (!pre.refinementRefersToThis) alias
817842
else alias match {
818-
case TypeRef(SkolemType(`pre`), aliasName) => lookupRefined(aliasName )
819-
case _ => NoType
843+
case TypeRef(SkolemType(`pre`), aliasName) => lookupRefined(aliasName) // (1)
844+
case _ => if (name == tpnme.Apply) betaReduce(alias) else NoType // (2)
820845
}
821-
case _ => loop(pre.parent)
846+
case _ => loop(pre.parent, resolved)
822847
}
823848
case SkolemType(binder) =>
824849
binder.lookupRefined(name)
825850
case pre: WildcardType =>
826851
WildcardType
852+
case pre: TypeRef =>
853+
pre.info match {
854+
case TypeAlias(alias) => loop(alias, resolved)
855+
case _ => NoType
856+
}
827857
case _ =>
828858
NoType
829859
}
830860

831-
loop(this)
861+
loop(this, Nil)
832862
}
833863

834864
/** The type <this . name> , reduced if possible */

0 commit comments

Comments
 (0)