在编译过程中何时/何地进行类型检查

Lan*_*ard 3 ruby compiler-construction jit haskell typechecking

在编译过程中(在高级别)通常发生类型检查(教科书与实践中)时,在高级别想知道.我对编译过程的理解大致是:

  1. 将源代码解析为AST
  2. 将AST转换为中间表示IR
  3. 优化IR(即SSA表格,注册分配等)
  4. 简化IR
  5. 生成最终输出代码

想知道是否在(1)和(2),(2)和(3)之间,或者在(4)之间发生了类型检查,或者它是否在整个过程中发生,或者其他什么.我有兴趣知道面向对象,功能和逻辑编程的答案(按照优先级顺序),但如果我必须选择一个OO,如Ruby之类的动态类型语言,或者像静态类型的函数语言那样哈斯克尔.

sep*_*p2k 7

静态类型检查通常在AST上执行,因此它发生在1和2之间或作为2的一部分(意味着IR发生器在处理AST节点时调用类型检查器的函数 - 当然是IR发生器和类型检查器应该仍然存在于不同的模块/文件中).

理论上,您可以对IR执行类型检查,但这通常会导致以下至少一个问题:

  1. IR不包含足够的信息来捕获您想要的所有错误.
  2. IR在所有情况下都不包含足够的信息来生成最佳错误消息.作为一个例子,考虑IR表示使用相同指令的数组访问和指针算术.现在,您希望为具有浮点索引的数组访问生成错误.如果消息是"浮点值不允许作为指针算术的操作数",那么当代码不包含任何指针算术时会令人困惑.要求用户知道数组访问被表示为指针算术以理解错误消息,将不是非常用户友好的.
  3. 为了类型检查的目的,你向IR添加了大量的额外信息,使IR变得更加复杂和笨拙,但你从中获得的就是能够以与AST相同的方式处理IR. ,没有获得任何好处.

通常使用IR而不是AST意味着您不必处理尽可能多的情况(完全是因为IR使用相同的指令表示不同的事物).这是主要的好处.但是如果你为了能够以不同的方式再次处理这些情况而跳过额外的箍,你也可以首先使用AST.

因此,通常首选对AST¹进行类型检查.GHC(主要的Haskell编译器)执行AST的类型检查.

¹或至少与AST非常接近的东西 - 例如,可能是AST和最终IR之间的表示,它以某种方式简化了事物(例如删除扁平嵌套表达式),而不会丢失与类型检查相关的信息.


动态类型检查在运行时发生.执行这些动态类型检查的代码是解释器的一部分(如果有解释器)或由代码生成器插入.

Ruby在解释器中执行类型检查.