@@ -792,43 +792,73 @@ object Types {
792
792
793
793
// ----- Normalizing typerefs over refined types ----------------------------
794
794
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
796
796
* by other refinements), and the refined info is a type alias, return the alias,
797
797
* otherwise return NoType. Used to reduce types of the form
798
798
*
799
799
* P { ... type T = / += / -= U ... } # T
800
800
*
801
801
* 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
804
803
*
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:
806
805
*
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.
809
813
*/
810
814
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 {
812
816
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 {
815
839
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
817
842
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)
820
845
}
821
- case _ => loop(pre.parent)
846
+ case _ => loop(pre.parent, resolved )
822
847
}
823
848
case SkolemType (binder) =>
824
849
binder.lookupRefined(name)
825
850
case pre : WildcardType =>
826
851
WildcardType
852
+ case pre : TypeRef =>
853
+ pre.info match {
854
+ case TypeAlias (alias) => loop(alias, resolved)
855
+ case _ => NoType
856
+ }
827
857
case _ =>
828
858
NoType
829
859
}
830
860
831
- loop(this )
861
+ loop(this , Nil )
832
862
}
833
863
834
864
/** The type <this . name> , reduced if possible */
0 commit comments