清单和抽象类型分辨率

时间:2013-09-06 11:47:07

标签: scala compiler-construction

当编译器需要为具有抽象类型参数的类解析清单时,我遇到了编译器问题。以下代码段显示了问题

trait MyStuff

trait SecurityMutatorFactory[X]{
  def apply(x1:X,x2:X)
}

object Example{

  trait LEdge[N]
  {
    type L1
  }
  type MyEdge[X] = LEdge[X] { type L1 = SecurityMutatorFactory[X]}

  val a:Manifest[MyEdge[MyStuff]] = implicitly[Manifest[MyEdge[MyStuff]]]

}

结果,编译器抛出以下类型错误:

type mismatch;
 found   : scala.reflect.Manifest[LEdge[MyStuff]]
 required: Manifest[MyEdge[MyStuff]]
Note: LEdge[MyStuff] >: MyEdge[MyStuff], but trait Manifest is invariant in type T.
You may wish to investigate a wildcard type such as `_ >: MyEdge[MyStuff]`. (SLS 3.2.10)
  val a:Manifest[MyEdge[MyStuff]] = implicitly[Manifest[MyEdge[MyStuff]]]

编译器级别发生了什么? ^

2 个答案:

答案 0 :(得分:3)

好吧,我对这种模式并不熟悉:

type MyEdge[X] = LEdge[X] { type L1 = SecurityMutatorFactory[X]}

但我倾向于将使用type关键字定义的类型视为别名(概念),而不是对实施的保证(编辑更确切地说,我相信type在原型设计/指定方面提供了保证,但是在实际需要用它所基于的特征/类替换别名之前,不会生成AST /代码。因此,即使编译器在其错误消息中声明:

LEdge[MyStuff] >: MyEdge[MyStuff]

我不确定在字节码级别它是否相应地使用interfaces / methods / etc实现MyEdge。因此,它可能无法识别LEdge和MyEdge之间的通缉关系,最终:

found   : scala.reflect.Manifest[LEdge[MyStuff]]
required: Manifest[MyEdge[MyStuff]]

(并且,是否缺少包scala.reflect.提示?(1)

关于您的代码,您如何使用a?无论如何,如果以下是您的意图,请使用:

trait MyEdge[X] extends LEdge[X] {
   type L1 = SecurityMutatorFactory[X]
}

相反,它确实编译(scala 2.10)...(编辑我刚才注意到dmitry已经告诉过了)...在运行时我做了什么,我不知道!< / p>

作为一个值得注意的项目,在{2}之后不推荐使用Manifest;因此您可能更喜欢使用scaladoc中描述的TypeTag[T]

修改
(1)我怀疑发生以下情况:
- 在句法分析阶段,编译器将字面注册为您指定的内容,即implicitly方法将返回 a Manifest[MyEdge[MyStuff]]
- 通过代码生成阶段,别名“协调”到最近的类或特征;在implicitly的情况下,结果的类型Manifest[MyEdge[MyStuff]]变为特征scala.reflect.Manifest[LEdge[MyStuff]]]
- 由于Manifest中涉及的类型推断的某些限制以及类型参数中的类型“别名”,但是,某些指定的要求Manifest[MyEdge[MyStuff]]仍然保持其原始形状
- (这是纯粹的猜想,因为我没有读过这个答案的Scala编译器源代码)编译器一方面会有正确的AST /代码,但是一个方法原型/规范仍然在它的raw / literal下另一方面是形状;这不适合它会发出错误。

希望有帮助...

答案 1 :(得分:3)

正如其他人所说,问题来自

type MyEdge[X] = LEdge[X] { type L1 = SecurityMutatorFactory[X] }

type F[X] = ...形式的声明引入了类型同义词,即现有类型的新名称。他们不构建新的特征或类。但是,LEdge[X] { type L1 = SecurityMutatorFactory[X] }正在构建一个新的匿名类。所以你的例子是 approxlly 等同于

trait MyEdge[X] extends LEdge[X] { type L1 = SecurityMutatorFactory[X] }

(这是您最想要的)但示例中的原始定义是定义匿名类的同义词,而不是定义新类MyEdge[X]。因此,在示例中,新类实际上不会被称为MyEdge。构造隐式清单时,编译器将类型同义词替换为基础类型,但无法为其构造清单,因为该类型是匿名的。

用正常的扩展名定义替换MyEdge声明:

trait MyEdge[X] extends LEdge[X] { type L1 = SecurityMutatorFactory[X] }

或与普通类型同义词:

type MyEdge[X] = LEdge[X]

都成功编译。

修改

以下是为匿名类生成隐式清单失败的具体原因。 在语言规范类型中,BaseType { ... }形式的经历被称为精炼类型。 根据语言规范,精炼类型的清单只是其基类的清单。然而,这无法进行类型检查,因为您要求Manifest[LEdge[MyStuff]{ type L1 = SecurityMutatorFactory[X] }],但算法返回Manifest[LEdge[MyStuff]]。这意味着您只能在逆变位置中为具有细化类型的类型构造隐式清单。例如使用:

type MyEdge[X] = LEdge[X] { type L1 = SecurityMutatorFactory[X] } => AnyRef
在你的例子中,

允许它编译,虽然它显然不是你所追求的。

构造隐式清单的完整算法在语言规范的7.5节末尾给出。第6条涵盖了这个问题:

  

6)如果T是精化类型T'{R},则为T'生成清单。 (也就是说,改进从未在清单中反映出来。)