Scala Programming Language
  1. Scala Programming Language
  2. SI-5585

uniform inference for expression and valdef when existentials are involved

    Details

      Description

      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.

        Issue Links

          Activity

          Hide
          Alexander added a comment -
          Show
          Alexander added a comment - It's very similar to https://issues.scala-lang.org/browse/SI-5579
          Hide
          Paul Phillips added a comment -

          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.

          Show
          Paul Phillips added a comment - 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.
          Hide
          Paolo G. Giarrusso added a comment - - edited

          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 =>
          
          Show
          Paolo G. Giarrusso added a comment - - edited 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 =>
          Hide
          Jason Zaugg added a comment - - edited

          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.

          https://github.com/scala/scala/commit/225fac5

          Show
          Jason Zaugg added a comment - - edited 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. https://github.com/scala/scala/commit/225fac5
          Hide
          Paolo G. Giarrusso added a comment -

          > 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.

          Show
          Paolo G. Giarrusso added a comment - > 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.

            People

            • Assignee:
              Adriaan Moors
              Reporter:
              Alexander
            • Votes:
              1 Vote for this issue
              Watchers:
              8 Start watching this issue

              Dates

              • Created:
                Updated:

                Development