@@ -2341,7 +2341,7 @@ object ScalaPsiUtil {
2341
2341
* @see SCL-6140
2342
2342
* @see https://github.com/scala/scala/pull/3018/
2343
2343
*/
2344
- def toSAMType (expected : ScType , scope : GlobalSearchScope ): Option [ScType ] = {
2344
+ def toSAMType (expected : ScType , scalaScope : GlobalSearchScope ): Option [ScType ] = {
2345
2345
2346
2346
def constructorValidForSAM (constructors : Array [PsiMethod ]): Boolean = {
2347
2347
// primary constructor (if any) must be public, no-args, not overloaded
@@ -2371,8 +2371,14 @@ object ScalaPsiUtil {
2371
2371
! abst.head.hasTypeParameters
2372
2372
2373
2373
if (valid) {
2374
- abst.head.getType() match {
2375
- case Success (tp, _) => Some (sub.subst(tp))
2374
+ val fun = abst.head
2375
+ fun.getType() match {
2376
+ case Success (tp, _) =>
2377
+ val subbed = sub.subst(tp)
2378
+ extrapolateWildcardBounds(subbed, expected, fun.getProject, scalaScope) match {
2379
+ case s@ Some (_) => s
2380
+ case _ => Some (subbed)
2381
+ }
2376
2382
case _ => None
2377
2383
}
2378
2384
} else None
@@ -2384,15 +2390,63 @@ object ScalaPsiUtil {
2384
2390
// need to generate ScType for Java method
2385
2391
val method = abst.head
2386
2392
val project = method.getProject
2387
- val returnType : ScType = ScType .create(method.getReturnType, project, scope )
2393
+ val returnType : ScType = ScType .create(method.getReturnType, project, scalaScope )
2388
2394
val params : Array [ScType ] = method.getParameterList.getParameters.map {
2389
- param : PsiParameter => ScType .create(param.getTypeElement.getType, project, scope)
2395
+ param : PsiParameter => ScType .create(param.getTypeElement.getType, project, scalaScope)
2396
+ }
2397
+ val fun = ScFunctionType (returnType, params)(project, scalaScope)
2398
+ val subbed = sub.subst(fun)
2399
+ extrapolateWildcardBounds(subbed, expected, project, scalaScope) match {
2400
+ case s@ Some (_) => s
2401
+ case _ => Some (subbed)
2390
2402
}
2391
- val result = ScFunctionType (returnType, params)(project, scope)
2392
- Some (sub.subst(result))
2393
2403
} else None
2394
2404
}
2395
2405
case None => None
2396
2406
}
2397
2407
}
2408
+
2409
+ /**
2410
+ * In some cases existential bounds can be simplified without losing precision
2411
+ *
2412
+ * trait Comparinator[T] { def compare(a: T, b: T): Int }
2413
+ *
2414
+ * trait Test {
2415
+ * def foo(a: Comparinator[_ >: String]): Int
2416
+ * }
2417
+ *
2418
+ * can be simplified to:
2419
+ *
2420
+ * trait Test {
2421
+ * def foo(a: Comparinator[String]): Int
2422
+ * }
2423
+ *
2424
+ * @see https://github.com/scala/scala/pull/4101
2425
+ * @see SCL-8956
2426
+ */
2427
+ private def extrapolateWildcardBounds (tp : ScType , expected : ScType , proj : Project , scope : GlobalSearchScope ): Option [ScType ] = {
2428
+ expected match {
2429
+ case ScExistentialType (ScParameterizedType (expectedDesignator, _), wildcards) =>
2430
+ tp match {
2431
+ case ScFunctionType (retTp, params) =>
2432
+ def convertParameter (tpArg : ScType , variance : Int ): ScType = {
2433
+ wildcards.find(_.name == tpArg.canonicalText) match {
2434
+ case Some (wildcard) =>
2435
+ (wildcard.lowerBound, wildcard.upperBound) match {
2436
+ case (lo, Any ) if variance == ScTypeParam .Contravariant => lo
2437
+ case (Nothing , hi) if variance == ScTypeParam .Covariant => hi
2438
+ case _ => tpArg
2439
+ }
2440
+ case _ => tpArg
2441
+ }
2442
+ }
2443
+ // parameter clauses are contravariant positions, return types are covariant positions
2444
+ val newParams = params.map(convertParameter(_, ScTypeParam .Contravariant ))
2445
+ val newRetTp = convertParameter(retTp, ScTypeParam .Covariant )
2446
+ Some (ScFunctionType (newRetTp, newParams)(proj, scope))
2447
+ case _ => None
2448
+ }
2449
+ case _ => None
2450
+ }
2451
+ }
2398
2452
}
0 commit comments