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

Type inference issue with 2.9.0.RC3 for arities 21 and 22, but not 1 to 20

    Details

      Description

      [Edited for brevity and accuracy.]

      Compiles with 2.8.1, fails with 2.9.0.RC1 through current.

      object Test {  
        def f[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T](table: Tuple20[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T])(fun: (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T) => Unit) {
        }
        def g[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U](table: Tuple21[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U])(fun: (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U) => Unit) {
        }
      
        def g20 = f(
          (  1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1)
        ) { case ((a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t)) => () }
        
        def g21 = g(
            (1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1)
        ) { case ((a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u)) => () }
      }
      

      Failure in rc:

      c.scala:13: error: missing parameter type for expanded function
      The argument types of an anonymous function must be fully known. (SLS 8.5)
      Expected type was: Function21[Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Unit]
        ) { case ((a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u)) => () }
          ^
      one error found
      

        Activity

        Hide
        Paul Phillips added a comment -

        Fascinating bug. However it is in RC1. I'm pretty confident of that fact because I can reproduce the absence of the bug in 2.8.1, but all the rcs show the bug.

        Show
        Paul Phillips added a comment - Fascinating bug. However it is in RC1. I'm pretty confident of that fact because I can reproduce the absence of the bug in 2.8.1, but all the rcs show the bug.
        Hide
        Paul Phillips added a comment -

        Reduced by a couple orders of magnitude, and removing the red herrings of implicit conversions and overloaded varargs polymorphic applies, and changed to use a partial function because the error message is much clearer (and shorter.)

        object Test {  
          def f[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T](table: Tuple20[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T])(fun: (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T) => Unit) {
          }
          def g[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U](table: Tuple21[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U])(fun: (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U) => Unit) {
          }
        
          def g20 = f(
            (  1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1)
          ) { case ((a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t)) => () }
          
          def g21 = g(
              (1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1)
          ) { case ((a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u)) => () }
        }
        

        This compiles in 2.8. In rc1 through current it fails:

        c.scala:13: error: missing parameter type for expanded function
        The argument types of an anonymous function must be fully known. (SLS 8.5)
        Expected type was: Function21[Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Unit]
          ) { case ((a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u)) => () }
            ^
        one error found
        
        Show
        Paul Phillips added a comment - Reduced by a couple orders of magnitude, and removing the red herrings of implicit conversions and overloaded varargs polymorphic applies, and changed to use a partial function because the error message is much clearer (and shorter.) object Test { def f[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T](table: Tuple20[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T])(fun: (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T) => Unit) { } def g[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U](table: Tuple21[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U])(fun: (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U) => Unit) { } def g20 = f( ( 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) ) { case ((a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t)) => () } def g21 = g( (1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) ) { case ((a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u)) => () } } This compiles in 2.8. In rc1 through current it fails: c.scala:13: error: missing parameter type for expanded function The argument types of an anonymous function must be fully known. (SLS 8.5) Expected type was: Function21[Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Unit] ) { case ((a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u)) => () } ^ one error found
        Hide
        Iulian Dragos added a comment -

        Adriaan, can you please have a look?

        Show
        Iulian Dragos added a comment - Adriaan, can you please have a look?
        Hide
        Adriaan Moors added a comment -

        classic off-by-one, I'd say (as well as the poster child for sane variable names):

        now:

            def isFunctionType(tp: Type): Boolean = tp.normalize match {
              case TypeRef(_, sym, args) if args.nonEmpty =>
                val len = args.length
                len < MaxFunctionArity && sym == FunctionClass(len - 1)
              case _ =>
                false
            }
        

        i claim this is more clear as well as correct:

            def isFunctionType(tp: Type): Boolean = tp.normalize match {
              case TypeRef(_, sym, args) if args.nonEmpty =>
                val arity = args.length - 1
                arity <= MaxFunctionArity && sym == FunctionClass(arity)
              case _ =>
                false
            }
        
        Show
        Adriaan Moors added a comment - classic off-by-one, I'd say (as well as the poster child for sane variable names): now: def isFunctionType(tp: Type): Boolean = tp.normalize match { case TypeRef(_, sym, args) if args.nonEmpty => val len = args.length len < MaxFunctionArity && sym == FunctionClass(len - 1) case _ => false } i claim this is more clear as well as correct: def isFunctionType(tp: Type): Boolean = tp.normalize match { case TypeRef(_, sym, args) if args.nonEmpty => val arity = args.length - 1 arity <= MaxFunctionArity && sym == FunctionClass(arity) case _ => false }
        Hide
        Paul Phillips added a comment -

        Replying to [comment:5 moors]:
        > classic off-by-one, I'd say (as well as the poster child for sane variable names):

        But how will lenny respond to this blatant attempt to exclude him?

        Now I see how creates a class "off-by-two" bug (as this fails at both 21 and 22.) One takes this:

          args.length - 1 <= MaxFunctionArity
        

        And cleverly turns it into this:

        val len = args.length
        len < MaxFunctionArity
        

        Adding one and changing from <= to < must cancel each other out, right?

        At least the perpetrator of this was nobly trying to make things faster by eliminating some of the many calls to list.length. He deserves a medal, not your fencepost scorn.

        Show
        Paul Phillips added a comment - Replying to [comment:5 moors] : > classic off-by-one, I'd say (as well as the poster child for sane variable names): But how will lenny respond to this blatant attempt to exclude him? Now I see how creates a class "off-by-two" bug (as this fails at both 21 and 22.) One takes this: args.length - 1 <= MaxFunctionArity And cleverly turns it into this: val len = args.length len < MaxFunctionArity Adding one and changing from <= to < must cancel each other out, right? At least the perpetrator of this was nobly trying to make things faster by eliminating some of the many calls to list.length. He deserves a medal, not your fencepost scorn.
        Hide
        Paul Phillips added a comment -

        Fixed in 75e584bd0c , sorry it took so long.

        Show
        Paul Phillips added a comment - Fixed in 75e584bd0c , sorry it took so long.

          People

          • Assignee:
            Paul Phillips
            Reporter:
            Bill Venners
            TracCC:
            Paul Phillips
          • Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development