2016-12-04 4 views
2

가장 아래에 설명 된 펑키 시나리오의 비트 내부 객체 회원의 루트 형의 형태 인수를 가져옵니다.스칼라 매크로 : 클래스 정의

sealed trait Painting[T]이 있고 그 다음에 trait ImpressionistPainting[T] extends Painting[T] 등과 같이 더 특수화 된 유사 콘텐츠가 있다고 가정하면 간단한 밀폐 유형 제품군을 구축 할 수 있습니다.

class Gallery[T <: Gallery[T]]()(implicit helper: GalleryHelper[T]) 

그리고 :

trait GalleryHelper[T <: Gallery[T]] { 
    def paintings: Set[Painting[_]] 
} 
object GalleryHelper { 
    implicit def materialize[T <: Gallery[T]]: GalleyHelper[T] = { 
    macro MyMacro.materialize[T] 
    } 

    def apply[T <: Gallery[T]]()(
    implicit ev: GalleryHelper[T] 
): GalleryHelper[T] = ev 
} 

지금까지 아주 기본적이고 간단 foo는 바 코드

나는 다음 F와 클래스 다형성과 같은 바인딩 유형을 경계해야합니다.

매크로 같은, 내가 갤러리를 설명하거나 임의의 "사용자 콘텐츠"입력이 경우에해야 할 항목의 도우미 목록을 구체화에이 설정의 전체 목표는 :

class MyGallery extends Gallery[MyGallery] { 
    object `le-reve` extends CubistPainting[Picasso] 
    object starry_night extends PostImpressionistPainting[VanGogh] 
    // .. 
} 

을 이제와 나는 매크로 원하는 일부 매크로의 compat 재미는 문제의 도우미를 실현하고 MemberType <:< Painting[_]을있는 사람들을 추출 T <: Gallery[T]의 멤버를 필터링 할 수 있습니다.

모두 매우 간단합니다. 아래에 표시된 것은 상속 된 모든 멤버의 목록을 작성된 순서대로 반환해야하기 때문에 간단히 type.decls.filter(_.typeSignature <:< typeOf[Filter]보다 복잡합니다. 주어진 갤러리는 다른 갤러리를 확장합니다.

def findMembersWithBound[T : WeakTypeTag, Filter : TypeTag](
    exclusions: Symbol => Option[Symbol] = { s: Symbol => Some(s) } 
): Set[Symbol] = { 
    val tpe = weakTypeOf[T].typeSymbol.typeSignature 

    (
     for { 
     baseClass <- tpe.baseClasses.reverse.flatMap(exclusions(_)) 
     symbol <- baseClass.typeSignature.members.sorted 
     if symbol.typeSignature <:< typeOf[Filter] 
     } yield symbol 
    )(collection.breakOut) 
    } 

그래서 암시 매크로, 타입 T에 대한 모듈 멤버의 기본 탐색이 경우 Painting[_]에, 하위 유형별로 필터링 할 필요가 다음 사용자 경우가 제공하는 어떤 특정 유형의 인수를 보면 변형 유형은 Painting입니다. 이것은 어떤 식 으로든 관련이 경우 사용자가 직접 objectPainting[_]Painting의 하위 클래스를 결코 확장하지 않도록 유형 제품군은 밀봉된다.

@macrocompat.bundle 
class MyMacro(val c: blackbox.Context) { 
    import c.universe._ 
    def materialize[T <: Gallery[T]]: Tree = { 
    val galleryTpe = weakTypeOf[T] 
    val fields = findMembersWithBound[T, Painting[_]](exclusions) 

    val colMembers = sourceMembers.map { member => 
     val memberType = member.typeSignatureIn(galleryTpe) 

     memberType.baseClasses.find(colSymbol ==) match { 
     case Some(root) => { 
      // Herein lies the problem, typeArgs is Nil. 
      root.typeSignatureIn(memberType).typeArgs.headOption match { 
      case Some(colSignature) => colSignature 
      case None => c.abort(
       c.enclosingPosition, 
       s"Could not find the artist for ${member.asModule.name}" 
     ) 
     } 
     } 
     case None => c.abort(c.enclosingPosition, s"Could not find root painting type for ${member.asModule.name}") 
    } 
    } 
} 

문제는 Painting로 전달 원래의 형태 인수 중 어느 것도 typeSignature가 범위 등을 평가하는 apper 것에도 불구하고, 더 이상 볼 수없고, 단순히 확인 반을 만들기 위해 노력하고 있다는 것입니다 고흐는 유명한 월도가되지 않습니다.

그러나 다른 dealias 나에 대한 올바른 API는 다시 그 typeArgs 볼 수 있도록 무엇입니까? 현재 비어있는 목록입니다.

답변

2

확인은 asSeenFrom를 사용하여이 작업을 수행 할 수있는 "잘 숨겨"방법이 밝혀졌습니다. 관련 부분은 다음과 같습니다

root.typeSignature.typeParams match { 
    case head :: Nil => head.asType.toType.asSeenFrom(memberType, colSymbol) 
    case _ => c.abort(
    c.enclosingPosition, 
    "Expected exactly one type parameter provided for painting type" 
) 
}