From ee4b5a34d8aa789ebc521926123fba79eebe5981 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sat, 3 Apr 2021 20:58:42 +0200 Subject: Use bitflags to compress function properties Very minor savings, only 1 MB or so --- Cargo.lock | 1 + crates/hir/src/display.rs | 17 ++++--- crates/hir/src/lib.rs | 6 +-- crates/hir_def/Cargo.toml | 1 + crates/hir_def/src/data.rs | 57 +++++++++++++++++------ crates/hir_def/src/item_tree.rs | 31 +++++++------ crates/hir_def/src/item_tree/lower.rs | 66 ++++++++++++++++----------- crates/hir_ty/src/diagnostics/decl_check.rs | 2 +- crates/hir_ty/src/diagnostics/unsafe_check.rs | 6 +-- crates/hir_ty/src/lower.rs | 2 +- crates/hir_ty/src/method_resolution.rs | 2 +- 11 files changed, 120 insertions(+), 71 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 05383d8b7..4531d8fb1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -498,6 +498,7 @@ version = "0.0.0" dependencies = [ "anymap", "base_db", + "bitflags", "cfg", "cov-mark", "dashmap", diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs index ab04c55bc..559ea31a0 100644 --- a/crates/hir/src/display.rs +++ b/crates/hir/src/display.rs @@ -20,22 +20,21 @@ impl HirDisplay for Function { fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { let data = f.db.function_data(self.id); write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; - let qual = &data.qualifier; - if qual.is_default { + if data.is_default() { write!(f, "default ")?; } - if qual.is_const { + if data.is_const() { write!(f, "const ")?; } - if qual.is_async { + if data.is_async() { write!(f, "async ")?; } - if qual.is_unsafe { + if data.is_unsafe() { write!(f, "unsafe ")?; } - if let Some(abi) = &qual.abi { + if let Some(abi) = &data.abi { // FIXME: String escape? - write!(f, "extern \"{}\" ", abi)?; + write!(f, "extern \"{}\" ", &**abi)?; } write!(f, "fn {}", data.name)?; @@ -68,7 +67,7 @@ impl HirDisplay for Function { write!(f, ", ")?; } else { first = false; - if data.has_self_param { + if data.has_self_param() { write_self_param(type_ref, f)?; continue; } @@ -88,7 +87,7 @@ impl HirDisplay for Function { // `FunctionData::ret_type` will be `::core::future::Future` for async fns. // Use ugly pattern match to strip the Future trait. // Better way? - let ret_type = if !qual.is_async { + let ret_type = if !data.is_async() { &data.ret_type } else { match &*data.ret_type { diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 29010191b..eb19e4b51 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -832,7 +832,7 @@ impl Function { } pub fn self_param(self, db: &dyn HirDatabase) -> Option { - if !db.function_data(self.id).has_self_param { + if !db.function_data(self.id).has_self_param() { return None; } Some(SelfParam { func: self.id }) @@ -864,7 +864,7 @@ impl Function { } pub fn is_unsafe(self, db: &dyn HirDatabase) -> bool { - db.function_data(self.id).qualifier.is_unsafe + db.function_data(self.id).is_unsafe() } pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { @@ -878,7 +878,7 @@ impl Function { /// /// This is false in the case of required (not provided) trait methods. pub fn has_body(self, db: &dyn HirDatabase) -> bool { - db.function_data(self.id).has_body + db.function_data(self.id).has_body() } /// A textual representation of the HIR of this function for debugging purposes. diff --git a/crates/hir_def/Cargo.toml b/crates/hir_def/Cargo.toml index 43324d8d9..60adb655c 100644 --- a/crates/hir_def/Cargo.toml +++ b/crates/hir_def/Cargo.toml @@ -10,6 +10,7 @@ edition = "2018" doctest = false [dependencies] +bitflags = "1.2.1" cov-mark = { version = "1.1", features = ["thread-local"] } dashmap = { version = "4.0.2", features = ["raw-api"] } log = "0.4.8" diff --git a/crates/hir_def/src/data.rs b/crates/hir_def/src/data.rs index 31f994681..b409fb45c 100644 --- a/crates/hir_def/src/data.rs +++ b/crates/hir_def/src/data.rs @@ -10,7 +10,7 @@ use crate::{ body::Expander, db::DefDatabase, intern::Interned, - item_tree::{AssocItem, FunctionQualifier, ItemTreeId, ModItem, Param}, + item_tree::{AssocItem, FnFlags, ItemTreeId, ModItem, Param}, type_ref::{TraitRef, TypeBound, TypeRef}, visibility::RawVisibility, AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId, @@ -23,14 +23,9 @@ pub struct FunctionData { pub params: Vec>, pub ret_type: Interned, pub attrs: Attrs, - /// True if the first param is `self`. This is relevant to decide whether this - /// can be called as a method. - pub has_self_param: bool, - pub has_body: bool, - pub qualifier: FunctionQualifier, - pub is_in_extern_block: bool, - pub is_varargs: bool, pub visibility: RawVisibility, + pub abi: Option>, + flags: FnFlags, } impl FunctionData { @@ -53,6 +48,11 @@ impl FunctionData { .next_back() .map_or(false, |param| matches!(item_tree[param], Param::Varargs)); + let mut flags = func.flags; + if is_varargs { + flags |= FnFlags::IS_VARARGS; + } + Arc::new(FunctionData { name: func.name.clone(), params: enabled_params @@ -64,14 +64,45 @@ impl FunctionData { .collect(), ret_type: func.ret_type.clone(), attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()), - has_self_param: func.has_self_param, - has_body: func.has_body, - qualifier: func.qualifier.clone(), - is_in_extern_block: func.is_in_extern_block, - is_varargs, visibility: item_tree[func.visibility].clone(), + abi: func.abi.clone(), + flags, }) } + + pub fn has_body(&self) -> bool { + self.flags.contains(FnFlags::HAS_BODY) + } + + /// True if the first param is `self`. This is relevant to decide whether this + /// can be called as a method. + pub fn has_self_param(&self) -> bool { + self.flags.contains(FnFlags::HAS_SELF_PARAM) + } + + pub fn is_default(&self) -> bool { + self.flags.contains(FnFlags::IS_DEFAULT) + } + + pub fn is_const(&self) -> bool { + self.flags.contains(FnFlags::IS_CONST) + } + + pub fn is_async(&self) -> bool { + self.flags.contains(FnFlags::IS_ASYNC) + } + + pub fn is_unsafe(&self) -> bool { + self.flags.contains(FnFlags::IS_UNSAFE) + } + + pub fn is_in_extern_block(&self) -> bool { + self.flags.contains(FnFlags::IS_IN_EXTERN_BLOCK) + } + + pub fn is_varargs(&self) -> bool { + self.flags.contains(FnFlags::IS_VARARGS) + } } #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index dd80cef23..c6d700977 100644 --- a/crates/hir_def/src/item_tree.rs +++ b/crates/hir_def/src/item_tree.rs @@ -24,7 +24,7 @@ use la_arena::{Arena, Idx, RawIdx}; use profile::Count; use rustc_hash::FxHashMap; use smallvec::SmallVec; -use syntax::{ast, match_ast, SmolStr, SyntaxKind}; +use syntax::{ast, match_ast, SyntaxKind}; use crate::{ attr::{Attrs, RawAttrs}, @@ -556,15 +556,11 @@ pub struct Function { pub name: Name, pub visibility: RawVisibilityId, pub generic_params: GenericParamsId, - pub has_self_param: bool, - pub has_body: bool, - pub qualifier: FunctionQualifier, - /// Whether the function is located in an `extern` block (*not* whether it is an - /// `extern "abi" fn`). - pub is_in_extern_block: bool, + pub abi: Option>, pub params: IdRange, pub ret_type: Interned, pub ast_id: FileAstId, + pub(crate) flags: FnFlags, } #[derive(Debug, Clone, Eq, PartialEq)] @@ -573,13 +569,20 @@ pub enum Param { Varargs, } -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct FunctionQualifier { - pub is_default: bool, - pub is_const: bool, - pub is_async: bool, - pub is_unsafe: bool, - pub abi: Option, +bitflags::bitflags! { + /// NOTE: Shared with `FunctionData` + pub(crate) struct FnFlags: u8 { + const HAS_SELF_PARAM = 1 << 0; + const HAS_BODY = 1 << 1; + const IS_DEFAULT = 1 << 2; + const IS_CONST = 1 << 3; + const IS_ASYNC = 1 << 4; + const IS_UNSAFE = 1 << 5; + /// Whether the function is located in an `extern` block (*not* whether it is an + /// `extern "abi" fn`). + const IS_IN_EXTERN_BLOCK = 1 << 6; + const IS_VARARGS = 1 << 7; + } } #[derive(Debug, Clone, Eq, PartialEq)] diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs index ead7cd7a4..39e8403b0 100644 --- a/crates/hir_def/src/item_tree/lower.rs +++ b/crates/hir_def/src/item_tree/lower.rs @@ -395,39 +395,51 @@ impl Ctx { ret_type }; - let has_body = func.body().is_some(); + let abi = func.abi().map(|abi| { + // FIXME: Abi::abi() -> Option? + match abi.syntax().last_token() { + Some(tok) if tok.kind() == SyntaxKind::STRING => { + // FIXME: Better way to unescape? + Interned::new_str(tok.text().trim_matches('"')) + } + _ => { + // `extern` default to be `extern "C"`. + Interned::new_str("C") + } + } + }); let ast_id = self.source_ast_id_map.ast_id(func); - let qualifier = FunctionQualifier { - is_default: func.default_token().is_some(), - is_const: func.const_token().is_some(), - is_async: func.async_token().is_some(), - is_unsafe: func.unsafe_token().is_some(), - abi: func.abi().map(|abi| { - // FIXME: Abi::abi() -> Option? - match abi.syntax().last_token() { - Some(tok) if tok.kind() == SyntaxKind::STRING => { - // FIXME: Better way to unescape? - tok.text().trim_matches('"').into() - } - _ => { - // `extern` default to be `extern "C"`. - "C".into() - } - } - }), - }; + + let mut flags = FnFlags::empty(); + if func.body().is_some() { + flags |= FnFlags::HAS_BODY; + } + if has_self_param { + flags |= FnFlags::HAS_SELF_PARAM; + } + if func.default_token().is_some() { + flags |= FnFlags::IS_DEFAULT; + } + if func.const_token().is_some() { + flags |= FnFlags::IS_CONST; + } + if func.async_token().is_some() { + flags |= FnFlags::IS_ASYNC; + } + if func.unsafe_token().is_some() { + flags |= FnFlags::IS_UNSAFE; + } + let mut res = Function { name, visibility, generic_params: GenericParamsId::EMPTY, - has_self_param, - has_body, - qualifier, - is_in_extern_block: false, + abi, params, ret_type: Interned::new(ret_type), ast_id, + flags, }; res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func); @@ -640,8 +652,10 @@ impl Ctx { ast::ExternItem::Fn(ast) => { let func_id = self.lower_function(&ast)?; let func = &mut self.data().functions[func_id.index]; - func.qualifier.is_unsafe = is_intrinsic_fn_unsafe(&func.name); - func.is_in_extern_block = true; + if is_intrinsic_fn_unsafe(&func.name) { + func.flags |= FnFlags::IS_UNSAFE; + } + func.flags |= FnFlags::IS_IN_EXTERN_BLOCK; func_id.into() } ast::ExternItem::Static(ast) => { diff --git a/crates/hir_ty/src/diagnostics/decl_check.rs b/crates/hir_ty/src/diagnostics/decl_check.rs index 33a0f4d7d..207c7cb82 100644 --- a/crates/hir_ty/src/diagnostics/decl_check.rs +++ b/crates/hir_ty/src/diagnostics/decl_check.rs @@ -91,7 +91,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> { fn validate_func(&mut self, func: FunctionId) { let data = self.db.function_data(func); - if data.is_in_extern_block { + if data.is_in_extern_block() { cov_mark::hit!(extern_func_incorrect_case_ignored); return; } diff --git a/crates/hir_ty/src/diagnostics/unsafe_check.rs b/crates/hir_ty/src/diagnostics/unsafe_check.rs index a71eebc6f..b5efe9df5 100644 --- a/crates/hir_ty/src/diagnostics/unsafe_check.rs +++ b/crates/hir_ty/src/diagnostics/unsafe_check.rs @@ -32,7 +32,7 @@ impl<'a, 'b> UnsafeValidator<'a, 'b> { let def = self.owner; let unsafe_expressions = unsafe_expressions(db, self.infer.as_ref(), def); let is_unsafe = match self.owner { - DefWithBodyId::FunctionId(it) => db.function_data(it).qualifier.is_unsafe, + DefWithBodyId::FunctionId(it) => db.function_data(it).is_unsafe(), DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) => false, }; if is_unsafe @@ -86,7 +86,7 @@ fn walk_unsafe( match expr { &Expr::Call { callee, .. } => { if let Some(func) = infer[callee].as_fn_def(db) { - if db.function_data(func).qualifier.is_unsafe { + if db.function_data(func).is_unsafe() { unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block }); } } @@ -103,7 +103,7 @@ fn walk_unsafe( Expr::MethodCall { .. } => { if infer .method_resolution(current) - .map(|func| db.function_data(func).qualifier.is_unsafe) + .map(|func| db.function_data(func).is_unsafe()) .unwrap_or(false) { unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block }); diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs index f595683e5..e60d7c730 100644 --- a/crates/hir_ty/src/lower.rs +++ b/crates/hir_ty/src/lower.rs @@ -1054,7 +1054,7 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig { let ret = (&ctx_ret).lower_ty(&data.ret_type); let generics = generics(db.upcast(), def.into()); let num_binders = generics.len(); - Binders::new(num_binders, CallableSig::from_params_and_return(params, ret, data.is_varargs)) + Binders::new(num_binders, CallableSig::from_params_and_return(params, ret, data.is_varargs())) } /// Build the declared type of a function. This should not need to look at the diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs index 338851fa8..c093fce20 100644 --- a/crates/hir_ty/src/method_resolution.rs +++ b/crates/hir_ty/src/method_resolution.rs @@ -675,7 +675,7 @@ fn is_valid_candidate( } } if let Some(receiver_ty) = receiver_ty { - if !data.has_self_param { + if !data.has_self_param() { return false; } let transformed_receiver_ty = match transform_receiver_ty(db, m, self_ty) { -- cgit v1.2.3