]> git.lizzy.rs Git - rust.git/commitdiff
Use bitflags to compress function properties
authorJonas Schievink <jonasschievink@gmail.com>
Sat, 3 Apr 2021 18:58:42 +0000 (20:58 +0200)
committerJonas Schievink <jonasschievink@gmail.com>
Sat, 3 Apr 2021 18:58:42 +0000 (20:58 +0200)
Very minor savings, only 1 MB or so

Cargo.lock
crates/hir/src/display.rs
crates/hir/src/lib.rs
crates/hir_def/Cargo.toml
crates/hir_def/src/data.rs
crates/hir_def/src/item_tree.rs
crates/hir_def/src/item_tree/lower.rs
crates/hir_ty/src/diagnostics/decl_check.rs
crates/hir_ty/src/diagnostics/unsafe_check.rs
crates/hir_ty/src/lower.rs
crates/hir_ty/src/method_resolution.rs

index 05383d8b7e465621feebc2fa27bdbb2082625f1d..4531d8fb1cbabb1c5a2060958eb9e7655dff24f6 100644 (file)
@@ -498,6 +498,7 @@ version = "0.0.0"
 dependencies = [
  "anymap",
  "base_db",
+ "bitflags",
  "cfg",
  "cov-mark",
  "dashmap",
index ab04c55bc19e02498350bbc019599854eecbe4a2..559ea31a0ac3afbec597b9f0dc3c087eb105dc2d 100644 (file)
@@ -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 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
                 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 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
         // `FunctionData::ret_type` will be `::core::future::Future<Output = ...>` 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 {
index 29010191b5e675799d252b0f9b09a590580b0430..eb19e4b51a888070e5b104c0d7ecedb802a528f8 100644 (file)
@@ -832,7 +832,7 @@ pub fn ret_type(self, db: &dyn HirDatabase) -> Type {
     }
 
     pub fn self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> {
-        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 @@ pub fn method_params(self, db: &dyn HirDatabase) -> Option<Vec<Param>> {
     }
 
     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 @@ pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) {
     ///
     /// 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.
index 43324d8d9b160319a3c6c725383c429db3e12e5d..60adb655c75b80d1cad8982b07ac851f6457c410 100644 (file)
@@ -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"
index 31f994681960a893fc0a3759532937e9e4960696..b409fb45cdb656d87bfb9ae44da02b9c588abf8d 100644 (file)
@@ -10,7 +10,7 @@
     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<Interned<TypeRef>>,
     pub ret_type: Interned<TypeRef>,
     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<Interned<str>>,
+    flags: FnFlags,
 }
 
 impl FunctionData {
@@ -53,6 +48,11 @@ pub(crate) fn fn_data_query(db: &dyn DefDatabase, func: FunctionId) -> Arc<Funct
             .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 @@ pub(crate) fn fn_data_query(db: &dyn DefDatabase, func: FunctionId) -> Arc<Funct
                 .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)]
index dd80cef23a59a3b4cc37bcb3c000292da97fcb81..c6d700977e365484d1b7916568cc228278c69666 100644 (file)
@@ -24,7 +24,7 @@
 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<Interned<str>>,
     pub params: IdRange<Param>,
     pub ret_type: Interned<TypeRef>,
     pub ast_id: FileAstId<ast::Fn>,
+    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<SmolStr>,
+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)]
index ead7cd7a4588549868da3b6cf6e628e32204b3e3..39e8403b0999d8b854c541f012a84394cb38be4b 100644 (file)
@@ -395,39 +395,51 @@ fn lower_function(&mut self, func: &ast::Fn) -> Option<FileItemTreeId<Function>>
             ret_type
         };
 
-        let has_body = func.body().is_some();
+        let abi = func.abi().map(|abi| {
+            // FIXME: Abi::abi() -> Option<SyntaxToken>?
+            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<SyntaxToken>?
-                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 @@ fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> Vec<ModItem> {
                         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) => {
index 33a0f4d7d484bbf9c8fd590054403900b1a6f736..207c7cb824e984df0f15c783daebadf495a4851e 100644 (file)
@@ -91,7 +91,7 @@ fn allowed(&self, id: AttrDefId, allow_name: &str) -> bool {
 
     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;
         }
index a71eebc6fa4a8395f5ea504781b7e1c8f7ebaf9d..b5efe9df5c45b19c4721bf975690940b7a452362 100644 (file)
@@ -32,7 +32,7 @@ pub(super) fn validate_body(&mut self, db: &dyn HirDatabase) {
         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 });
index f595683e5f983387581f38cf74810a58e4427216..e60d7c730dad3722a14d2e6b59b3ec3bb71de6cf 100644 (file)
@@ -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
index 338851fa81dca8e18e59587776a192e7653c7aaa..c093fce2017d277d7974ec3983c6f4603c9349f7 100644 (file)
@@ -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) {