milessabin / macro-compat

macro-compat is a small library which allows you to compile macros with Scala 2.10.x which are written to the Scala 2.11/2 macro API.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Consider if type is existential when calling dealias?

dwijnand opened this issue · comments

Currently Type#dealias is defined as an alias for normalize: [1]

But according to Shapeless for Scala 2.10, it should consider if the type is existential: [2]

Should the definition here of dealias take that into account?

Good spot. Yes, semantics of dealias in 2.11.x aren't quite the same as normalize in 2.10.x. I'll ask on scala/contributors ...

Yes, that's related IIRC.

See discussion here. @retronym is suggesting,

def dealias(t: Type) = t match {
  case _ if t.takesTypeArgs => t
  case _ : RefinedType => t
  case _ => t.normalize
}

We could also try with and without a special case for ExistentialType.

More evidence that dealias (and typeArgs) needs tweaking with regards to ExistentialType:

    // Doesn't work, bug in macro-compat
//  val dealiased = tpe.dealias
    val dealiased = tpe match {
      case existential: ExistentialType => existential
      case other => other.normalize
    }
    dealiased match {
...
      case ExistentialType(quantified, underlying) =>
        // Doesn't work, bug in macro-compat
    //  val tArgs = dealiased.typeArgs
        val TypeRef(_, _, tArgs0) = underlying
        val tArgs = tArgs0.map { tpe => if(tpe.typeSymbol.asType.isExistential) typeOf[Any] else tpe }
...

For more context, those are taken from trying to migrate the Scala 2.10 variant of Shapeless' TypeableMacros, and the failure is that the test code in core/src/test/scala/shapeless/typeable.scala doesn't compile (if I recall correctly the error was "can't find Typeable instance for this type")

[error] /Users/dnw/dev/shapeless-2.10/core/src/test/scala/shapeless/typeable.scala:367: could not find implicit value for parameter castU: shapeless.Typeable[Either[Int, _]]
[error]     val cei3 = ei.cast[Either[Int, _]]
[error]                       ^
[error] /Users/dnw/dev/shapeless-2.10/core/src/test/scala/shapeless/typeable.scala:380: could not find implicit value for parameter castU: shapeless.Typeable[Either[_, String]]
[error]     val ces3 = es.cast[Either[_, String]]
[error]                       ^
[error] two errors found

I tried a bunch of different combinations, both in here and in combination with different .typeArgs implementation.

I have no idea, I've just special-cased the two instances I found:

https://github.com/milessabin/shapeless/blob/495e275c144e907cc636dc612bc293c80af3ecce/core/src/main/scala_2.10/shapeless/compat.scala#L81-L96

I don't see a point in continuing to keep this issue open.

I'm going to reopen this because I'd like to take another look. Can you say what you tried as implementations of dealias and typeArgs? Did you go as far as copy/pasting the 2.11.x definitions into macro-compat?

👍

I tried different combinations (merges) of possible definitions of Type#dealias between

val dealiased = tpe match {
  case existential: ExistentialType => existential
  case other => other.normalize
}

and

def dealias(t: Type) = t match {
  case _ if t.takesTypeArgs => t
  case _ : RefinedType => t
  case _ => t.normalize
}

that @retronym recommended, in combinations with possible definitions of Type#typeArgs between

def typeArgs: List[Type] = tpe match {
  case TypeRef(_, _, args) => args
  case _ => Nil
}

and

def typeArgs: List[Type] = tpe match {
  case TypeRef(_, _, args) => args.map { tpe => if(tpe.typeSymbol.asType.isExistential) typeOf[Any] else tpe }
  case _ => Nil
}

and something somewhere (sorry it was a little while ago) broke in shapeless' build.

Thanks ... I'll try the copy/paste from 2.11.x approach :-)

Fixed in 5bbf257.

Very cool, thank you.

Possibly a bit hasty. Back in shapeless dealias is looking good, but typeArgs isn't quite the same.

Done :-)