4

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

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]]]

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

4

2 回答 2

3

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

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

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

LEdge[MyStuff] >: MyEdge[MyStuff]

我不确定在字节码级别,它是否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 已经告诉过)......在运行时做了什么,我不知道!

需要注意的Manifest是,在 scala 2.9 之后已弃用;所以你可能更喜欢TypeTag[T]按照 scaladoc 中的描述使用。

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

希望对您有所帮助...

于 2013-09-09T17:33:24.953 回答
3

正如其他人所建议的那样,问题来自

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

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

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 { ... }的类型表达式称为精炼类型。根据语言规范,精炼类型的清单只是其基类的清单。但是,这无法进行类型检查,因为您要求 a 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' 生成清单。(也就是说,细化永远不会反映在清单中)。

于 2013-09-15T01:47:07.383 回答