2017-02-04 9 views
0

У меня есть некоторые проблемы с макросами scala и идентификацией реализованного типа конструктора. Не уверен, что я делаю что-то неправильно здесь или что будет правильным вызовом. Из документации, похоже, typeSignatureIn должен возвращать правильную информацию, например. ClassTag [Int], но когда я запускаю макрос, я фактически получаю ClassTag [U], который не может скомпилироваться, поскольку U является параметром типа, а не реализованным типом.Получение реализованного типа для класса Scala с использованием макросов

import scala.language.experimental.macros 
import scala.reflect.ClassTag 
import scala.reflect.macros.Context 

def macroImpl[T: c.WeakTypeTag](c: Context) = { 
    import c.universe._ 

    val typeToMock = weakTypeOf[T] 

    val primaryConstructorOpt = typeToMock.members.collectFirst { 
    case method: MethodSymbolApi if method.isPrimaryConstructor => method 
    } 

    val constructorArgumentsTypes = primaryConstructorOpt.map { 
    constructor => 
    val constructorTypeContext = constructor.typeSignatureIn(typeToMock) 
    val constructorArguments = constructor.paramss 
    constructorArguments.map { symbols => 
     symbols.map(_.typeSignatureIn(constructorTypeContext)) 
    } 
    } 

    println(typeToMock) 
    println(constructorArgumentsTypes) 

    c.literalUnit 
} 

def foo[T] = macro macroImpl[T] 

class Foo[U: ClassTag] 

foo[Foo[Int]] 

запустить его:

scala> foo[Foo[Int]] 
Foo[Int] 
Some(List(List(), List(scala.reflect.ClassTag[U])) 

Мне нужно, чтобы получить ClassTag [Int] каким-то образом, чтобы иметь возможность генерировать правильный дерево позже, какие-то идеи?

ответ

0

Попробуйте использовать dealias в каждом месте, где вы разрешаете тип. Scala сохраняет ссылки на месте, даже когда она знает, к чему они относятся. dealias получает копию (?) Типа, в котором ссылки заменены.

Вы также должны выбрать либо черный ящик, либо белые макросы, а не только scala.reflect.macros.Context.

Это похоже на работу:

import scala.language.experimental.macros 
import scala.reflect.ClassTag 
import scala.reflect.macros.whitebox.Context 

def macroImpl[T: c.WeakTypeTag](c: Context) = { 
    import c.universe._ 

    val typeToMock = weakTypeOf[T].dealias 

    val primaryConstructorOpt = typeToMock.members.collectFirst { 
    case method: MethodSymbolApi if method.isPrimaryConstructor => method 
    } 

    val constructorArgumentsTypes = primaryConstructorOpt.map { constructor => 
    val constructorTypeContext = constructor.typeSignatureIn(typeToMock).dealias 
    val constructorArguments = constructorTypeContext.paramLists 
    constructorArguments.map { symbols => 
     symbols.map(_.typeSignatureIn(constructorTypeContext).dealias) 
    } 
    } 

    println(typeToMock) 
    println(constructorArgumentsTypes) 

    q"()" 
} 

def foo[T]: Any = macro macroImpl[T] 

class Foo[U: ClassTag] 

foo[Foo[Int]] 

Результат

Foo[Int] 
Some(List(List(), List(scala.reflect.ClassTag[Int]))) 
+0

большое спасибо. Все еще изо всех сил пытаюсь интегрировать это в более широкую кодовую базу, но это дало мне хорошее руководство для того, –

 Смежные вопросы

  • Нет связанных вопросов^_^