@@ -3783,8 +3783,8 @@ object Types {
3783
3783
* and PolyType not allowed!)
3784
3784
* - can be instantiated without arguments or with just () as argument.
3785
3785
*
3786
- * The pattern `SAMType(denot )` matches a SAM type, where `denot ` is the
3787
- * denotation of the single abstract method as a member of the type .
3786
+ * The pattern `SAMType(sam )` matches a SAM type, where `sam ` is the
3787
+ * type of the single abstract method.
3788
3788
*/
3789
3789
object SAMType {
3790
3790
def zeroParamClass (tp : Type )(implicit ctx : Context ): Type = tp match {
@@ -3811,20 +3811,55 @@ object Types {
3811
3811
}
3812
3812
def isInstantiatable (tp : Type )(implicit ctx : Context ): Boolean = zeroParamClass(tp) match {
3813
3813
case cinfo : ClassInfo =>
3814
- val tref = tp.narrow
3815
- val selfType = cinfo.selfType.asSeenFrom(tref, cinfo.cls)
3816
- tref <:< selfType
3814
+ val selfType = cinfo.selfType.asSeenFrom(tp, cinfo.cls)
3815
+ tp <:< selfType
3817
3816
case _ =>
3818
3817
false
3819
3818
}
3820
- def unapply (tp : Type )(implicit ctx : Context ): Option [SingleDenotation ] =
3819
+ def unapply (tp : Type )(implicit ctx : Context ): Option [MethodType ] =
3821
3820
if (isInstantiatable(tp)) {
3822
3821
val absMems = tp.abstractTermMembers
3823
3822
// println(s"absMems: ${absMems map (_.show) mkString ", "}")
3824
3823
if (absMems.size == 1 )
3825
3824
absMems.head.info match {
3826
- case mt : MethodType if ! mt.isParamDependent => Some (absMems.head)
3827
- case _ => None
3825
+ case mt : MethodType if ! mt.isParamDependent =>
3826
+ val cls = tp.classSymbol
3827
+
3828
+ // Given a SAM type such as:
3829
+ //
3830
+ // import java.util.function.Function
3831
+ // Function[_ >: String, _ <: Int]
3832
+ //
3833
+ // the single abstract method will have type:
3834
+ //
3835
+ // (x: Function[_ >: String, _ <: Int]#T): Function[_ >: String, _ <: Int]#R
3836
+ //
3837
+ // which is not implementable outside of the scope of Function.
3838
+ //
3839
+ // To avoid this kind of issue, we approximate references to
3840
+ // parameters of the SAM type by their bounds, this way in the
3841
+ // above example we get:
3842
+ //
3843
+ // (x: String): Int
3844
+ val approxParams = new ApproximatingTypeMap {
3845
+ def apply (tp : Type ): Type = tp match {
3846
+ case tp : TypeRef if tp.symbol.is(ClassTypeParam ) && tp.symbol.owner == cls =>
3847
+ tp.info match {
3848
+ case TypeAlias (alias) =>
3849
+ mapOver(alias)
3850
+ case TypeBounds (lo, hi) =>
3851
+ range(atVariance(- variance)(apply(lo)), apply(hi))
3852
+ case _ =>
3853
+ range(defn.NothingType , defn.AnyType ) // should happen only in error cases
3854
+ }
3855
+ case _ =>
3856
+ mapOver(tp)
3857
+ }
3858
+ }
3859
+ val approx = approxParams(mt).asInstanceOf [MethodType ]
3860
+ Some (approx)
3861
+ case _ =>
3862
+ None
3828
3863
}
3829
3864
else if (tp isRef defn.PartialFunctionClass )
3830
3865
// To maintain compatibility with 2.x, we treat PartialFunction specially,
@@ -3833,7 +3868,7 @@ object Types {
3833
3868
// def isDefinedAt(x: T) = true
3834
3869
// and overwrite that method whenever the function body is a sequence of
3835
3870
// case clauses.
3836
- absMems.find(_.symbol.name == nme.apply)
3871
+ absMems.find(_.symbol.name == nme.apply).map(_.info. asInstanceOf [ MethodType ])
3837
3872
else None
3838
3873
}
3839
3874
else None
0 commit comments