我了解 Editions 的目标以及如何使用它们,但文档并没有说明它们的内部工作原理。
假设我有两个源文件:
old.rs,针对 Rust 2015;
new.rs,针对 Rust 2018。
我想构建一个同时使用它们的应用程序。正在使用什么机制来确保它们可以互操作?
两者都做old.rs,并new.rs会转换为相同型号HIR?或者均质化发生在此之前(例如 AST 水平)还是之后(例如 MIR 水平)?
版本只影响语法,不会改变编译器编译代码的方式。解析器几乎是编译器唯一的版本感知组件,通过对版本进行一些检查来决定如何解析内容。两个版本的 AST 是相同的,尽管 spans 知道它们的版本,并且编译器中的一些东西会检查它们使用的是哪个版本。HIR 和 MIR 不需要知道版本。
例如。对于新关键字:
/// Returns `true` if the token is a keyword used in the language.
pub fn is_used_keyword(self) -> bool {
// Note: `span.edition()` is relatively expensive, don't call it unless necessary.
self.name >= kw::As && self.name <= kw::While ||
self.name.is_used_keyword_2018() && self.span.rust_2018()
}
Run Code Online (Sandbox Code Playgroud)
额外self.name.is_used_keyword_2018() && self.span.rust_2018()会检查该关键字是否是2018版中添加的关键字(例如dyn),对于2015,它将被视为常规符号。
另一个例子是在 2015 年,可以在 trait 声明中省略参数名称,现在是禁止的。这也是透明处理的:
// We don't allow argument names to be left off in edition 2018.
let is_name_required = p.token.span.rust_2018();
p.parse_arg_general(true, false, |_| is_name_required)
Run Code Online (Sandbox Code Playgroud)
在这种情况下,另一段代码将发出错误,但仅限于 2018:
if require_name && (
is_trait_item ||
self.token == token::Comma ||
self.token == token::CloseDelim(token::Paren)
) { // `fn foo(a, b) {}` or `fn foo(usize, usize) {}`
err.span_suggestion(
pat.span,
"if this was a parameter name, give it a type",
format!("{}: TypeName", ident),
Applicability::HasPlaceholders,
);
err.span_suggestion(
pat.span,
"if this is a type, explicitly ignore the parameter name",
format!("_: {}", ident),
Applicability::MachineApplicable,
);
err.note("anonymous parameters are removed in the 2018 edition (see RFC 1685)");
return Some(ident);
}
Run Code Online (Sandbox Code Playgroud)
对于 2015 年,创建了一个虚拟名称:
let ident = Ident::new(kw::Invalid, self.prev_span);
let pat = P(Pat {
id: ast::DUMMY_NODE_ID,
node: PatKind::Ident(
BindingMode::ByValue(Mutability::Immutable), ident, None),
span: ty.span,
});
Run Code Online (Sandbox Code Playgroud)
编译器的其余部分不需要知道用户是否实际提供了名称。
| 归档时间: |
|
| 查看次数: |
265 次 |
| 最近记录: |