rust - 允许针对不同版本的源代码互操作的确切机制是什么?
问题描述
我了解 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()
}
extraself.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)
然后在这种情况下,另一段代码将发出错误,但仅适用于 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);
}
而对于 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,
});
编译器的其余部分不需要知道用户是否实际提供了名称。
推荐阅读
- c - 在 VMX 中启用 EPT 导致由于来宾状态而无法进入
- sql - Create Table as Select 正在更改某些数据类型
- css - 弹性盒需要宽度才能正确调整大小
- url-rewriting - 仅重写 url 并保持在同一页面上
- javascript - 使用 jQuery 更新 dom 而不是追加
- javascript - 后台脚本打开 URL 后如何等待内容脚本侦听器加载?
- javascript - 如何使用服务帐户和 Google Drive API 解决 403 错误
- ios - 查找当前位置与另一个位置之间的距离(Swift 5)
- python - 在三维 Pandas 数据框中随时间回归
- javascript - 谷歌地图信息窗口中按钮的点击事件