Search code examples
scalapath-dependent-typetype-projection

Scala type projection: pick an object within a path-dependent trait


I have a path-dependent trait declaring several modules. That is fine. However, I write a macro and I need to access those inner types and I am unable to write a proper expression selecting them.

trait A {

  type Foo

  object module { // one  of modules encapsulating functionality

     class Bar // I use it as an annotation depending on Foo but that is irrelevant
  }

  class Other
}

Now I need to write a proper type expression selecting the Bar class to retrieve its weakTypeTag. I am able to write weakTypeOf[ A#Other ] to select the Other class. But when I try to select Bar it does not work. I tried:

  • A#module.Bar
  • A#module#Bar
  • A#module.type.Bar
  • A#module.type#Bar

All these fail at the module selection.

Why do not these work and how make them working? Thanks.


Solution

  • module is an object inside A, (it depends on instance of A), so this object A should be reflected in its type signature:

    scala> typeOf[a.module.type forSome { val a: A }]
    res1: reflect.runtime.universe.Type = a.module.type forSome { val a: A }
    

    you can see this by creating alias Inner inside of trait A

    trait A {
      type Inner = module.type // it is actually this.module.type, where this refers to the instance of A
      object module {
        class Bar
      }
    }
    

    now we can check that these two types are equivalent:

    scala> typeOf[A#Inner]
    res2: reflect.runtime.universe.Type = _8.module.type forSome { val _8: A }
    
    scala> res1 =:= res2
    res3: Boolean = true
    

    Finally, to access innermost Bar, we need to add appropriate projection:

    scala> implicitly[(a.module.type forSome { val a: A })#Bar =:= A#Inner#Bar]
    res4: =:=[a.module.Bar,_38.module.Bar] = <function1>