Uploaded image for project: '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.

        Attachments

          Issue Links

            Activity

            Hide
            alefas Alexander added a comment -
            Show
            alefas Alexander added a comment - It's very similar to https://issues.scala-lang.org/browse/SI-5579
            Hide
            extempore 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
            extempore 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
            pggiarrusso 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
            pggiarrusso 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
            retronym 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
            retronym 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
            pggiarrusso 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
            pggiarrusso 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:
                moors Adriaan Moors
                Reporter:
                alefas Alexander
              • Votes:
                1 Vote for this issue
                Watchers:
                7 Start watching this issue

                Dates

                • Created:
                  Updated: