Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

uniform inference for expression and valdef when existentials are involved #5585

Closed
scabug opened this issue Mar 19, 2012 · 8 comments
Closed

Comments

@scabug
Copy link

scabug commented Mar 19, 2012

class Result[+A]

case class Success[A](x: A) extends Result[A]

class Apply[A]

object Apply {
  def apply[A](f: Int => Result[A]): Apply[A] = new Apply[A]
}

object TestUnit {
  def goo : Apply[Option[Int]] = Apply { i =>
    /* val p = */i match {
      case 1 => Success(Some(1))
      case _ => Success(None)
    }
    //p
  }
}

This code compiles wуll. However with uncommented it fails. I checked all generics under the clojure are inferred in the same way. So I can't explain this different behavior.

@scabug
Copy link
Author

scabug commented Mar 19, 2012

Imported From: https://issues.scala-lang.org/browse/SI-5585?orig=1
Reporter: @Alefas
Affected Versions: 2.9.1, 2.10.0
See #5579

@scabug
Copy link
Author

scabug commented Mar 19, 2012

@Alefas said:
It's very similar to #5579

@scabug
Copy link
Author

scabug commented Mar 20, 2012

@paulp said:
With the intermediate assignment, it seems to infer "Success[_ >: Some[Int] with None.type <: Option[Int]]" as the result of the match. Then it decides this is incompatible with the typevar. Without the intermediate assignment, it is able to connect the dots between ?A and the match.

I guess my question is, why doesn't it simplify Success[_ >: Some[Int] with None.type <: Option[Int]] to Success[Option[Int]]. Of course if you do that by hand with type annotations, everything works.

@scabug
Copy link
Author

scabug commented Mar 21, 2012

@Blaisorblade said (edited on Mar 21, 2012 7:59:04 AM UTC):
In my experience using wildcards a lot more than appropriate, the error message seems normal. It just says that you cannot pass a BoundedWildcardType as a type parameter, as it often happens (in my experience).

Reading the source, this does not make sense since recursion should end here:
https://github.com/scala/scala/blob/d8ba5d091e5641553b438ef9930a6023a2709dcd/src/compiler/scala/reflect/internal/Types.scala#L5347
However, it needs to pass a couple of layers before. For the error to happen, in fact, it is required a double mismatch: Success vs Result and type variable vs bounded wildcard. Either making Success covariant or exchanging Success with Result either at the Apply.apply signature or at its caller hides the bug.

<console>:13: error: no type parameters for method apply: (f: Int => Result[A])Apply[A] in object Apply exist so that it can be applied to arguments (Int => Success[_ >: Some[Int] with None.type <: Option[Int]])
 --- because ---
argument expression's type is not compatible with formal parameter type;
 found   : Int => Success[_ >: Some[Int] with None.type <: Option[Int]]
 required: Int => Result[?A]
         def goo : Apply[Option[Int]] = Apply { i =>

@scabug
Copy link
Author

scabug commented Feb 10, 2013

@retronym said (edited on Feb 10, 2013 11:50:49 AM UTC):
Here's another look at this:

% ~/code/scala2 cat sandbox/t5585.scala
class Result[+A]

case class Success[A](x: A) extends Result[A]

class Apply[A]

object Apply {
  def apply[A](f: Int => Result[A]): Apply[A] = new Apply[A]
}

object TestUnit {
  def goo : Apply[Option[Int]] = Apply.apply { i =>
    val p = (0: Int) match {
      case 1 => Success(Some(1))
      case _ => Success(None)
    }
    p
  }

  //
  // OK
  //


  def f[A](r: Result[A]): Apply[A] = ???
  f {
    (0: Int) match {
      case 1 => Success(Some(1))
      case _ => Success(None)
    }
  }: Apply[Option[Int]]

  f {
    val p = (0: Int) match {
      case 1 => Success(Some(1))
      case _ => Success(None)
    }
    p
  }: Apply[Option[Int]]


  case class H[-A, +B](b: B)
  def h[A](r: H[Int, Result[A]]): Apply[A] = ???
  h {
    val p = (0: Int) match {
      case 1 => Success(Some(1))
      case _ => Success(None)
    }
    H(p)
  }: Apply[Option[Int]]


  //
  // KO
  //

  def g[A](r: Function1[Int, Result[A]]): Apply[A] = ???
  g {
    val p = (0: Int) match {
      case 1 => Success(Some(1))
      case _ => Success(None)
    }
    (i: Int) => p
  }: Apply[Option[Int]]

}
% qbin/scalac  sandbox/t5585.scala

% git diff
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index dc5491a..00af937 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -2837,7 +2837,7 @@ trait Typers extends Modes with Adaptations with Tags {
     //        }
             val formals = vparamSyms map (_.tpe)
             val body1 = typed(fun.body, respt)
-            val restpe = packedType(body1, fun.symbol).deconst.resultType
+            val restpe = body1.tpe.deconst
             val funtpe = typeRef(clazz.tpe.prefix, clazz, formals :+ restpe)
     //        body = checkNoEscaping.locals(context.scope, restpe, body)
             treeCopy.Function(fun, vparams, body1).setType(funtpe)

An understanding of packedType seems important here.

scala/scala@225fac5

@scabug
Copy link
Author

scabug commented Jun 11, 2013

@Blaisorblade said:

In my experience using wildcards a lot more than appropriate, the error message seems normal. It just says that you cannot pass a BoundedWildcardType as a type parameter, as it often happens (in my experience).

I should clarify: with "normal" I meant "a bug I see all the time", not "the right thing to do". At least, that's what I should have meant.

@SethTisue
Copy link
Member

I don't know what changed between 2.12 and 2.13 to make this work, but it works now. Scala 3 accepts it as well.

@som-snytt
Copy link

FWIW Scala 2 inference of p is unchanged

    def g: Apply[Option[Int]] = Apply.apply[Option[Int]](((i: Int) => {
      val p: Success[_ >: Some[Int] with None.type <: Option[Int]] = i match {
        case 1 => Success.apply[Some[Int]](scala.Some.apply[Int](1))
        case _ => Success.apply[None.type](scala.None)
      };
      p
    }))

Scala 3

    def g: Apply[Option[Int]] =
      Apply.apply[Option[Int]](
        {
          {
            def $anonfun(i: Int): Result[Option[Int]] =
              {
                val p: Success[Option[Int]] =
                  i match
                    {
                      case 1 =>
                        Success.apply[Option[Int]](Some.apply[Int](1))
                      case _ =>
                        Success.apply[Option[Int]](None)
                    }
                p:Success[Option[Int]]
              }
            closure($anonfun)
          }
        }
      )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants