diff --git a/crates/hir-def/src/adt.rs b/crates/hir-def/src/adt.rs index 277135d6dc..7850958006 100644 --- a/crates/hir-def/src/adt.rs +++ b/crates/hir-def/src/adt.rs @@ -1,6 +1,6 @@ //! Defines hir-level representation of structs, enums and unions -use std::sync::Arc; +use std::{num::NonZeroU32, sync::Arc}; use base_db::CrateId; use either::Either; @@ -14,6 +14,7 @@ use tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree}; use crate::{ body::{CfgExpander, LowerCtx}, + builtin_type::{BuiltinInt, BuiltinUint}, db::DefDatabase, intern::Interned, item_tree::{AttrOwner, Field, Fields, ItemTree, ModItem, RawVisibilityId}, @@ -31,7 +32,7 @@ use cfg::CfgOptions; pub struct StructData { pub name: Name, pub variant_data: Arc, - pub repr: Option, + pub repr: Option, pub visibility: RawVisibility, } @@ -39,6 +40,7 @@ pub struct StructData { pub struct EnumData { pub name: Name, pub variants: Arena, + pub repr: Option, pub visibility: RawVisibility, } @@ -63,10 +65,19 @@ pub struct FieldData { pub visibility: RawVisibility, } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Copy, Debug, Clone, PartialEq, Eq)] pub enum ReprKind { - Packed, - Other, + C, + BuiltinInt { builtin: Either, is_c: bool }, + Transparent, + Default, +} + +#[derive(Copy, Debug, Clone, PartialEq, Eq)] +pub struct ReprData { + pub kind: ReprKind, + pub packed: bool, + pub align: Option, } fn repr_from_value( @@ -74,21 +85,60 @@ fn repr_from_value( krate: CrateId, item_tree: &ItemTree, of: AttrOwner, -) -> Option { +) -> Option { item_tree.attrs(db, krate, of).by_key("repr").tt_values().find_map(parse_repr_tt) } -fn parse_repr_tt(tt: &Subtree) -> Option { +fn parse_repr_tt(tt: &Subtree) -> Option { match tt.delimiter { Some(Delimiter { kind: DelimiterKind::Parenthesis, .. }) => {} _ => return None, } - let mut it = tt.token_trees.iter(); - match it.next()? { - TokenTree::Leaf(Leaf::Ident(ident)) if ident.text == "packed" => Some(ReprKind::Packed), - _ => Some(ReprKind::Other), + let mut data = ReprData { kind: ReprKind::Default, packed: false, align: None }; + + let mut tts = tt.token_trees.iter().peekable(); + while let Some(tt) = tts.next() { + if let TokenTree::Leaf(Leaf::Ident(ident)) = tt { + match &*ident.text { + "packed" => { + data.packed = true; + if let Some(TokenTree::Subtree(_)) = tts.peek() { + tts.next(); + } + } + "align" => { + if let Some(TokenTree::Subtree(tt)) = tts.peek() { + tts.next(); + if let Some(TokenTree::Leaf(Leaf::Literal(lit))) = tt.token_trees.first() { + if let Ok(align) = lit.text.parse() { + data.align = Some(align); + } + } + } + } + "C" => { + if let ReprKind::BuiltinInt { is_c, .. } = &mut data.kind { + *is_c = true; + } else { + data.kind = ReprKind::C; + } + } + "transparent" => data.kind = ReprKind::Transparent, + repr => { + let is_c = matches!(data.kind, ReprKind::C); + if let Some(builtin) = BuiltinInt::from_suffix(repr) + .map(Either::Left) + .or_else(|| BuiltinUint::from_suffix(repr).map(Either::Right)) + { + data.kind = ReprKind::BuiltinInt { builtin, is_c }; + } + } + } + } } + + Some(data) } impl StructData { @@ -108,6 +158,7 @@ impl StructData { visibility: item_tree[strukt.visibility].clone(), }) } + pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc { let loc = id.lookup(db); let krate = loc.container.krate; @@ -133,6 +184,7 @@ impl EnumData { let krate = loc.container.krate; let item_tree = loc.id.item_tree(db); let cfg_options = db.crate_graph()[krate].cfg_options.clone(); + let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into()); let enum_ = &item_tree[loc.id.value]; let mut variants = Arena::new(); @@ -158,6 +210,7 @@ impl EnumData { Arc::new(EnumData { name: enum_.name.clone(), variants, + repr, visibility: item_tree[enum_.visibility].clone(), }) } diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index 4c44840e86..5c7aa72349 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -479,7 +479,6 @@ pub enum DefWithBodyId { impl_from!(FunctionId, ConstId, StaticId for DefWithBodyId); -// FIXME: Rename EnumVariantId to VariantId so that the macro above can be used impl From for DefWithBodyId { fn from(id: EnumVariantId) -> Self { DefWithBodyId::VariantId(id) diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs index e16530ecc1..9ac5eaa74e 100644 --- a/crates/hir-ty/src/db.rs +++ b/crates/hir-ty/src/db.rs @@ -44,12 +44,12 @@ pub trait HirDatabase: DefDatabase + Upcast { #[salsa::invoke(crate::lower::const_param_ty_query)] fn const_param_ty(&self, def: ConstParamId) -> Ty; - #[salsa::invoke(crate::consteval::const_eval_query)] + #[salsa::invoke(crate::consteval::const_eval_variant_query)] #[salsa::cycle(crate::consteval::const_eval_recover)] fn const_eval(&self, def: ConstId) -> Result; #[salsa::invoke(crate::consteval::const_eval_query_variant)] - #[salsa::cycle(crate::consteval::const_eval_recover_variant)] + #[salsa::cycle(crate::consteval::const_eval_variant_recover)] fn const_eval_variant(&self, def: EnumVariantId) -> Result; #[salsa::invoke(crate::lower::impl_trait_query)] diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 7d1c982075..85309d3233 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -67,9 +67,12 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc ctx.collect_const(&db.const_data(c)), DefWithBodyId::FunctionId(f) => ctx.collect_fn(f), DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_data(s)), - DefWithBodyId::VariantId(v) => { + DefWithBodyId::VariantId(_v) => { + // db.enum_data(v.parent) // FIXME: This should return the `repr(...)` type of the enum - ctx.return_ty = TyBuilder::def_ty(db, v.parent.into()).fill_with_unknown().build() + ctx.return_ty = TyBuilder::builtin(hir_def::builtin_type::BuiltinType::Uint( + hir_def::builtin_type::BuiltinUint::U32, + )); } } diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 389e07db33..7d25eee0c0 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -39,7 +39,7 @@ use arrayvec::ArrayVec; use base_db::{CrateDisplayName, CrateId, CrateOrigin, Edition, FileId, ProcMacroKind}; use either::Either; use hir_def::{ - adt::{ReprKind, VariantData}, + adt::{ReprData, VariantData}, body::{BodyDiagnostic, SyntheticSyntax}, expr::{BindingAnnotation, LabelId, Pat, PatId}, generics::{TypeOrConstParamData, TypeParamProvenance}, @@ -874,7 +874,7 @@ impl Struct { Type::from_def(db, self.id) } - pub fn repr(self, db: &dyn HirDatabase) -> Option { + pub fn repr(self, db: &dyn HirDatabase) -> Option { db.struct_data(self.id).repr.clone() } @@ -2964,7 +2964,7 @@ impl Type { let adt = adt_id.into(); match adt { - Adt::Struct(s) => matches!(s.repr(db), Some(ReprKind::Packed)), + Adt::Struct(s) => matches!(s.repr(db), Some(ReprData { packed: true, .. })), _ => false, } }