Skip to content

Implement bulitin line! macro #2205

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Nov 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions crates/ra_hir/src/ty/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4810,3 +4810,22 @@ fn no_such_field_diagnostics() {
"###
);
}

#[test]
fn infer_builtin_macros_line() {
assert_snapshot!(
infer(r#"
#[rustc_builtin_macro]
macro_rules! line {() => {}}

fn main() {
let x = line!();
}
"#),
@r###"
![0; 1) '6': i32
[64; 88) '{ ...!(); }': ()
[74; 75) 'x': i32
"###
);
}
25 changes: 23 additions & 2 deletions crates/ra_hir_def/src/nameres/collector.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
//! FIXME: write short doc here

use hir_expand::{
builtin_macro::find_builtin_macro,
name::{self, AsName, Name},
HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind,
HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroDefKind, MacroFileKind,
};
use ra_cfg::CfgOptions;
use ra_db::{CrateId, FileId};
Expand Down Expand Up @@ -688,10 +689,30 @@ where
fn collect_macro(&mut self, mac: &raw::MacroData) {
let ast_id = AstId::new(self.file_id, mac.ast_id);

// Case 0: builtin macros
if mac.builtin {
if let Some(name) = &mac.name {
let krate = self.def_collector.def_map.krate;
if let Some(macro_id) = find_builtin_macro(name, krate, ast_id) {
self.def_collector.define_macro(
self.module_id,
name.clone(),
macro_id,
mac.export,
);
return;
}
}
}

// Case 1: macro rules, define a macro in crate-global mutable scope
if is_macro_rules(&mac.path) {
if let Some(name) = &mac.name {
let macro_id = MacroDefId { ast_id, krate: self.def_collector.def_map.krate };
let macro_id = MacroDefId {
ast_id,
krate: self.def_collector.def_map.krate,
kind: MacroDefKind::Declarative,
};
self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export);
}
return;
Expand Down
7 changes: 6 additions & 1 deletion crates/ra_hir_def/src/nameres/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ pub(super) struct MacroData {
pub(super) path: Path,
pub(super) name: Option<Name>,
pub(super) export: bool,
pub(super) builtin: bool,
}

struct RawItemsCollector {
Expand Down Expand Up @@ -367,7 +368,11 @@ impl RawItemsCollector {
// FIXME: cfg_attr
let export = m.attrs().filter_map(|x| x.simple_name()).any(|name| name == "macro_export");

let m = self.raw_items.macros.alloc(MacroData { ast_id, path, name, export });
// FIXME: cfg_attr
let builtin =
m.attrs().filter_map(|x| x.simple_name()).any(|name| name == "rustc_builtin_macro");

let m = self.raw_items.macros.alloc(MacroData { ast_id, path, name, export, builtin });
self.push_item(current_module, attrs, RawItemKind::Macro(m));
}

Expand Down
80 changes: 80 additions & 0 deletions crates/ra_hir_expand/src/builtin_macro.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
//! Builtin macro
use crate::db::AstDatabase;
use crate::{
ast::{self, AstNode},
name, AstId, CrateId, HirFileId, MacroCallId, MacroDefId, MacroDefKind, MacroFileKind,
TextUnit,
};

use crate::quote;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum BuiltinExpander {
Line,
}

impl BuiltinExpander {
pub fn expand(
&self,
db: &dyn AstDatabase,
id: MacroCallId,
tt: &tt::Subtree,
) -> Result<tt::Subtree, mbe::ExpandError> {
match self {
BuiltinExpander::Line => line_expand(db, id, tt),
}
}
}

pub fn find_builtin_macro(
ident: &name::Name,
krate: CrateId,
ast_id: AstId<ast::MacroCall>,
) -> Option<MacroDefId> {
// FIXME: Better registering method
if ident == &name::LINE_MACRO {
Some(MacroDefId { krate, ast_id, kind: MacroDefKind::BuiltIn(BuiltinExpander::Line) })
} else {
None
}
}

fn to_line_number(db: &dyn AstDatabase, file: HirFileId, pos: TextUnit) -> usize {
// FIXME: Use expansion info
let file_id = file.original_file(db);
let text = db.file_text(file_id);
let mut line_num = 1;

// Count line end
for (i, c) in text.chars().enumerate() {
if i == pos.to_usize() {
break;
}
if c == '\n' {
line_num += 1;
}
}

line_num
}

fn line_expand(
db: &dyn AstDatabase,
id: MacroCallId,
_tt: &tt::Subtree,
) -> Result<tt::Subtree, mbe::ExpandError> {
let loc = db.lookup_intern_macro(id);
let macro_call = loc.ast_id.to_node(db);

let arg = macro_call.token_tree().ok_or_else(|| mbe::ExpandError::UnexpectedToken)?;
let arg_start = arg.syntax().text_range().start();

let file = id.as_file(MacroFileKind::Expr);
let line_num = to_line_number(db, file, arg_start);

let expanded = quote! {
#line_num
};

Ok(expanded)
}
66 changes: 50 additions & 16 deletions crates/ra_hir_expand/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,37 @@ use ra_prof::profile;
use ra_syntax::{AstNode, Parse, SyntaxNode};

use crate::{
ast_id_map::AstIdMap, HirFileId, HirFileIdRepr, MacroCallId, MacroCallLoc, MacroDefId,
MacroFile, MacroFileKind,
ast_id_map::AstIdMap, BuiltinExpander, HirFileId, HirFileIdRepr, MacroCallId, MacroCallLoc,
MacroDefId, MacroDefKind, MacroFile, MacroFileKind,
};

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum TokenExpander {
MacroRules(mbe::MacroRules),
Builtin(BuiltinExpander),
}

impl TokenExpander {
pub fn expand(
&self,
db: &dyn AstDatabase,
id: MacroCallId,
tt: &tt::Subtree,
) -> Result<tt::Subtree, mbe::ExpandError> {
match self {
TokenExpander::MacroRules(it) => it.expand(tt),
TokenExpander::Builtin(it) => it.expand(db, id, tt),
}
}

pub fn shift(&self) -> u32 {
match self {
TokenExpander::MacroRules(it) => it.shift(),
TokenExpander::Builtin(_) => 0,
}
}
}

// FIXME: rename to ExpandDatabase
#[salsa::query_group(AstDatabaseStorage)]
pub trait AstDatabase: SourceDatabase {
Expand All @@ -24,7 +51,7 @@ pub trait AstDatabase: SourceDatabase {
#[salsa::interned]
fn intern_macro(&self, macro_call: MacroCallLoc) -> MacroCallId;
fn macro_arg(&self, id: MacroCallId) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>>;
fn macro_def(&self, id: MacroDefId) -> Option<Arc<(mbe::MacroRules, mbe::TokenMap)>>;
fn macro_def(&self, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>>;
fn parse_macro(
&self,
macro_file: MacroFile,
Expand All @@ -41,18 +68,25 @@ pub(crate) fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<AstIdM
pub(crate) fn macro_def(
db: &dyn AstDatabase,
id: MacroDefId,
) -> Option<Arc<(mbe::MacroRules, mbe::TokenMap)>> {
let macro_call = id.ast_id.to_node(db);
let arg = macro_call.token_tree()?;
let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| {
log::warn!("fail on macro_def to token tree: {:#?}", arg);
None
})?;
let rules = MacroRules::parse(&tt).ok().or_else(|| {
log::warn!("fail on macro_def parse: {:#?}", tt);
None
})?;
Some(Arc::new((rules, tmap)))
) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> {
match id.kind {
MacroDefKind::Declarative => {
let macro_call = id.ast_id.to_node(db);
let arg = macro_call.token_tree()?;
let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| {
log::warn!("fail on macro_def to token tree: {:#?}", arg);
None
})?;
let rules = MacroRules::parse(&tt).ok().or_else(|| {
log::warn!("fail on macro_def parse: {:#?}", tt);
None
})?;
Some(Arc::new((TokenExpander::MacroRules(rules), tmap)))
}
MacroDefKind::BuiltIn(expander) => {
Some(Arc::new((TokenExpander::Builtin(expander.clone()), mbe::TokenMap::default())))
}
}
}

pub(crate) fn macro_arg(
Expand All @@ -74,7 +108,7 @@ pub(crate) fn macro_expand(
let macro_arg = db.macro_arg(id).ok_or("Fail to args in to tt::TokenTree")?;

let macro_rules = db.macro_def(loc.def).ok_or("Fail to find macro definition")?;
let tt = macro_rules.0.expand(&macro_arg.0).map_err(|err| format!("{:?}", err))?;
let tt = macro_rules.0.expand(db, id, &macro_arg.0).map_err(|err| format!("{:?}", err))?;
// Set a hard limit for the expanded tt
let count = tt.count();
if count > 65536 {
Expand Down
7 changes: 5 additions & 2 deletions crates/ra_hir_expand/src/hygiene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::{
db::AstDatabase,
either::Either,
name::{AsName, Name},
HirFileId, HirFileIdRepr,
HirFileId, HirFileIdRepr, MacroDefKind,
};

#[derive(Debug)]
Expand All @@ -24,7 +24,10 @@ impl Hygiene {
HirFileIdRepr::FileId(_) => None,
HirFileIdRepr::MacroFile(macro_file) => {
let loc = db.lookup_intern_macro(macro_file.macro_call_id);
Some(loc.def.krate)
match loc.def.kind {
MacroDefKind::Declarative => Some(loc.def.krate),
MacroDefKind::BuiltIn(_) => None,
}
}
};
Hygiene { def_crate }
Expand Down
12 changes: 11 additions & 1 deletion crates/ra_hir_expand/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ pub mod either;
pub mod name;
pub mod hygiene;
pub mod diagnostics;
pub mod builtin_macro;
pub mod quote;

use std::hash::{Hash, Hasher};
use std::sync::Arc;
Expand All @@ -21,6 +23,7 @@ use ra_syntax::{
};

use crate::ast_id_map::FileAstId;
use crate::builtin_macro::BuiltinExpander;

/// Input to the analyzer is a set of files, where each file is identified by
/// `FileId` and contains source code. However, another source of source code in
Expand Down Expand Up @@ -122,6 +125,13 @@ impl salsa::InternKey for MacroCallId {
pub struct MacroDefId {
pub krate: CrateId,
pub ast_id: AstId<ast::MacroCall>,
pub kind: MacroDefKind,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum MacroDefKind {
Declarative,
BuiltIn(BuiltinExpander),
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
Expand All @@ -144,7 +154,7 @@ pub struct ExpansionInfo {
pub(crate) def_start: (HirFileId, TextUnit),
pub(crate) shift: u32,

pub(crate) macro_def: Arc<(mbe::MacroRules, mbe::TokenMap)>,
pub(crate) macro_def: Arc<(db::TokenExpander, mbe::TokenMap)>,
pub(crate) macro_arg: Arc<(tt::Subtree, mbe::TokenMap)>,
pub(crate) exp_map: Arc<mbe::RevTokenMap>,
}
Expand Down
3 changes: 3 additions & 0 deletions crates/ra_hir_expand/src/name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,3 +140,6 @@ pub const RESULT_TYPE: Name = Name::new_inline_ascii(6, b"Result");
pub const OUTPUT_TYPE: Name = Name::new_inline_ascii(6, b"Output");
pub const TARGET_TYPE: Name = Name::new_inline_ascii(6, b"Target");
pub const BOX_TYPE: Name = Name::new_inline_ascii(3, b"Box");

// Builtin Macros
pub const LINE_MACRO: Name = Name::new_inline_ascii(4, b"line");
Loading