Swift如何消除泛型构造函数的歧义?

时间:2015-07-27 12:14:19

标签: swift parsing generics ambiguity ambiguous-grammar

考虑以下Swift表达式

println(Generic<Foo, Bar>(1))

通常情况下,人们会将其视为对构造函数Generic<Foo, Bar>的通用调用,其参数为(1)

println( Generic<Foo,Bar>(1) )

然而,当重新安排令牌时,它也可能代表两个单独的比较,例如,如果GenericFoo是一些命名不佳的数字变量:

println(Generic < Foo, Bar > (1))
// or, with proper parenthesis
println((Generic < Foo), (Bar > 1))

我们在这里可以观察到,具有这样的通用构造函数的表达式非常模糊,即使对于人类也不容易消除歧义。这里的问题是Swift没有构造函数的new关键字,这使得它们在某些情况下与方法调用和运算符不一致。因此,我感兴趣的是Swift编译器(解析器)如何设法消除上述表达式的歧义。解析依赖于上下文(类型,变量,函数)的方式是否可以解析?

2 个答案:

答案 0 :(得分:1)

答案很简单:编译器根本不允许您声明这些变量:

struct Generic<T, U> {

    init(_ i: Int) {}
}
struct Foo {}
struct Bar {}

print(Generic<Foo, Bar>(1))

// error
let Foo = 0      // invalid redeclaration of Foo
let Bar = 3      // invalid redeclaration of Bar
let Generic = 5  // invalid redeclaration of Generic
print(Generic<Foo, Bar>(1))

在另一个源文件中创建变量或类型声明,当前声明“覆盖”另一个。

答案 1 :(得分:0)

至少有三种方法可以解决这个问题(也许还有更多)。

  1. 结合使用符号表进行解析。当解析器遇到通用类型时,它将被添加到符号表中。当解析器随后遇到通用类型符号时,它将切换为解析通用参数,而不是比较运算符。

  2. 第二个(由JS ++使用并描述了here)是使用GLR解析器并解析两个分支。然后在类型分析阶段,选择通用分析分支。

  3. 任意提前匹配Constructor = Symbol "<" GenericParameters ">" "(" CallParameters ")" .(即>(...)总是 是通用构造函数调用)。

有趣的是,这段代码:

struct A<T, U> {
    init(_ i: Int) {}
}

struct B {}
struct C {}

print(A<B, C>(1))

成功,但此代码:

struct A<T, U> {
    init(_ i: Int) {}
}

struct B {}
struct C {}

print(A<B, C>1)

给出此错误:

error: binary operator '<' cannot be applied to operands of type 'A<_, _>.Type' and 'B.Type'
print(A<B, C>1)
      ~^~

这很有趣,因为它表明Swift使用了第三个选项:任意超前。他们的语法大概是这样的(大大简化了):

Constructor = Symbol "<" GenericParameters ">" "(" CallParameters ")" .
Less = Terminal "<" Terminal .

Expr = Constructor | Less .