Skip to content

Commit f756d61

Browse files
authored
Rework the driver docs (#2162)
1 parent 1fe9814 commit f756d61

7 files changed

+272
-198
lines changed

Diff for: examples/rustc-driver-example.rs

+74-74
Original file line numberDiff line numberDiff line change
@@ -1,92 +1,92 @@
11
#![feature(rustc_private)]
22

3+
extern crate rustc_ast;
4+
extern crate rustc_ast_pretty;
5+
extern crate rustc_data_structures;
36
extern crate rustc_driver;
47
extern crate rustc_error_codes;
58
extern crate rustc_errors;
69
extern crate rustc_hash;
710
extern crate rustc_hir;
811
extern crate rustc_interface;
12+
extern crate rustc_middle;
913
extern crate rustc_session;
1014
extern crate rustc_span;
1115

12-
use std::{path, process, str, sync::Arc};
16+
use std::io;
17+
use std::path::Path;
1318

14-
use rustc_errors::registry;
15-
use rustc_hash::FxHashMap;
16-
use rustc_session::config;
19+
use rustc_ast_pretty::pprust::item_to_string;
20+
use rustc_data_structures::sync::Lrc;
21+
use rustc_driver::{Compilation, RunCompiler};
22+
use rustc_interface::interface::Compiler;
23+
use rustc_middle::ty::TyCtxt;
1724

25+
struct MyFileLoader;
26+
27+
impl rustc_span::source_map::FileLoader for MyFileLoader {
28+
fn file_exists(&self, path: &Path) -> bool {
29+
path == Path::new("main.rs")
30+
}
31+
32+
fn read_file(&self, path: &Path) -> io::Result<String> {
33+
if path == Path::new("main.rs") {
34+
Ok(r#"
1835
fn main() {
19-
let out = process::Command::new("rustc")
20-
.arg("--print=sysroot")
21-
.current_dir(".")
22-
.output()
23-
.unwrap();
24-
let sysroot = str::from_utf8(&out.stdout).unwrap().trim();
25-
let config = rustc_interface::Config {
26-
// Command line options
27-
opts: config::Options {
28-
maybe_sysroot: Some(path::PathBuf::from(sysroot)),
29-
..config::Options::default()
30-
},
31-
// cfg! configuration in addition to the default ones
32-
crate_cfg: Vec::new(), // FxHashSet<(String, Option<String>)>
33-
crate_check_cfg: Vec::new(), // CheckCfg
34-
input: config::Input::Str {
35-
name: rustc_span::FileName::Custom("main.rs".into()),
36-
input: r#"
37-
static HELLO: &str = "Hello, world!";
38-
fn main() {
39-
println!("{HELLO}");
36+
let message = "Hello, World!";
37+
println!("{message}");
4038
}
4139
"#
42-
.into(),
43-
},
44-
output_dir: None, // Option<PathBuf>
45-
output_file: None, // Option<PathBuf>
46-
file_loader: None, // Option<Box<dyn FileLoader + Send + Sync>>
47-
locale_resources: rustc_driver::DEFAULT_LOCALE_RESOURCES,
48-
lint_caps: FxHashMap::default(), // FxHashMap<lint::LintId, lint::Level>
49-
// This is a callback from the driver that is called when [`ParseSess`] is created.
50-
psess_created: None, //Option<Box<dyn FnOnce(&mut ParseSess) + Send>>
51-
// This is a callback from the driver that is called when we're registering lints;
52-
// it is called during plugin registration when we have the LintStore in a non-shared state.
53-
//
54-
// Note that if you find a Some here you probably want to call that function in the new
55-
// function being registered.
56-
register_lints: None, // Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>
57-
// This is a callback from the driver that is called just after we have populated
58-
// the list of queries.
59-
//
60-
// The second parameter is local providers and the third parameter is external providers.
61-
override_queries: None, // Option<fn(&Session, &mut ty::query::Providers<'_>, &mut ty::query::Providers<'_>)>
62-
// Registry of diagnostics codes.
63-
registry: registry::Registry::new(rustc_errors::codes::DIAGNOSTICS),
64-
make_codegen_backend: None,
65-
expanded_args: Vec::new(),
66-
ice_file: None,
67-
hash_untracked_state: None,
68-
using_internal_features: Arc::default(),
69-
};
70-
rustc_interface::run_compiler(config, |compiler| {
71-
compiler.enter(|queries| {
72-
// Parse the program and print the syntax tree.
73-
let parse = queries.parse().unwrap().get_mut().clone();
74-
println!("{parse:?}");
75-
// Analyze the program and inspect the types of definitions.
76-
queries.global_ctxt().unwrap().enter(|tcx| {
77-
for id in tcx.hir().items() {
78-
let hir = tcx.hir();
79-
let item = hir.item(id);
80-
match item.kind {
81-
rustc_hir::ItemKind::Static(_, _, _) | rustc_hir::ItemKind::Fn(_, _, _) => {
82-
let name = item.ident;
83-
let ty = tcx.type_of(item.hir_id().owner.def_id);
84-
println!("{name:?}:\t{ty:?}")
85-
}
86-
_ => (),
87-
}
40+
.to_string())
41+
} else {
42+
Err(io::Error::other("oops"))
43+
}
44+
}
45+
46+
fn read_binary_file(&self, _path: &Path) -> io::Result<Lrc<[u8]>> {
47+
Err(io::Error::other("oops"))
48+
}
49+
}
50+
51+
struct MyCallbacks;
52+
53+
impl rustc_driver::Callbacks for MyCallbacks {
54+
fn after_crate_root_parsing(
55+
&mut self,
56+
_compiler: &Compiler,
57+
krate: &rustc_ast::Crate,
58+
) -> Compilation {
59+
for item in &krate.items {
60+
println!("{}", item_to_string(&item));
61+
}
62+
63+
Compilation::Continue
64+
}
65+
66+
fn after_analysis(&mut self, _compiler: &Compiler, tcx: TyCtxt<'_>) -> Compilation {
67+
// Analyze the program and inspect the types of definitions.
68+
for id in tcx.hir().items() {
69+
let hir = tcx.hir();
70+
let item = hir.item(id);
71+
match item.kind {
72+
rustc_hir::ItemKind::Static(_, _, _) | rustc_hir::ItemKind::Fn(_, _, _) => {
73+
let name = item.ident;
74+
let ty = tcx.type_of(item.hir_id().owner.def_id);
75+
println!("{name:?}:\t{ty:?}")
8876
}
89-
})
90-
});
91-
});
77+
_ => (),
78+
}
79+
}
80+
81+
Compilation::Stop
82+
}
83+
}
84+
85+
fn main() {
86+
match RunCompiler::new(&["main.rs".to_string()], &mut MyCallbacks) {
87+
mut compiler => {
88+
compiler.set_file_loader(Some(Box::new(MyFileLoader)));
89+
compiler.run();
90+
}
91+
}
9292
}

Diff for: examples/rustc-driver-interacting-with-the-ast.rs

+75-66
Original file line numberDiff line numberDiff line change
@@ -1,90 +1,99 @@
11
#![feature(rustc_private)]
22

3+
extern crate rustc_ast;
34
extern crate rustc_ast_pretty;
5+
extern crate rustc_data_structures;
46
extern crate rustc_driver;
57
extern crate rustc_error_codes;
68
extern crate rustc_errors;
79
extern crate rustc_hash;
810
extern crate rustc_hir;
911
extern crate rustc_interface;
12+
extern crate rustc_middle;
1013
extern crate rustc_session;
1114
extern crate rustc_span;
1215

13-
use std::{path, process, str, sync::Arc};
16+
use std::io;
17+
use std::path::Path;
1418

1519
use rustc_ast_pretty::pprust::item_to_string;
16-
use rustc_errors::registry;
17-
use rustc_session::config;
20+
use rustc_data_structures::sync::Lrc;
21+
use rustc_driver::{Compilation, RunCompiler};
22+
use rustc_interface::interface::Compiler;
23+
use rustc_middle::ty::TyCtxt;
1824

19-
fn main() {
20-
let out = process::Command::new("rustc")
21-
.arg("--print=sysroot")
22-
.current_dir(".")
23-
.output()
24-
.unwrap();
25-
let sysroot = str::from_utf8(&out.stdout).unwrap().trim();
26-
let config = rustc_interface::Config {
27-
opts: config::Options {
28-
maybe_sysroot: Some(path::PathBuf::from(sysroot)),
29-
..config::Options::default()
30-
},
31-
input: config::Input::Str {
32-
name: rustc_span::FileName::Custom("main.rs".to_string()),
33-
input: r#"
25+
struct MyFileLoader;
26+
27+
impl rustc_span::source_map::FileLoader for MyFileLoader {
28+
fn file_exists(&self, path: &Path) -> bool {
29+
path == Path::new("main.rs")
30+
}
31+
32+
fn read_file(&self, path: &Path) -> io::Result<String> {
33+
if path == Path::new("main.rs") {
34+
Ok(r#"
3435
fn main() {
3536
let message = "Hello, World!";
3637
println!("{message}");
3738
}
3839
"#
39-
.to_string(),
40-
},
41-
crate_cfg: Vec::new(),
42-
crate_check_cfg: Vec::new(),
43-
output_dir: None,
44-
output_file: None,
45-
file_loader: None,
46-
locale_resources: rustc_driver::DEFAULT_LOCALE_RESOURCES,
47-
lint_caps: rustc_hash::FxHashMap::default(),
48-
psess_created: None,
49-
register_lints: None,
50-
override_queries: None,
51-
make_codegen_backend: None,
52-
registry: registry::Registry::new(rustc_errors::codes::DIAGNOSTICS),
53-
expanded_args: Vec::new(),
54-
ice_file: None,
55-
hash_untracked_state: None,
56-
using_internal_features: Arc::default(),
57-
};
58-
rustc_interface::run_compiler(config, |compiler| {
59-
compiler.enter(|queries| {
60-
// TODO: add this to -Z unpretty
61-
let ast_krate = queries.parse().unwrap().get_mut().clone();
62-
for item in ast_krate.items {
63-
println!("{}", item_to_string(&item));
64-
}
65-
// Analyze the crate and inspect the types under the cursor.
66-
queries.global_ctxt().unwrap().enter(|tcx| {
67-
// Every compilation contains a single crate.
68-
let hir_krate = tcx.hir();
69-
// Iterate over the top-level items in the crate, looking for the main function.
70-
for id in hir_krate.items() {
71-
let item = hir_krate.item(id);
72-
// Use pattern-matching to find a specific node inside the main function.
73-
if let rustc_hir::ItemKind::Fn(_, _, body_id) = item.kind {
74-
let expr = &tcx.hir().body(body_id).value;
75-
if let rustc_hir::ExprKind::Block(block, _) = expr.kind {
76-
if let rustc_hir::StmtKind::Let(let_stmt) = block.stmts[0].kind {
77-
if let Some(expr) = let_stmt.init {
78-
let hir_id = expr.hir_id; // hir_id identifies the string "Hello, world!"
79-
let def_id = item.hir_id().owner.def_id; // def_id identifies the main function
80-
let ty = tcx.typeck(def_id).node_type(hir_id);
81-
println!("{expr:#?}: {ty:?}");
82-
}
83-
}
40+
.to_string())
41+
} else {
42+
Err(io::Error::other("oops"))
43+
}
44+
}
45+
46+
fn read_binary_file(&self, _path: &Path) -> io::Result<Lrc<[u8]>> {
47+
Err(io::Error::other("oops"))
48+
}
49+
}
50+
51+
struct MyCallbacks;
52+
53+
impl rustc_driver::Callbacks for MyCallbacks {
54+
fn after_crate_root_parsing(
55+
&mut self,
56+
_compiler: &Compiler,
57+
krate: &rustc_ast::Crate,
58+
) -> Compilation {
59+
for item in &krate.items {
60+
println!("{}", item_to_string(&item));
61+
}
62+
63+
Compilation::Continue
64+
}
65+
66+
fn after_analysis(&mut self, _compiler: &Compiler, tcx: TyCtxt<'_>) -> Compilation {
67+
// Every compilation contains a single crate.
68+
let hir_krate = tcx.hir();
69+
// Iterate over the top-level items in the crate, looking for the main function.
70+
for id in hir_krate.items() {
71+
let item = hir_krate.item(id);
72+
// Use pattern-matching to find a specific node inside the main function.
73+
if let rustc_hir::ItemKind::Fn(_, _, body_id) = item.kind {
74+
let expr = &tcx.hir().body(body_id).value;
75+
if let rustc_hir::ExprKind::Block(block, _) = expr.kind {
76+
if let rustc_hir::StmtKind::Let(let_stmt) = block.stmts[0].kind {
77+
if let Some(expr) = let_stmt.init {
78+
let hir_id = expr.hir_id; // hir_id identifies the string "Hello, world!"
79+
let def_id = item.hir_id().owner.def_id; // def_id identifies the main function
80+
let ty = tcx.typeck(def_id).node_type(hir_id);
81+
println!("{expr:#?}: {ty:?}");
8482
}
8583
}
8684
}
87-
})
88-
});
89-
});
85+
}
86+
}
87+
88+
Compilation::Stop
89+
}
90+
}
91+
92+
fn main() {
93+
match RunCompiler::new(&["main.rs".to_string()], &mut MyCallbacks) {
94+
mut compiler => {
95+
compiler.set_file_loader(Some(Box::new(MyFileLoader)));
96+
compiler.run();
97+
}
98+
}
9099
}

0 commit comments

Comments
 (0)