aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonas Schievink <[email protected]>2021-04-03 19:58:42 +0100
committerJonas Schievink <[email protected]>2021-04-03 19:58:42 +0100
commitee4b5a34d8aa789ebc521926123fba79eebe5981 (patch)
tree9e5444bdd56ad6725525764d9f35a20f927b2209
parentf7e6b186e1d2f3a31b8e21d0885e13f12f12d71b (diff)
Use bitflags to compress function properties
Very minor savings, only 1 MB or so
-rw-r--r--Cargo.lock1
-rw-r--r--crates/hir/src/display.rs17
-rw-r--r--crates/hir/src/lib.rs6
-rw-r--r--crates/hir_def/Cargo.toml1
-rw-r--r--crates/hir_def/src/data.rs57
-rw-r--r--crates/hir_def/src/item_tree.rs31
-rw-r--r--crates/hir_def/src/item_tree/lower.rs66
-rw-r--r--crates/hir_ty/src/diagnostics/decl_check.rs2
-rw-r--r--crates/hir_ty/src/diagnostics/unsafe_check.rs6
-rw-r--r--crates/hir_ty/src/lower.rs2
-rw-r--r--crates/hir_ty/src/method_resolution.rs2
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"
498dependencies = [ 498dependencies = [
499 "anymap", 499 "anymap",
500 "base_db", 500 "base_db",
501 "bitflags",
501 "cfg", 502 "cfg",
502 "cov-mark", 503 "cov-mark",
503 "dashmap", 504 "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 {
20 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { 20 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
21 let data = f.db.function_data(self.id); 21 let data = f.db.function_data(self.id);
22 write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; 22 write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
23 let qual = &data.qualifier; 23 if data.is_default() {
24 if qual.is_default {
25 write!(f, "default ")?; 24 write!(f, "default ")?;
26 } 25 }
27 if qual.is_const { 26 if data.is_const() {
28 write!(f, "const ")?; 27 write!(f, "const ")?;
29 } 28 }
30 if qual.is_async { 29 if data.is_async() {
31 write!(f, "async ")?; 30 write!(f, "async ")?;
32 } 31 }
33 if qual.is_unsafe { 32 if data.is_unsafe() {
34 write!(f, "unsafe ")?; 33 write!(f, "unsafe ")?;
35 } 34 }
36 if let Some(abi) = &qual.abi { 35 if let Some(abi) = &data.abi {
37 // FIXME: String escape? 36 // FIXME: String escape?
38 write!(f, "extern \"{}\" ", abi)?; 37 write!(f, "extern \"{}\" ", &**abi)?;
39 } 38 }
40 write!(f, "fn {}", data.name)?; 39 write!(f, "fn {}", data.name)?;
41 40
@@ -68,7 +67,7 @@ impl HirDisplay for Function {
68 write!(f, ", ")?; 67 write!(f, ", ")?;
69 } else { 68 } else {
70 first = false; 69 first = false;
71 if data.has_self_param { 70 if data.has_self_param() {
72 write_self_param(type_ref, f)?; 71 write_self_param(type_ref, f)?;
73 continue; 72 continue;
74 } 73 }
@@ -88,7 +87,7 @@ impl HirDisplay for Function {
88 // `FunctionData::ret_type` will be `::core::future::Future<Output = ...>` for async fns. 87 // `FunctionData::ret_type` will be `::core::future::Future<Output = ...>` for async fns.
89 // Use ugly pattern match to strip the Future trait. 88 // Use ugly pattern match to strip the Future trait.
90 // Better way? 89 // Better way?
91 let ret_type = if !qual.is_async { 90 let ret_type = if !data.is_async() {
92 &data.ret_type 91 &data.ret_type
93 } else { 92 } else {
94 match &*data.ret_type { 93 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 {
832 } 832 }
833 833
834 pub fn self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> { 834 pub fn self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> {
835 if !db.function_data(self.id).has_self_param { 835 if !db.function_data(self.id).has_self_param() {
836 return None; 836 return None;
837 } 837 }
838 Some(SelfParam { func: self.id }) 838 Some(SelfParam { func: self.id })
@@ -864,7 +864,7 @@ impl Function {
864 } 864 }
865 865
866 pub fn is_unsafe(self, db: &dyn HirDatabase) -> bool { 866 pub fn is_unsafe(self, db: &dyn HirDatabase) -> bool {
867 db.function_data(self.id).qualifier.is_unsafe 867 db.function_data(self.id).is_unsafe()
868 } 868 }
869 869
870 pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { 870 pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) {
@@ -878,7 +878,7 @@ impl Function {
878 /// 878 ///
879 /// This is false in the case of required (not provided) trait methods. 879 /// This is false in the case of required (not provided) trait methods.
880 pub fn has_body(self, db: &dyn HirDatabase) -> bool { 880 pub fn has_body(self, db: &dyn HirDatabase) -> bool {
881 db.function_data(self.id).has_body 881 db.function_data(self.id).has_body()
882 } 882 }
883 883
884 /// A textual representation of the HIR of this function for debugging purposes. 884 /// 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"
10doctest = false 10doctest = false
11 11
12[dependencies] 12[dependencies]
13bitflags = "1.2.1"
13cov-mark = { version = "1.1", features = ["thread-local"] } 14cov-mark = { version = "1.1", features = ["thread-local"] }
14dashmap = { version = "4.0.2", features = ["raw-api"] } 15dashmap = { version = "4.0.2", features = ["raw-api"] }
15log = "0.4.8" 16log = "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::{
10 body::Expander, 10 body::Expander,
11 db::DefDatabase, 11 db::DefDatabase,
12 intern::Interned, 12 intern::Interned,
13 item_tree::{AssocItem, FunctionQualifier, ItemTreeId, ModItem, Param}, 13 item_tree::{AssocItem, FnFlags, ItemTreeId, ModItem, Param},
14 type_ref::{TraitRef, TypeBound, TypeRef}, 14 type_ref::{TraitRef, TypeBound, TypeRef},
15 visibility::RawVisibility, 15 visibility::RawVisibility,
16 AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId, 16 AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId,
@@ -23,14 +23,9 @@ pub struct FunctionData {
23 pub params: Vec<Interned<TypeRef>>, 23 pub params: Vec<Interned<TypeRef>>,
24 pub ret_type: Interned<TypeRef>, 24 pub ret_type: Interned<TypeRef>,
25 pub attrs: Attrs, 25 pub attrs: Attrs,
26 /// True if the first param is `self`. This is relevant to decide whether this
27 /// can be called as a method.
28 pub has_self_param: bool,
29 pub has_body: bool,
30 pub qualifier: FunctionQualifier,
31 pub is_in_extern_block: bool,
32 pub is_varargs: bool,
33 pub visibility: RawVisibility, 26 pub visibility: RawVisibility,
27 pub abi: Option<Interned<str>>,
28 flags: FnFlags,
34} 29}
35 30
36impl FunctionData { 31impl FunctionData {
@@ -53,6 +48,11 @@ impl FunctionData {
53 .next_back() 48 .next_back()
54 .map_or(false, |param| matches!(item_tree[param], Param::Varargs)); 49 .map_or(false, |param| matches!(item_tree[param], Param::Varargs));
55 50
51 let mut flags = func.flags;
52 if is_varargs {
53 flags |= FnFlags::IS_VARARGS;
54 }
55
56 Arc::new(FunctionData { 56 Arc::new(FunctionData {
57 name: func.name.clone(), 57 name: func.name.clone(),
58 params: enabled_params 58 params: enabled_params
@@ -64,14 +64,45 @@ impl FunctionData {
64 .collect(), 64 .collect(),
65 ret_type: func.ret_type.clone(), 65 ret_type: func.ret_type.clone(),
66 attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()), 66 attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()),
67 has_self_param: func.has_self_param,
68 has_body: func.has_body,
69 qualifier: func.qualifier.clone(),
70 is_in_extern_block: func.is_in_extern_block,
71 is_varargs,
72 visibility: item_tree[func.visibility].clone(), 67 visibility: item_tree[func.visibility].clone(),
68 abi: func.abi.clone(),
69 flags,
73 }) 70 })
74 } 71 }
72
73 pub fn has_body(&self) -> bool {
74 self.flags.contains(FnFlags::HAS_BODY)
75 }
76
77 /// True if the first param is `self`. This is relevant to decide whether this
78 /// can be called as a method.
79 pub fn has_self_param(&self) -> bool {
80 self.flags.contains(FnFlags::HAS_SELF_PARAM)
81 }
82
83 pub fn is_default(&self) -> bool {
84 self.flags.contains(FnFlags::IS_DEFAULT)
85 }
86
87 pub fn is_const(&self) -> bool {
88 self.flags.contains(FnFlags::IS_CONST)
89 }
90
91 pub fn is_async(&self) -> bool {
92 self.flags.contains(FnFlags::IS_ASYNC)
93 }
94
95 pub fn is_unsafe(&self) -> bool {
96 self.flags.contains(FnFlags::IS_UNSAFE)
97 }
98
99 pub fn is_in_extern_block(&self) -> bool {
100 self.flags.contains(FnFlags::IS_IN_EXTERN_BLOCK)
101 }
102
103 pub fn is_varargs(&self) -> bool {
104 self.flags.contains(FnFlags::IS_VARARGS)
105 }
75} 106}
76 107
77#[derive(Debug, Clone, PartialEq, Eq)] 108#[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};
24use profile::Count; 24use profile::Count;
25use rustc_hash::FxHashMap; 25use rustc_hash::FxHashMap;
26use smallvec::SmallVec; 26use smallvec::SmallVec;
27use syntax::{ast, match_ast, SmolStr, SyntaxKind}; 27use syntax::{ast, match_ast, SyntaxKind};
28 28
29use crate::{ 29use crate::{
30 attr::{Attrs, RawAttrs}, 30 attr::{Attrs, RawAttrs},
@@ -556,15 +556,11 @@ pub struct Function {
556 pub name: Name, 556 pub name: Name,
557 pub visibility: RawVisibilityId, 557 pub visibility: RawVisibilityId,
558 pub generic_params: GenericParamsId, 558 pub generic_params: GenericParamsId,
559 pub has_self_param: bool, 559 pub abi: Option<Interned<str>>,
560 pub has_body: bool,
561 pub qualifier: FunctionQualifier,
562 /// Whether the function is located in an `extern` block (*not* whether it is an
563 /// `extern "abi" fn`).
564 pub is_in_extern_block: bool,
565 pub params: IdRange<Param>, 560 pub params: IdRange<Param>,
566 pub ret_type: Interned<TypeRef>, 561 pub ret_type: Interned<TypeRef>,
567 pub ast_id: FileAstId<ast::Fn>, 562 pub ast_id: FileAstId<ast::Fn>,
563 pub(crate) flags: FnFlags,
568} 564}
569 565
570#[derive(Debug, Clone, Eq, PartialEq)] 566#[derive(Debug, Clone, Eq, PartialEq)]
@@ -573,13 +569,20 @@ pub enum Param {
573 Varargs, 569 Varargs,
574} 570}
575 571
576#[derive(Debug, Clone, PartialEq, Eq)] 572bitflags::bitflags! {
577pub struct FunctionQualifier { 573 /// NOTE: Shared with `FunctionData`
578 pub is_default: bool, 574 pub(crate) struct FnFlags: u8 {
579 pub is_const: bool, 575 const HAS_SELF_PARAM = 1 << 0;
580 pub is_async: bool, 576 const HAS_BODY = 1 << 1;
581 pub is_unsafe: bool, 577 const IS_DEFAULT = 1 << 2;
582 pub abi: Option<SmolStr>, 578 const IS_CONST = 1 << 3;
579 const IS_ASYNC = 1 << 4;
580 const IS_UNSAFE = 1 << 5;
581 /// Whether the function is located in an `extern` block (*not* whether it is an
582 /// `extern "abi" fn`).
583 const IS_IN_EXTERN_BLOCK = 1 << 6;
584 const IS_VARARGS = 1 << 7;
585 }
583} 586}
584 587
585#[derive(Debug, Clone, Eq, PartialEq)] 588#[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 {
395 ret_type 395 ret_type
396 }; 396 };
397 397
398 let has_body = func.body().is_some(); 398 let abi = func.abi().map(|abi| {
399 // FIXME: Abi::abi() -> Option<SyntaxToken>?
400 match abi.syntax().last_token() {
401 Some(tok) if tok.kind() == SyntaxKind::STRING => {
402 // FIXME: Better way to unescape?
403 Interned::new_str(tok.text().trim_matches('"'))
404 }
405 _ => {
406 // `extern` default to be `extern "C"`.
407 Interned::new_str("C")
408 }
409 }
410 });
399 411
400 let ast_id = self.source_ast_id_map.ast_id(func); 412 let ast_id = self.source_ast_id_map.ast_id(func);
401 let qualifier = FunctionQualifier { 413
402 is_default: func.default_token().is_some(), 414 let mut flags = FnFlags::empty();
403 is_const: func.const_token().is_some(), 415 if func.body().is_some() {
404 is_async: func.async_token().is_some(), 416 flags |= FnFlags::HAS_BODY;
405 is_unsafe: func.unsafe_token().is_some(), 417 }
406 abi: func.abi().map(|abi| { 418 if has_self_param {
407 // FIXME: Abi::abi() -> Option<SyntaxToken>? 419 flags |= FnFlags::HAS_SELF_PARAM;
408 match abi.syntax().last_token() { 420 }
409 Some(tok) if tok.kind() == SyntaxKind::STRING => { 421 if func.default_token().is_some() {
410 // FIXME: Better way to unescape? 422 flags |= FnFlags::IS_DEFAULT;
411 tok.text().trim_matches('"').into() 423 }
412 } 424 if func.const_token().is_some() {
413 _ => { 425 flags |= FnFlags::IS_CONST;
414 // `extern` default to be `extern "C"`. 426 }
415 "C".into() 427 if func.async_token().is_some() {
416 } 428 flags |= FnFlags::IS_ASYNC;
417 } 429 }
418 }), 430 if func.unsafe_token().is_some() {
419 }; 431 flags |= FnFlags::IS_UNSAFE;
432 }
433
420 let mut res = Function { 434 let mut res = Function {
421 name, 435 name,
422 visibility, 436 visibility,
423 generic_params: GenericParamsId::EMPTY, 437 generic_params: GenericParamsId::EMPTY,
424 has_self_param, 438 abi,
425 has_body,
426 qualifier,
427 is_in_extern_block: false,
428 params, 439 params,
429 ret_type: Interned::new(ret_type), 440 ret_type: Interned::new(ret_type),
430 ast_id, 441 ast_id,
442 flags,
431 }; 443 };
432 res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func); 444 res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func);
433 445
@@ -640,8 +652,10 @@ impl Ctx {
640 ast::ExternItem::Fn(ast) => { 652 ast::ExternItem::Fn(ast) => {
641 let func_id = self.lower_function(&ast)?; 653 let func_id = self.lower_function(&ast)?;
642 let func = &mut self.data().functions[func_id.index]; 654 let func = &mut self.data().functions[func_id.index];
643 func.qualifier.is_unsafe = is_intrinsic_fn_unsafe(&func.name); 655 if is_intrinsic_fn_unsafe(&func.name) {
644 func.is_in_extern_block = true; 656 func.flags |= FnFlags::IS_UNSAFE;
657 }
658 func.flags |= FnFlags::IS_IN_EXTERN_BLOCK;
645 func_id.into() 659 func_id.into()
646 } 660 }
647 ast::ExternItem::Static(ast) => { 661 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> {
91 91
92 fn validate_func(&mut self, func: FunctionId) { 92 fn validate_func(&mut self, func: FunctionId) {
93 let data = self.db.function_data(func); 93 let data = self.db.function_data(func);
94 if data.is_in_extern_block { 94 if data.is_in_extern_block() {
95 cov_mark::hit!(extern_func_incorrect_case_ignored); 95 cov_mark::hit!(extern_func_incorrect_case_ignored);
96 return; 96 return;
97 } 97 }
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> {
32 let def = self.owner; 32 let def = self.owner;
33 let unsafe_expressions = unsafe_expressions(db, self.infer.as_ref(), def); 33 let unsafe_expressions = unsafe_expressions(db, self.infer.as_ref(), def);
34 let is_unsafe = match self.owner { 34 let is_unsafe = match self.owner {
35 DefWithBodyId::FunctionId(it) => db.function_data(it).qualifier.is_unsafe, 35 DefWithBodyId::FunctionId(it) => db.function_data(it).is_unsafe(),
36 DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) => false, 36 DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) => false,
37 }; 37 };
38 if is_unsafe 38 if is_unsafe
@@ -86,7 +86,7 @@ fn walk_unsafe(
86 match expr { 86 match expr {
87 &Expr::Call { callee, .. } => { 87 &Expr::Call { callee, .. } => {
88 if let Some(func) = infer[callee].as_fn_def(db) { 88 if let Some(func) = infer[callee].as_fn_def(db) {
89 if db.function_data(func).qualifier.is_unsafe { 89 if db.function_data(func).is_unsafe() {
90 unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block }); 90 unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block });
91 } 91 }
92 } 92 }
@@ -103,7 +103,7 @@ fn walk_unsafe(
103 Expr::MethodCall { .. } => { 103 Expr::MethodCall { .. } => {
104 if infer 104 if infer
105 .method_resolution(current) 105 .method_resolution(current)
106 .map(|func| db.function_data(func).qualifier.is_unsafe) 106 .map(|func| db.function_data(func).is_unsafe())
107 .unwrap_or(false) 107 .unwrap_or(false)
108 { 108 {
109 unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block }); 109 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 {
1054 let ret = (&ctx_ret).lower_ty(&data.ret_type); 1054 let ret = (&ctx_ret).lower_ty(&data.ret_type);
1055 let generics = generics(db.upcast(), def.into()); 1055 let generics = generics(db.upcast(), def.into());
1056 let num_binders = generics.len(); 1056 let num_binders = generics.len();
1057 Binders::new(num_binders, CallableSig::from_params_and_return(params, ret, data.is_varargs)) 1057 Binders::new(num_binders, CallableSig::from_params_and_return(params, ret, data.is_varargs()))
1058} 1058}
1059 1059
1060/// Build the declared type of a function. This should not need to look at the 1060/// 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(
675 } 675 }
676 } 676 }
677 if let Some(receiver_ty) = receiver_ty { 677 if let Some(receiver_ty) = receiver_ty {
678 if !data.has_self_param { 678 if !data.has_self_param() {
679 return false; 679 return false;
680 } 680 }
681 let transformed_receiver_ty = match transform_receiver_ty(db, m, self_ty) { 681 let transformed_receiver_ty = match transform_receiver_ty(db, m, self_ty) {