Scala宏:“不能从具有未解析的类型参数的类型T创建TypeTag". [英] Scala Macros: "cannot create TypeTag from a type T having unresolved type parameters"

查看:131
本文介绍了Scala宏:“不能从具有未解析的类型参数的类型T创建TypeTag".的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Scalas新宏,并发现要点来自

I'm playing around with Scalas new macros and found this gist from akshaal. As it seams I did not quite get it. Given the following trait (the fieldsMacro is more or less the same as in akshaal example)

case class Field[I <: AnyRef](name: String, get: I => Any)

type Fields[I <: AnyRef] = List[Field[I]]

trait FieldAccess {
import FieldMacors._
    import Field._
    import language.experimental.macros

    def fields[T <: AnyRef]: Fields[T] = macro fieldsMacro[T]

    def field[T <: AnyRef](name: String): Fields[T] = fields[T].headOption <-- does not work!
                                                             ^
}
 object FieldMacors {

import language.experimental.macros
import Field._

def fields[T <: AnyRef]: Fields[T] = macro fieldsMacro[T]

/**
 * Get a list of fiels
 */
def fieldsMacro[T <: AnyRef: c.TypeTag](c: Context): c.Expr[Fields[T]] = {
  import c.universe._
  val instanceT = c.typeOf[T]

  val fields = instanceT.members.filter(member => member.isTerm && !member.isMethod)

  // transform an iterable of expr in a expr of list.
  def foldIntoListExpr[T: c.TypeTag](exprs: Iterable[c.Expr[T]]): c.Expr[List[T]] =
    exprs.foldLeft(reify { Nil: List[T] }) {
      (accumExpr, expr) =>
        reify { expr.splice :: accumExpr.splice }
    }

  val fieldAccessores = for (field <- fields) yield {
    val name = field.name.toString.trim // Why is there a space at the end of field name?!
    val nameExpr = c literal name

    // Construct expression (x : $I) => x.$name
    val getFunArgTree = ValDef(Modifiers(), newTermName("x"), TypeTree(instanceT), EmptyTree)
    val getFunBodyTree = Select(Ident(newTermName("x")), newTermName(name))
    val getFunExpr = c.Expr[T => Any](Function(List(getFunArgTree), getFunBodyTree))
    reify {
      Field[T](name = nameExpr.splice, get = getFunExpr.splice)
    }
  }
  foldIntoListExpr(fieldAccessores)
}
}

编译器抱怨 无法从具有无法解析的类型参数的类型T创建TypeTag"

the compiler complains about 'Cannot create TypeTag from a type T having unresolved type parameters'

我如何设法将T传递给宏,或者必须实现另一个使用fieldsMacro的宏

How do I manage to get the T to the macro or must I implement another macro that uses the fieldsMacro

推荐答案

T: TypeTag为类型参数绑定的上下文T意味着您要求提供代替该参数的类型参数是具体的(即,不包含对未加标签的类型参数或抽象类型成员).否则会发生错误.

T: TypeTag context bound for a type parameter T means that you require type arguments provided in place of this parameter to be concrete (i.e. not contain references to untagged type parameters or abstract type members). Otherwise an error occurs.

示例:

scala> val ru = scala.reflect.runtime.universe
ru @ 6d657803: scala.reflect.api.JavaUniverse = scala.reflect.runtime.JavaUniverse@6d657803

scala> def foo[T: ru.TypeTag] = implicitly[ru.TypeTag[T]]
foo: [T](implicit evidence$1: reflect.runtime.universe.TypeTag[T])reflect.runtime.universe.TypeTag[T]

scala> foo[Int]
res0 @ 7eeb8007: reflect.runtime.universe.TypeTag[Int] = TypeTag[Int]

scala> foo[List[Int]]
res1 @ 7d53ccbe: reflect.runtime.universe.TypeTag[List[Int]] = TypeTag[scala.List[Int]]

scala> def bar[T] = foo[T] // T is not a concrete type here, hence the error
<console>:26: error: No TypeTag available for T
       def bar[T] = foo[T]
                       ^

scala> def bar[T] = foo[List[T]] // T being not concrete renders 
                                 // the entire compound type not concrete
<console>:26: error: No TypeTag available for List[T]
       def bar[T] = foo[List[T]]
                       ^

scala> def bar[T: TypeTag] = foo[T] // to the contrast T is concrete here
                                    // because it's bound by a concrete tag bound
bar: [T](implicit evidence$1: reflect.runtime.universe.TypeTag[T])reflect.runtime.universe.TypeTag[T]

scala> bar[Int]
res2 @ 7eeb8007: reflect.runtime.universe.TypeTag[Int] = TypeTag[Int]

scala> def bar[T: TypeTag] = foo[List[T]]
bar: [T](implicit evidence$1: reflect.runtime.universe.TypeTag[T])reflect.runtime.universe.TypeTag[List[T]]

scala> bar[Int]
res3 @ 1a108c98: reflect.runtime.universe.TypeTag[List[Int]] = TypeTag[scala.List[Int]]

scala> bar[List[Int]]
res4 @ 76d5989c: reflect.runtime.universe.TypeTag[List[List[Int]]] = TypeTag[scala.List[scala.List[Int]]]

具有在编译时可强制执行的具体类型的概念很有用.默认情况下,启用具体类型标签非常有用,如 https://issues.scala所述-lang.org/browse/SI-5884 .

Having a notion of concrete types to be enforcible at compile-time is useful. Having concrete type tags on by default is useful as well as described in https://issues.scala-lang.org/browse/SI-5884.

但是,正如您所看到的那样,宏中的具体类型标记可能会引起混乱,因为通常,宏应同时适用于具体类型和非具体类型.因此,应该始终使用c.AbsTypeTag代替.由于这个原因,我们不再允许在2.10.0-M7中使用c.TypeTag上下文范围: https://github.com/scala/scala/commit/788478d3ab .

However as you've seen yourself, concrete type tags in macros can be a source of confusion, because typically macros should work both for concrete and non-concrete types. Therefore one should always use c.AbsTypeTag instead. Due to this reason we no longer allow c.TypeTag context bounds in 2.10.0-M7: https://github.com/scala/scala/commit/788478d3ab.

修改.在2.10.0-RC1中,某些AbsTypeTag已重命名为WeakTypeTag.关于类型标签的其他所有内容都保持不变.

Edit. In 2.10.0-RC1 some AbsTypeTag has been renamed to WeakTypeTag. Everything else about type tags remains the same.

这篇关于Scala宏:“不能从具有未解析的类型参数的类型T创建TypeTag".的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆