2

I have the following function defined:

import org.apache.spark.sql.catalyst.{ScalaReflection}

import ScalaReflection.universe
import universe.TypeTag

def scalaTypesFor(dataType: DataType): Set[TypeTag[_]] = ...

def scalaTypeOpt: Option[TypeTag[_]] = ...

val catalystType = ...
scalaTypeOpt.map(v => Set(v))
      .getOrElse{
        val default = scalaTypesFor(catalystType)
        default
      }

in this case, both scalaTypesFor and scalaTypeOpt are expected to yield a TypeTag with wildcard parameter, they should be of the same type. However, the compiler gave me the following error:

Error:(29, 51) inferred type arguments [scala.collection.immutable.Set[_117] forSome { type _$2; type _117 >: org.apache.spark.sql.catalyst.ScalaReflection.universe.TypeTag[_$2] <: org.apache.spark.sql.catalyst.ScalaReflection.universe.TypeTag[_] }] do not conform to method getOrElse's type parameter bounds [B >: scala.collection.immutable.Set[org.apache.spark.sql.catalyst.ScalaReflection.universe.TypeTag[_$2]] forSome { type _$2 }]
    val effective = scalaTypeOpt.map(v => Set(v)).getOrElse{
                                                  ^

What's wrong with the type inference and how to fix it?

tribbloid
  • 4,026
  • 14
  • 64
  • 103

1 Answers1

2

I think the issue is that you have two unknown types _ and there's no guarantee that they are compatible. Also immutable Sets in scala are incorrectly invariant (before people start commenting, there have been many discussions and the very final word on this is that, indeed, there is no truly fundamental reason for them NOT to be covariant) so that tends to produce annoying typing issues as well.

Don't have a compiler around to test but you could try a few things

  1. (unlikely to work) ascribe the type of Set as Set[TypeTag[_]](v)
  2. change your code so you allow the compiler to capture the unknown type and prove to itself that it's the same one as such:

    def scalaTypesFor[T](dataType: DataType): Set[TypeTag[T]] = ???
    
    def scalaTypeOpt[T]: Option[TypeTag[T]] = ???
    
    def xform[T] = {
       val catalystType = ???
       scalaTypeOpt[T].map(v => Set(v))
          .getOrElse{
           val default = scalaTypesFor[T](catalystType)
           default
         }
     }
    

or if you can make them local defs

    def xform[T] = {
       def scalaTypesFor(dataType: DataType): Set[TypeTag[T]] = ???
       def scalaTypeOpt: Option[TypeTag[T]] = ???

       val catalystType = ???
       scalaTypeOpt.map(v => Set(v))
          .getOrElse{
           val default = scalaTypesFor(catalystType)
           default
         }
     }
Creos
  • 2,445
  • 3
  • 27
  • 45