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

crashy interplay between value class, existentials, inference

    Details

      Description

      class Observable1[+T](val asJava: JObservable[_ <: T]) extends AnyVal {
        private def foo[X](a: JObservable[X]): JObservable[X] = ???
        def synchronize: Observable1[T] = new Observable1(foo(asJava))
      }
      
      class JObservable[T]
      
      scalac-hash v2.11.0-M4 sandbox/value-class-existential.scala
      [info] v2.11.0-M4 => /Users/jason/usr/scala-v2.11.0-M4-0-g8b41240
      error: scala.reflect.internal.Types$TypeError: type mismatch;
       found   : Observable1[_$1] where type _$1 <: T
       required: Observable1[T]
      	at scala.tools.nsc.typechecker.Contexts$Context.issue(Contexts.scala:549)
      	at scala.tools.nsc.typechecker.ContextErrors$ErrorUtils$.issueTypeError(ContextErrors.scala:97)
      	at scala.tools.nsc.typechecker.ContextErrors$ErrorUtils$.issueNormalTypeError(ContextErrors.scala:86)
      	at scala.tools.nsc.typechecker.ContextErrors$TyperContextErrors$TyperErrorGen$.AdaptTypeError(ContextErrors.scala:184)
      	at scala.tools.nsc.typechecker.Typers$Typer.adaptMismatchedSkolems$1(Typers.scala:1126)
      	at scala.tools.nsc.typechecker.Typers$Typer.fallbackAfterVanillaAdapt$1(Typers.scala:1195)
      	at scala.tools.nsc.typechecker.Typers$Typer.vanillaAdapt$1(Typers.scala:1232)
      	at scala.tools.nsc.typechecker.Typers$Typer.adapt(Typers.scala:1275)
      	at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5370)
      	at scala.tools.nsc.typechecker.Typers$Typer.transformedOrTyped(Typers.scala:5554)
      	at scala.tools.nsc.typechecker.Typers$Typer.typedDefDef(Typers.scala:2307)
      	at scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:5281)
      	at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5352)
      	at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5411)
      	at scala.tools.nsc.typechecker.Typers$Typer.typedPos(Typers.scala:5418)
      	at scala.tools.nsc.transform.ExtensionMethods$Extender$$anonfun$transformStats$1$$anonfun$10$$anonfun$apply$9.apply(ExtensionMethods.scala:260)
      	at scala.tools.nsc.transform.ExtensionMethods$Extender$$a
      

        Activity

        Hide
        Jason Zaugg added a comment -

        Workaround is the explicitly add type argument:

        def synchronize: Observable1[T] = new Observable1[T](foo(asJava))
        
        Show
        Jason Zaugg added a comment - Workaround is the explicitly add type argument: def synchronize: Observable1[T] = new Observable1[T](foo(asJava))
        Hide
        Jason Zaugg added a comment -

        This problem adds to the list of lamentations that comment on adaptMismatchedSkolems.

        In this case our expected type contains a new type parameter (of the extension method), whereas the type of the tree contains an existential skolem still pinned to the corresponding class type parameter.

        tree.tpe         = Observable1#7037[_$1#12344]
        <_$1#12344>.info =  <: T#7040
        
        pt               = Observable1#7037[T#15644]
        
        Show
        Jason Zaugg added a comment - This problem adds to the list of lamentations that comment on adaptMismatchedSkolems . In this case our expected type contains a new type parameter (of the extension method), whereas the type of the tree contains an existential skolem still pinned to the corresponding class type parameter. tree.tpe = Observable1#7037[_$1#12344] <_$1#12344>.info = <: T#7040 pt = Observable1#7037[T#15644]
        Show
        Jason Zaugg added a comment - https://github.com/scala/scala/pull/2916
        Hide
        Samuel Grütter added a comment -

        I've run into a second problem related to this:

        object Test {
          class Observable[+T](val asJava: JObservable[_ <: T]) extends AnyVal {
            private def foo[X](a: JObservable[X]): JObservable[X] = ???
            def window(count: Int): Observable[Observable[T]] = {
              // this line makes the compiler crash (if it's the last line of this method):
              // convert(asJava.window())
              
              // this line gives an error:
              // "type mismatch; found : Test.JObservable[Test.JObservable[_$1]] required: Test.JObservable[Test.JObservable[T]]"
              // convert(asJava.window(): JObservable[JObservable[T]])
              
              // workaround:
              convert(asJava.window().asInstanceOf[JObservable[JObservable[T]]])
            }
          }
          
          class JObservable[T] {
            def window(): JObservable[JObservable[T]] = ???
          }
          
          def convert[T](jObs: JObservable[JObservable[T]]): Observable[Observable[T]] = ???
        }
        

        The only workaround I found was a typecast. Is there a safer workaround?

        Show
        Samuel Grütter added a comment - I've run into a second problem related to this: object Test { class Observable[+T](val asJava: JObservable[_ <: T]) extends AnyVal { private def foo[X](a: JObservable[X]): JObservable[X] = ??? def window(count: Int): Observable[Observable[T]] = { // this line makes the compiler crash (if it's the last line of this method): // convert(asJava.window()) // this line gives an error: // "type mismatch; found : Test.JObservable[Test.JObservable[_$1]] required: Test.JObservable[Test.JObservable[T]]" // convert(asJava.window(): JObservable[JObservable[T]]) // workaround: convert(asJava.window().asInstanceOf[JObservable[JObservable[T]]]) } } class JObservable[T] { def window(): JObservable[JObservable[T]] = ??? } def convert[T](jObs: JObservable[JObservable[T]]): Observable[Observable[T]] = ??? } The only workaround I found was a typecast. Is there a safer workaround?
        Hide
        Jason Zaugg added a comment -

        Here's a workaround that uses a type ascription, rather than a cast:

        cat  sandbox/test.scala
        object Test {
          class Observable[+T](val asJava: JObservable[_ <: T]) extends AnyVal {
            private def foo[X](a: JObservable[X]): JObservable[X] = ???
            def window(count: Int): Observable[Observable[T]] = {
              convert(asJava.window()): Observable[Observable[T]]
            }
          }
        
          class JObservable[T] {
            def window(): JObservable[JObservable[T]] = ???
          }
        
          def convert[T](jObs: JObservable[JObservable[T]]): Observable[Observable[T]] = ???
        }
        topic/2894-rebase ~/code/scala scalac-hash v2.10.2 sandbox/test.scala
        [info] v2.10.2 => /Users/jason/usr/scala-v2.10.2-0-g60d462e
        topic/2894-rebase ~/code/scala
        
        Show
        Jason Zaugg added a comment - Here's a workaround that uses a type ascription, rather than a cast: cat sandbox/test.scala object Test { class Observable[+T](val asJava: JObservable[_ <: T]) extends AnyVal { private def foo[X](a: JObservable[X]): JObservable[X] = ??? def window(count: Int): Observable[Observable[T]] = { convert(asJava.window()): Observable[Observable[T]] } } class JObservable[T] { def window(): JObservable[JObservable[T]] = ??? } def convert[T](jObs: JObservable[JObservable[T]]): Observable[Observable[T]] = ??? } topic/2894-rebase ~/code/scala scalac-hash v2.10.2 sandbox/test.scala [info] v2.10.2 => /Users/jason/usr/scala-v2.10.2-0-g60d462e topic/2894-rebase ~/code/scala
        Hide
        Samuel Grütter added a comment -

        Great thanks! I did not even try this because I thought the return type of the method would have the same effect as this ascription...

        Show
        Samuel Grütter added a comment - Great thanks! I did not even try this because I thought the return type of the method would have the same effect as this ascription...

          People

          • Assignee:
            Jason Zaugg
            Reporter:
            Jason Zaugg
          • Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development