Java规范中的方法类型推断

8
我目前正在编写一个Java编译器,并实现了JLS7规范的第15.12.2.7节(http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.2.7),这是规范中最烦人的部分之一。然而,我仍然有一个问题,因为规范似乎有点不够明确或模棱两可。我的问题是以下这行代码: lcta(U) = ? if U's upper bound is Object, otherwise ? extends lub(U,Object)
U是任意类型表达式。类型表达式的上限是什么?此外,为什么lcta总是通配符?
规范定义了
CandidateInvocation(G) = lci(Inv(G))。
例如,考虑Inv(G) = { List<String> }的情况,即唯一可能的候选调用是单个参数化类型。由于规则的缘故,

lci(G<X1, ..., Xn>) = G<lcta(X1), ..., lcta(Xn)>

候选调用的结果为CandidateInvocation(G) = lci({List<String>}),其定义如下:

List<lcta(String)>

在我看来,lcta应该只返回字符串String,因为如果List<String>是唯一可能的调用方式,那么推断List<String>作为参数是一个好主意。然而,lcta(U)的定义规定结果要么是?,要么是? extends lub(...),因此结果始终是通配符。这似乎很奇怪。我在这里误解了什么吗?

2个回答

6
这看起来像是规范的错误。JSL3中不存在lcta(U)的条款。显然,当n=1时,JLS3对lci(e1..en)的定义不完整,新规范试图修复它。但是,正如你推理出的那样,修复似乎是胡言乱语。
Javac7将{ List<String> }计算为List<String>,忽略了添加的条款。
这个问题应该提给规范维护者;不确定如何联系他们。您可以尝试openjdk compiler-dev邮件列表;里面有一些知识渊博的人。

我现在已经实现了lcta(U) = U,看起来工作得很好。如果我发现这个实现产生了令人惊讶的结果,我会报告的。顺便说一句:由于Object始终是U的超类,因此lub(U,Object)不是总是U吗?因此,规则真的是完全无用的。它唯一可能有用的事情就是将? extends Object转换为?。但是,由于U是一个类型表达式,它不能包含通配符,因此这种情况可能永远不会出现...真奇怪。 - gexicide
和邮件列表的好主意,我想我会在那里尝试一下。 - gexicide
lub = 最小上界。我认为任何类型都应该比对象“低”,即“小”。否则,调用lub(U,Object)将更加愚蠢,因为它可以简单地被替换为Object。 - gexicide

1
我在编译器开发邮件列表中提出了问题,并得到了回答:
是的,规范在这里是错误的。lcta(U)的规则非常糟糕 :)。此外,他们声称,对于单个参数,最好根本不要调用lcta(U),而只是使用U(因为单个参数U的最小公共类型参数应始终是U本身)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接