diff --git a/crates/base-db/src/fixture.rs b/crates/base-db/src/fixture.rs index 5b11343173b3..d3abc3870b70 100644 --- a/crates/base-db/src/fixture.rs +++ b/crates/base-db/src/fixture.rs @@ -215,7 +215,7 @@ impl ChangeFixture { None, default_cfg, Default::default(), - Env::default(), + Env::new_for_test_fixture(), false, CrateOrigin::Local { repo: None, name: None }, default_target_data_layout @@ -259,7 +259,7 @@ impl ChangeFixture { None, Default::default(), Default::default(), - Env::default(), + Env::new_for_test_fixture(), false, CrateOrigin::Lang(LangCrateOrigin::Core), target_layout.clone(), @@ -298,7 +298,7 @@ impl ChangeFixture { None, Default::default(), Default::default(), - Env::default(), + Env::new_for_test_fixture(), true, CrateOrigin::Local { repo: None, name: None }, target_layout, diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs index e8d521b42f86..64b026f4da56 100644 --- a/crates/base-db/src/input.rs +++ b/crates/base-db/src/input.rs @@ -151,6 +151,12 @@ pub enum CrateOrigin { Lang(LangCrateOrigin), } +impl CrateOrigin { + pub fn is_local(&self) -> bool { + matches!(self, CrateOrigin::Local { .. }) + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum LangCrateOrigin { Alloc, @@ -333,6 +339,17 @@ pub struct Env { entries: FxHashMap, } +impl Env { + pub fn new_for_test_fixture() -> Self { + Env { + entries: FxHashMap::from_iter([( + String::from("__ra_is_test_fixture"), + String::from("__ra_is_test_fixture"), + )]), + } + } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Dependency { pub crate_id: CrateId, @@ -456,6 +473,10 @@ impl CrateGraph { self.arena.iter().map(|(idx, _)| idx) } + pub fn iter_mut(&mut self) -> impl Iterator + '_ { + self.arena.iter_mut() + } + /// Returns an iterator over all transitive dependencies of the given crate, /// including the crate itself. pub fn transitive_deps(&self, of: CrateId) -> impl Iterator { diff --git a/crates/hir-def/src/body.rs b/crates/hir-def/src/body.rs index 36626ed1a9b1..3ed7dfefc0fc 100644 --- a/crates/hir-def/src/body.rs +++ b/crates/hir-def/src/body.rs @@ -118,7 +118,7 @@ impl Body { let _p = profile::span("body_with_source_map_query"); let mut params = None; - let (file_id, module, body, is_async_fn) = { + let (file_id, body, is_async_fn) = { match def { DefWithBodyId::FunctionId(f) => { let data = db.function_data(f); @@ -138,31 +138,29 @@ impl Body { }), ) }); - ( - src.file_id, - f.module(db), - src.value.body().map(ast::Expr::from), - data.has_async_kw(), - ) + (src.file_id, src.value.body().map(ast::Expr::from), data.has_async_kw()) } DefWithBodyId::ConstId(c) => { let c = c.lookup(db); let src = c.source(db); - (src.file_id, c.module(db), src.value.body(), false) + (src.file_id, src.value.body(), false) } DefWithBodyId::StaticId(s) => { let s = s.lookup(db); let src = s.source(db); - (src.file_id, s.module(db), src.value.body(), false) + (src.file_id, src.value.body(), false) } DefWithBodyId::VariantId(v) => { - let e = v.parent.lookup(db); let src = v.parent.child_source(db); let variant = &src.value[v.local_id]; - (src.file_id, e.container, variant.expr(), false) + (src.file_id, variant.expr(), false) + } + DefWithBodyId::InTypeConstId(c) => { + (c.lookup(db).0.file_id, c.source(db).expr(), false) } } }; + let module = def.module(db); let expander = Expander::new(db, file_id, module); let (mut body, source_map) = Body::new(db, def, expander, params, body, module.krate, is_async_fn); diff --git a/crates/hir-def/src/body/pretty.rs b/crates/hir-def/src/body/pretty.rs index 88380aa355d1..cd6df0e6325c 100644 --- a/crates/hir-def/src/body/pretty.rs +++ b/crates/hir-def/src/body/pretty.rs @@ -40,6 +40,7 @@ pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBo }; format!("const {name} = ") } + DefWithBodyId::InTypeConstId(_) => format!("In type const = "), DefWithBodyId::VariantId(it) => { let src = it.parent.child_source(db); let variant = &src.value[it.local_id]; diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs index 6d18e3f56cab..e6a6eb03497f 100644 --- a/crates/hir-def/src/db.rs +++ b/crates/hir-def/src/db.rs @@ -1,7 +1,7 @@ //! Defines database & queries for name resolution. use base_db::{salsa, CrateId, SourceDatabase, Upcast}; use either::Either; -use hir_expand::{db::ExpandDatabase, HirFileId}; +use hir_expand::{db::ExpandDatabase, AstId, HirFileId}; use intern::Interned; use la_arena::ArenaMap; use syntax::{ast, AstPtr}; @@ -22,11 +22,12 @@ use crate::{ lang_item::{LangItem, LangItemTarget, LangItems}, nameres::{diagnostics::DefDiagnostic, DefMap}, visibility::{self, Visibility}, - AnonymousConstId, AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, - EnumLoc, ExternBlockId, ExternBlockLoc, FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, - LocalEnumVariantId, LocalFieldId, Macro2Id, Macro2Loc, MacroRulesId, MacroRulesLoc, - ProcMacroId, ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, TraitAliasId, - TraitAliasLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, VariantId, + AttrDefId, BlockId, BlockLoc, ConstBlockId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, + ExternBlockId, ExternBlockLoc, FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, + InTypeConstId, LocalEnumVariantId, LocalFieldId, Macro2Id, Macro2Loc, MacroRulesId, + MacroRulesLoc, OpaqueInternableThing, ProcMacroId, ProcMacroLoc, StaticId, StaticLoc, StructId, + StructLoc, TraitAliasId, TraitAliasLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, + TypeOwnerId, UnionId, UnionLoc, VariantId, }; #[salsa::query_group(InternDatabaseStorage)] @@ -62,7 +63,12 @@ pub trait InternDatabase: SourceDatabase { #[salsa::interned] fn intern_macro_rules(&self, loc: MacroRulesLoc) -> MacroRulesId; #[salsa::interned] - fn intern_anonymous_const(&self, id: (DefWithBodyId, ExprId)) -> AnonymousConstId; + fn intern_anonymous_const(&self, id: (DefWithBodyId, ExprId)) -> ConstBlockId; + #[salsa::interned] + fn intern_in_type_const( + &self, + id: (AstId, TypeOwnerId, Box), + ) -> InTypeConstId; } #[salsa::query_group(DefDatabaseStorage)] diff --git a/crates/hir-def/src/expander.rs b/crates/hir-def/src/expander.rs index 31653916f411..a588827c8d39 100644 --- a/crates/hir-def/src/expander.rs +++ b/crates/hir-def/src/expander.rs @@ -155,7 +155,7 @@ impl Expander { } pub(crate) fn parse_path(&mut self, db: &dyn DefDatabase, path: ast::Path) -> Option { - let ctx = LowerCtx::with_hygiene(db, &self.cfg_expander.hygiene); + let ctx = LowerCtx::new(db, &self.cfg_expander.hygiene, self.current_file_id); Path::from_src(path, &ctx) } diff --git a/crates/hir-def/src/hir.rs b/crates/hir-def/src/hir.rs index 4ad8a7aa8eb1..77d879a77ba5 100644 --- a/crates/hir-def/src/hir.rs +++ b/crates/hir-def/src/hir.rs @@ -26,7 +26,7 @@ use crate::{ builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint}, path::{GenericArgs, Path}, type_ref::{Mutability, Rawness, TypeRef}, - AnonymousConstId, BlockId, + BlockId, ConstBlockId, }; pub use syntax::ast::{ArithOp, BinaryOp, CmpOp, LogicOp, Ordering, RangeOp, UnaryOp}; @@ -181,7 +181,7 @@ pub enum Expr { statements: Box<[Statement]>, tail: Option, }, - Const(AnonymousConstId), + Const(ConstBlockId), Unsafe { id: Option, statements: Box<[Statement]>, diff --git a/crates/hir-def/src/hir/type_ref.rs b/crates/hir-def/src/hir/type_ref.rs index 0573c9a6f8af..fa1f4933a266 100644 --- a/crates/hir-def/src/hir/type_ref.rs +++ b/crates/hir-def/src/hir/type_ref.rs @@ -118,7 +118,7 @@ pub enum TypeRef { Reference(Box, Option, Mutability), // FIXME: for full const generics, the latter element (length) here is going to have to be an // expression that is further lowered later in hir_ty. - Array(Box, ConstRefOrPath), + Array(Box, ConstRef), Slice(Box), /// A fn pointer. Last element of the vector is the return type. Fn(Vec<(Option, TypeRef)>, bool /*varargs*/, bool /*is_unsafe*/), @@ -186,11 +186,7 @@ impl TypeRef { TypeRef::RawPtr(Box::new(inner_ty), mutability) } ast::Type::ArrayType(inner) => { - // FIXME: This is a hack. We should probably reuse the machinery of - // `hir_def::body::lower` to lower this into an `Expr` and then evaluate it at the - // `hir_ty` level, which would allow knowing the type of: - // let v: [u8; 2 + 2] = [0u8; 4]; - let len = ConstRefOrPath::from_expr_opt(inner.expr()); + let len = ConstRef::from_const_arg(ctx, inner.const_arg()); TypeRef::Array(Box::new(TypeRef::from_ast_opt(ctx, inner.ty())), len) } ast::Type::SliceType(inner) => { @@ -380,73 +376,84 @@ impl TypeBound { } #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum ConstRefOrPath { - Scalar(ConstRef), +pub enum ConstRef { + Scalar(LiteralConstRef), Path(Name), + Complex(AstId), } -impl ConstRefOrPath { - pub(crate) fn from_expr_opt(expr: Option) -> Self { - match expr { - Some(x) => Self::from_expr(x), - None => Self::Scalar(ConstRef::Unknown), +impl ConstRef { + pub(crate) fn from_const_arg(lower_ctx: &LowerCtx<'_>, arg: Option) -> Self { + if let Some(arg) = arg { + let ast_id = lower_ctx.ast_id(&arg); + if let Some(expr) = arg.expr() { + return Self::from_expr(expr, ast_id); + } } + Self::Scalar(LiteralConstRef::Unknown) } pub fn display<'a>(&'a self, db: &'a dyn ExpandDatabase) -> impl fmt::Display + 'a { - struct Display<'a>(&'a dyn ExpandDatabase, &'a ConstRefOrPath); + struct Display<'a>(&'a dyn ExpandDatabase, &'a ConstRef); impl fmt::Display for Display<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.1 { - ConstRefOrPath::Scalar(s) => s.fmt(f), - ConstRefOrPath::Path(n) => n.display(self.0).fmt(f), + ConstRef::Scalar(s) => s.fmt(f), + ConstRef::Path(n) => n.display(self.0).fmt(f), + ConstRef::Complex(_) => f.write_str("{const}"), } } } Display(db, self) } - // FIXME: as per the comments on `TypeRef::Array`, this evaluation should not happen at this - // parse stage. - fn from_expr(expr: ast::Expr) -> Self { + // We special case literals and single identifiers, to speed up things. + fn from_expr(expr: ast::Expr, ast_id: Option>) -> Self { + fn is_path_ident(p: &ast::PathExpr) -> bool { + let Some(path) = p.path() else { + return false; + }; + if path.coloncolon_token().is_some() { + return false; + } + if let Some(s) = path.segment() { + if s.coloncolon_token().is_some() || s.generic_arg_list().is_some() { + return false; + } + } + true + } match expr { - ast::Expr::PathExpr(p) => { + ast::Expr::PathExpr(p) if is_path_ident(&p) => { match p.path().and_then(|x| x.segment()).and_then(|x| x.name_ref()) { Some(x) => Self::Path(x.as_name()), - None => Self::Scalar(ConstRef::Unknown), + None => Self::Scalar(LiteralConstRef::Unknown), } } - ast::Expr::PrefixExpr(prefix_expr) => match prefix_expr.op_kind() { - Some(ast::UnaryOp::Neg) => { - let unsigned = Self::from_expr_opt(prefix_expr.expr()); - // Add sign - match unsigned { - Self::Scalar(ConstRef::UInt(num)) => { - Self::Scalar(ConstRef::Int(-(num as i128))) - } - other => other, - } - } - _ => Self::from_expr_opt(prefix_expr.expr()), - }, ast::Expr::Literal(literal) => Self::Scalar(match literal.kind() { ast::LiteralKind::IntNumber(num) => { - num.value().map(ConstRef::UInt).unwrap_or(ConstRef::Unknown) + num.value().map(LiteralConstRef::UInt).unwrap_or(LiteralConstRef::Unknown) } ast::LiteralKind::Char(c) => { - c.value().map(ConstRef::Char).unwrap_or(ConstRef::Unknown) + c.value().map(LiteralConstRef::Char).unwrap_or(LiteralConstRef::Unknown) } - ast::LiteralKind::Bool(f) => ConstRef::Bool(f), - _ => ConstRef::Unknown, + ast::LiteralKind::Bool(f) => LiteralConstRef::Bool(f), + _ => LiteralConstRef::Unknown, }), - _ => Self::Scalar(ConstRef::Unknown), + _ => { + if let Some(ast_id) = ast_id { + Self::Complex(ast_id) + } else { + Self::Scalar(LiteralConstRef::Unknown) + } + } } } } -/// A concrete constant value +/// A literal constant value #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum ConstRef { +pub enum LiteralConstRef { Int(i128), UInt(u128), Bool(bool), @@ -460,18 +467,20 @@ pub enum ConstRef { Unknown, } -impl ConstRef { +impl LiteralConstRef { pub fn builtin_type(&self) -> BuiltinType { match self { - ConstRef::UInt(_) | ConstRef::Unknown => BuiltinType::Uint(BuiltinUint::U128), - ConstRef::Int(_) => BuiltinType::Int(BuiltinInt::I128), - ConstRef::Char(_) => BuiltinType::Char, - ConstRef::Bool(_) => BuiltinType::Bool, + LiteralConstRef::UInt(_) | LiteralConstRef::Unknown => { + BuiltinType::Uint(BuiltinUint::U128) + } + LiteralConstRef::Int(_) => BuiltinType::Int(BuiltinInt::I128), + LiteralConstRef::Char(_) => BuiltinType::Char, + LiteralConstRef::Bool(_) => BuiltinType::Bool, } } } -impl From for ConstRef { +impl From for LiteralConstRef { fn from(literal: Literal) -> Self { match literal { Literal::Char(c) => Self::Char(c), @@ -483,14 +492,14 @@ impl From for ConstRef { } } -impl std::fmt::Display for ConstRef { +impl std::fmt::Display for LiteralConstRef { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { match self { - ConstRef::Int(num) => num.fmt(f), - ConstRef::UInt(num) => num.fmt(f), - ConstRef::Bool(flag) => flag.fmt(f), - ConstRef::Char(c) => write!(f, "'{c}'"), - ConstRef::Unknown => f.write_char('_'), + LiteralConstRef::Int(num) => num.fmt(f), + LiteralConstRef::UInt(num) => num.fmt(f), + LiteralConstRef::Bool(flag) => flag.fmt(f), + LiteralConstRef::Char(c) => write!(f, "'{c}'"), + LiteralConstRef::Unknown => f.write_char('_'), } } } diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index 98cff54cc22d..4f68093bcbe2 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -57,7 +57,10 @@ mod test_db; mod macro_expansion_tests; mod pretty; -use std::hash::{Hash, Hasher}; +use std::{ + hash::{Hash, Hasher}, + panic::{RefUnwindSafe, UnwindSafe}, +}; use base_db::{ impl_intern_key, @@ -89,8 +92,8 @@ use crate::{ builtin_type::BuiltinType, data::adt::VariantData, item_tree::{ - Const, Enum, Function, Impl, ItemTreeId, ItemTreeNode, MacroDef, MacroRules, ModItem, - Static, Struct, Trait, TraitAlias, TypeAlias, Union, + Const, Enum, Function, Impl, ItemTreeId, ItemTreeNode, MacroDef, MacroRules, Static, + Struct, Trait, TraitAlias, TypeAlias, Union, }, }; @@ -476,29 +479,183 @@ impl_from!( for ModuleDefId ); -// FIXME: make this a DefWithBodyId +/// Id of the anonymous const block expression and patterns. This is very similar to `ClosureId` and +/// shouldn't be a `DefWithBodyId` since its type inference is dependent on its parent. +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +pub struct ConstBlockId(InternId); +impl_intern_key!(ConstBlockId); + +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +pub enum TypeOwnerId { + FunctionId(FunctionId), + StaticId(StaticId), + ConstId(ConstId), + InTypeConstId(InTypeConstId), + AdtId(AdtId), + TraitId(TraitId), + TraitAliasId(TraitAliasId), + TypeAliasId(TypeAliasId), + ImplId(ImplId), + EnumVariantId(EnumVariantId), + // FIXME(const-generic-body): ModuleId should not be a type owner. This needs to be fixed to make `TypeOwnerId` actually + // useful for assigning ids to in type consts. + ModuleId(ModuleId), +} + +impl TypeOwnerId { + fn as_generic_def_id(self) -> Option { + Some(match self { + TypeOwnerId::FunctionId(x) => GenericDefId::FunctionId(x), + TypeOwnerId::ConstId(x) => GenericDefId::ConstId(x), + TypeOwnerId::AdtId(x) => GenericDefId::AdtId(x), + TypeOwnerId::TraitId(x) => GenericDefId::TraitId(x), + TypeOwnerId::TraitAliasId(x) => GenericDefId::TraitAliasId(x), + TypeOwnerId::TypeAliasId(x) => GenericDefId::TypeAliasId(x), + TypeOwnerId::ImplId(x) => GenericDefId::ImplId(x), + TypeOwnerId::EnumVariantId(x) => GenericDefId::EnumVariantId(x), + TypeOwnerId::InTypeConstId(_) | TypeOwnerId::ModuleId(_) | TypeOwnerId::StaticId(_) => { + return None + } + }) + } +} + +impl_from!( + FunctionId, + StaticId, + ConstId, + InTypeConstId, + AdtId, + TraitId, + TraitAliasId, + TypeAliasId, + ImplId, + EnumVariantId, + ModuleId + for TypeOwnerId +); + +// Every `DefWithBodyId` is a type owner, since bodies can contain type (e.g. `{ let x: Type = _; }`) +impl From for TypeOwnerId { + fn from(value: DefWithBodyId) -> Self { + match value { + DefWithBodyId::FunctionId(x) => x.into(), + DefWithBodyId::StaticId(x) => x.into(), + DefWithBodyId::ConstId(x) => x.into(), + DefWithBodyId::InTypeConstId(x) => x.into(), + DefWithBodyId::VariantId(x) => x.into(), + } + } +} + +impl From for TypeOwnerId { + fn from(value: GenericDefId) -> Self { + match value { + GenericDefId::FunctionId(x) => x.into(), + GenericDefId::AdtId(x) => x.into(), + GenericDefId::TraitId(x) => x.into(), + GenericDefId::TraitAliasId(x) => x.into(), + GenericDefId::TypeAliasId(x) => x.into(), + GenericDefId::ImplId(x) => x.into(), + GenericDefId::EnumVariantId(x) => x.into(), + GenericDefId::ConstId(x) => x.into(), + } + } +} + +/// A thing that we want to store in interned ids, but we don't know its type in `hir-def`. This is +/// currently only used in `InTypeConstId` for storing the type (which has type `Ty` defined in +/// the `hir-ty` crate) of the constant in its id, which is a temporary hack so we may want +/// to remove this after removing that. +pub trait OpaqueInternableThing: + std::any::Any + std::fmt::Debug + Sync + Send + UnwindSafe + RefUnwindSafe +{ + fn as_any(&self) -> &dyn std::any::Any; + fn box_any(&self) -> Box; + fn dyn_hash(&self, state: &mut dyn Hasher); + fn dyn_eq(&self, other: &dyn OpaqueInternableThing) -> bool; + fn dyn_clone(&self) -> Box; +} + +impl Hash for dyn OpaqueInternableThing { + fn hash(&self, state: &mut H) { + self.dyn_hash(state); + } +} + +impl PartialEq for dyn OpaqueInternableThing { + fn eq(&self, other: &Self) -> bool { + self.dyn_eq(other) + } +} + +impl Eq for dyn OpaqueInternableThing {} + +impl Clone for Box { + fn clone(&self) -> Self { + self.dyn_clone() + } +} + +// FIXME(const-generic-body): Use an stable id for in type consts. +// +// The current id uses `AstId` which will be changed by every change in the code. Ideally +// we should use an id which is relative to the type owner, so that every change will only invalidate the +// id if it happens inside of the type owner. +// +// The solution probably is to have some query on `TypeOwnerId` to traverse its constant children and store +// their `AstId` in a list (vector or arena), and use the index of that list in the id here. That query probably +// needs name resolution, and might go far and handles the whole path lowering or type lowering for a `TypeOwnerId`. +// +// Whatever path the solution takes, it should answer 3 questions at the same time: +// * Is the id stable enough? +// * How to find a constant id using an ast node / position in the source code? This is needed when we want to +// provide ide functionalities inside an in type const (which we currently don't support) e.g. go to definition +// for a local defined there. A complex id might have some trouble in this reverse mapping. +// * How to find the return type of a constant using its id? We have this data when we are doing type lowering +// and the name of the struct that contains this constant is resolved, so a query that only traverses the +// type owner by its syntax tree might have a hard time here. + +/// A constant in a type as a substitution for const generics (like `Foo<{ 2 + 2 }>`) or as an array +/// length (like `[u8; 2 + 2]`). These constants are body owner and are a variant of `DefWithBodyId`. These +/// are not called `AnonymousConstId` to prevent confusion with [`ConstBlockId`]. #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] -pub struct AnonymousConstId(InternId); -impl_intern_key!(AnonymousConstId); +pub struct InTypeConstId(InternId); +type InTypeConstLoc = (AstId, TypeOwnerId, Box); +impl_intern!(InTypeConstId, InTypeConstLoc, intern_in_type_const, lookup_intern_in_type_const); + +impl InTypeConstId { + pub fn source(&self, db: &dyn db::DefDatabase) -> ast::ConstArg { + let src = self.lookup(db).0; + let file_id = src.file_id; + let root = &db.parse_or_expand(file_id); + db.ast_id_map(file_id).get(src.value).to_node(root) + } +} /// A constant, which might appears as a const item, an annonymous const block in expressions /// or patterns, or as a constant in types with const generics. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum GeneralConstId { ConstId(ConstId), - AnonymousConstId(AnonymousConstId), + ConstBlockId(ConstBlockId), + InTypeConstId(InTypeConstId), } -impl_from!(ConstId, AnonymousConstId for GeneralConstId); +impl_from!(ConstId, ConstBlockId, InTypeConstId for GeneralConstId); impl GeneralConstId { pub fn generic_def(self, db: &dyn db::DefDatabase) -> Option { match self { GeneralConstId::ConstId(x) => Some(x.into()), - GeneralConstId::AnonymousConstId(x) => { + GeneralConstId::ConstBlockId(x) => { let (parent, _) = db.lookup_intern_anonymous_const(x); parent.as_generic_def_id() } + GeneralConstId::InTypeConstId(x) => { + let (_, parent, _) = x.lookup(db); + parent.as_generic_def_id() + } } } @@ -511,7 +668,8 @@ impl GeneralConstId { .and_then(|x| x.as_str()) .unwrap_or("_") .to_owned(), - GeneralConstId::AnonymousConstId(id) => format!("{{anonymous const {id:?}}}"), + GeneralConstId::ConstBlockId(id) => format!("{{anonymous const {id:?}}}"), + GeneralConstId::InTypeConstId(id) => format!("{{in type const {id:?}}}"), } } } @@ -522,10 +680,11 @@ pub enum DefWithBodyId { FunctionId(FunctionId), StaticId(StaticId), ConstId(ConstId), + InTypeConstId(InTypeConstId), VariantId(EnumVariantId), } -impl_from!(FunctionId, ConstId, StaticId for DefWithBodyId); +impl_from!(FunctionId, ConstId, StaticId, InTypeConstId for DefWithBodyId); impl From for DefWithBodyId { fn from(id: EnumVariantId) -> Self { @@ -540,6 +699,9 @@ impl DefWithBodyId { DefWithBodyId::StaticId(_) => None, DefWithBodyId::ConstId(c) => Some(c.into()), DefWithBodyId::VariantId(c) => Some(c.into()), + // FIXME: stable rust doesn't allow generics in constants, but we should + // use `TypeOwnerId::as_generic_def_id` when it does. + DefWithBodyId::InTypeConstId(_) => None, } } } @@ -734,24 +896,32 @@ impl HasModule for MacroId { } } -impl HasModule for DefWithBodyId { +impl HasModule for TypeOwnerId { fn module(&self, db: &dyn db::DefDatabase) -> ModuleId { match self { - DefWithBodyId::FunctionId(it) => it.lookup(db).module(db), - DefWithBodyId::StaticId(it) => it.lookup(db).module(db), - DefWithBodyId::ConstId(it) => it.lookup(db).module(db), - DefWithBodyId::VariantId(it) => it.parent.lookup(db).container, + TypeOwnerId::FunctionId(x) => x.lookup(db).module(db), + TypeOwnerId::StaticId(x) => x.lookup(db).module(db), + TypeOwnerId::ConstId(x) => x.lookup(db).module(db), + TypeOwnerId::InTypeConstId(x) => x.lookup(db).1.module(db), + TypeOwnerId::AdtId(x) => x.module(db), + TypeOwnerId::TraitId(x) => x.lookup(db).container, + TypeOwnerId::TraitAliasId(x) => x.lookup(db).container, + TypeOwnerId::TypeAliasId(x) => x.lookup(db).module(db), + TypeOwnerId::ImplId(x) => x.lookup(db).container, + TypeOwnerId::EnumVariantId(x) => x.parent.lookup(db).container, + TypeOwnerId::ModuleId(x) => *x, } } } -impl DefWithBodyId { - pub fn as_mod_item(self, db: &dyn db::DefDatabase) -> ModItem { +impl HasModule for DefWithBodyId { + fn module(&self, db: &dyn db::DefDatabase) -> ModuleId { match self { - DefWithBodyId::FunctionId(it) => it.lookup(db).id.value.into(), - DefWithBodyId::StaticId(it) => it.lookup(db).id.value.into(), - DefWithBodyId::ConstId(it) => it.lookup(db).id.value.into(), - DefWithBodyId::VariantId(it) => it.parent.lookup(db).id.value.into(), + DefWithBodyId::FunctionId(it) => it.lookup(db).module(db), + DefWithBodyId::StaticId(it) => it.lookup(db).module(db), + DefWithBodyId::ConstId(it) => it.lookup(db).module(db), + DefWithBodyId::VariantId(it) => it.parent.lookup(db).container, + DefWithBodyId::InTypeConstId(it) => it.lookup(db).1.module(db), } } } diff --git a/crates/hir-def/src/path.rs b/crates/hir-def/src/path.rs index b9b808254971..ff4ae69546cf 100644 --- a/crates/hir-def/src/path.rs +++ b/crates/hir-def/src/path.rs @@ -9,7 +9,7 @@ use std::{ use crate::{ lang_item::LangItemTarget, lower::LowerCtx, - type_ref::{ConstRefOrPath, LifetimeRef, TypeBound, TypeRef}, + type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef}, }; use hir_expand::name::Name; use intern::Interned; @@ -90,7 +90,7 @@ pub struct AssociatedTypeBinding { pub enum GenericArg { Type(TypeRef), Lifetime(LifetimeRef), - Const(ConstRefOrPath), + Const(ConstRef), } impl Path { diff --git a/crates/hir-def/src/path/lower.rs b/crates/hir-def/src/path/lower.rs index 26d2706175ca..1cb17ff0d261 100644 --- a/crates/hir-def/src/path/lower.rs +++ b/crates/hir-def/src/path/lower.rs @@ -2,7 +2,7 @@ use std::iter; -use crate::{lower::LowerCtx, type_ref::ConstRefOrPath}; +use crate::{lower::LowerCtx, type_ref::ConstRef}; use either::Either; use hir_expand::name::{name, AsName}; @@ -217,7 +217,7 @@ pub(super) fn lower_generic_args( } } ast::GenericArg::ConstArg(arg) => { - let arg = ConstRefOrPath::from_expr_opt(arg.expr()); + let arg = ConstRef::from_const_arg(lower_ctx, Some(arg)); args.push(GenericArg::Const(arg)) } } diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs index 06f5b2526a45..880a76f2b85d 100644 --- a/crates/hir-def/src/resolver.rs +++ b/crates/hir-def/src/resolver.rs @@ -24,8 +24,8 @@ use crate::{ AdtId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId, FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalModuleId, Lookup, Macro2Id, MacroId, MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, - StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, - VariantId, + StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, TypeOrConstParamId, TypeOwnerId, + TypeParamId, VariantId, }; #[derive(Debug, Clone)] @@ -1009,6 +1009,24 @@ impl HasResolver for ExternBlockId { } } +impl HasResolver for TypeOwnerId { + fn resolver(self, db: &dyn DefDatabase) -> Resolver { + match self { + TypeOwnerId::FunctionId(x) => x.resolver(db), + TypeOwnerId::StaticId(x) => x.resolver(db), + TypeOwnerId::ConstId(x) => x.resolver(db), + TypeOwnerId::InTypeConstId(x) => x.lookup(db).1.resolver(db), + TypeOwnerId::AdtId(x) => x.resolver(db), + TypeOwnerId::TraitId(x) => x.resolver(db), + TypeOwnerId::TraitAliasId(x) => x.resolver(db), + TypeOwnerId::TypeAliasId(x) => x.resolver(db), + TypeOwnerId::ImplId(x) => x.resolver(db), + TypeOwnerId::EnumVariantId(x) => x.resolver(db), + TypeOwnerId::ModuleId(x) => x.resolver(db), + } + } +} + impl HasResolver for DefWithBodyId { fn resolver(self, db: &dyn DefDatabase) -> Resolver { match self { @@ -1016,6 +1034,7 @@ impl HasResolver for DefWithBodyId { DefWithBodyId::FunctionId(f) => f.resolver(db), DefWithBodyId::StaticId(s) => s.resolver(db), DefWithBodyId::VariantId(v) => v.parent.resolver(db), + DefWithBodyId::InTypeConstId(c) => c.lookup(db).1.resolver(db), } } } diff --git a/crates/hir-expand/src/ast_id_map.rs b/crates/hir-expand/src/ast_id_map.rs index 400442de94b9..02efaace4370 100644 --- a/crates/hir-expand/src/ast_id_map.rs +++ b/crates/hir-expand/src/ast_id_map.rs @@ -98,6 +98,7 @@ impl AstIdMap { || ast::Variant::can_cast(kind) || ast::RecordField::can_cast(kind) || ast::TupleField::can_cast(kind) + || ast::ConstArg::can_cast(kind) { res.alloc(&it); true diff --git a/crates/hir-ty/src/chalk_db.rs b/crates/hir-ty/src/chalk_db.rs index ac962c9e3e1f..2a31e5cab8a2 100644 --- a/crates/hir-ty/src/chalk_db.rs +++ b/crates/hir-ty/src/chalk_db.rs @@ -497,7 +497,7 @@ pub(crate) fn associated_ty_data_query( let generic_params = generics(db.upcast(), type_alias.into()); // let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST); let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast()); - let ctx = crate::TyLoweringContext::new(db, &resolver) + let ctx = crate::TyLoweringContext::new(db, &resolver, type_alias.into()) .with_type_param_mode(crate::lower::ParamLoweringMode::Variable); let trait_subst = TyBuilder::subst_for_def(db, trait_, None) diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs index 40b63b17b5aa..7a7c12e5b442 100644 --- a/crates/hir-ty/src/consteval.rs +++ b/crates/hir-ty/src/consteval.rs @@ -6,7 +6,7 @@ use hir_def::{ hir::Expr, path::Path, resolver::{Resolver, ValueNs}, - type_ref::ConstRef, + type_ref::LiteralConstRef, EnumVariantId, GeneralConstId, StaticId, }; use la_arena::{Idx, RawIdx}; @@ -129,23 +129,28 @@ pub fn intern_const_scalar(value: ConstScalar, ty: Ty) -> Const { } /// Interns a constant scalar with the given type -pub fn intern_const_ref(db: &dyn HirDatabase, value: &ConstRef, ty: Ty, krate: CrateId) -> Const { +pub fn intern_const_ref( + db: &dyn HirDatabase, + value: &LiteralConstRef, + ty: Ty, + krate: CrateId, +) -> Const { let layout = db.layout_of_ty(ty.clone(), krate); let bytes = match value { - ConstRef::Int(i) => { + LiteralConstRef::Int(i) => { // FIXME: We should handle failure of layout better. let size = layout.map(|x| x.size.bytes_usize()).unwrap_or(16); ConstScalar::Bytes(i.to_le_bytes()[0..size].to_vec(), MemoryMap::default()) } - ConstRef::UInt(i) => { + LiteralConstRef::UInt(i) => { let size = layout.map(|x| x.size.bytes_usize()).unwrap_or(16); ConstScalar::Bytes(i.to_le_bytes()[0..size].to_vec(), MemoryMap::default()) } - ConstRef::Bool(b) => ConstScalar::Bytes(vec![*b as u8], MemoryMap::default()), - ConstRef::Char(c) => { + LiteralConstRef::Bool(b) => ConstScalar::Bytes(vec![*b as u8], MemoryMap::default()), + LiteralConstRef::Char(c) => { ConstScalar::Bytes((*c as u32).to_le_bytes().to_vec(), MemoryMap::default()) } - ConstRef::Unknown => ConstScalar::Unknown, + LiteralConstRef::Unknown => ConstScalar::Unknown, }; intern_const_scalar(bytes, ty) } @@ -154,7 +159,7 @@ pub fn intern_const_ref(db: &dyn HirDatabase, value: &ConstRef, ty: Ty, krate: C pub fn usize_const(db: &dyn HirDatabase, value: Option, krate: CrateId) -> Const { intern_const_ref( db, - &value.map_or(ConstRef::Unknown, ConstRef::UInt), + &value.map_or(LiteralConstRef::Unknown, LiteralConstRef::UInt), TyBuilder::usize(), krate, ) @@ -210,7 +215,7 @@ pub(crate) fn const_eval_query( GeneralConstId::ConstId(c) => { db.monomorphized_mir_body(c.into(), subst, db.trait_environment(c.into()))? } - GeneralConstId::AnonymousConstId(c) => { + GeneralConstId::ConstBlockId(c) => { let (def, root) = db.lookup_intern_anonymous_const(c); let body = db.body(def); let infer = db.infer(def); @@ -221,6 +226,7 @@ pub(crate) fn const_eval_query( db.trait_environment_for_body(def), )?) } + GeneralConstId::InTypeConstId(c) => db.mir_body(c.into())?, }; let c = interpret_mir(db, &body, false).0?; Ok(c) diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs index 06fff08b7d35..0db1fefbfef5 100644 --- a/crates/hir-ty/src/consteval/tests.rs +++ b/crates/hir-ty/src/consteval/tests.rs @@ -2051,6 +2051,17 @@ fn extern_weak_statics() { ); } +#[test] +fn from_ne_bytes() { + check_number( + r#" +//- minicore: int_impl +const GOAL: u32 = u32::from_ne_bytes([44, 1, 0, 0]); + "#, + 300, + ); +} + #[test] fn enums() { check_number( diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs index ca8a394e360d..9dd810f844d4 100644 --- a/crates/hir-ty/src/db.rs +++ b/crates/hir-ty/src/db.rs @@ -278,6 +278,7 @@ fn infer_wait(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc DefWithBodyId::VariantId(it) => { db.enum_data(it.parent).variants[it.local_id].name.display(db.upcast()).to_string() } + DefWithBodyId::InTypeConstId(it) => format!("in type const {it:?}"), }); db.infer_query(def) } diff --git a/crates/hir-ty/src/diagnostics/unsafe_check.rs b/crates/hir-ty/src/diagnostics/unsafe_check.rs index 7c38e6583a75..9f9a56ffab06 100644 --- a/crates/hir-ty/src/diagnostics/unsafe_check.rs +++ b/crates/hir-ty/src/diagnostics/unsafe_check.rs @@ -18,9 +18,10 @@ pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> Vec { let is_unsafe = match def { DefWithBodyId::FunctionId(it) => db.function_data(it).has_unsafe_kw(), - DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) | DefWithBodyId::VariantId(_) => { - false - } + DefWithBodyId::StaticId(_) + | DefWithBodyId::ConstId(_) + | DefWithBodyId::VariantId(_) + | DefWithBodyId::InTypeConstId(_) => false, }; if is_unsafe { return res; diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 80f32e96ee63..2506ae5bb6f3 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -41,10 +41,15 @@ use stdx::{always, never}; use triomphe::Arc; use crate::{ - db::HirDatabase, fold_tys, infer::coerce::CoerceMany, lower::ImplTraitLoweringMode, - static_lifetime, to_assoc_type_id, traits::FnTrait, AliasEq, AliasTy, ClosureId, DomainGoal, - GenericArg, Goal, ImplTraitId, InEnvironment, Interner, ProjectionTy, RpitId, Substitution, - TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, + db::HirDatabase, + fold_tys, + infer::coerce::CoerceMany, + lower::ImplTraitLoweringMode, + static_lifetime, to_assoc_type_id, + traits::FnTrait, + utils::{InTypeConstIdMetadata, UnevaluatedConstEvaluatorFolder}, + AliasEq, AliasTy, ClosureId, DomainGoal, GenericArg, Goal, ImplTraitId, InEnvironment, + Interner, ProjectionTy, RpitId, Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, }; // This lint has a false positive here. See the link below for details. @@ -102,6 +107,11 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc { + // FIXME(const-generic-body): We should not get the return type in this way. + ctx.return_ty = + c.lookup(db.upcast()).2.box_any().downcast::().unwrap().0; + } } ctx.infer_body(); @@ -684,7 +694,7 @@ impl<'a> InferenceContext<'a> { fn collect_fn(&mut self, func: FunctionId) { let data = self.db.function_data(func); - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver) + let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, func.into()) .with_impl_trait_mode(ImplTraitLoweringMode::Param); let mut param_tys = data.params.iter().map(|type_ref| ctx.lower_ty(type_ref)).collect::>(); @@ -708,7 +718,7 @@ impl<'a> InferenceContext<'a> { } let return_ty = &*data.ret_type; - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver) + let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into()) .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); let return_ty = ctx.lower_ty(return_ty); let return_ty = self.insert_type_vars(return_ty); @@ -823,7 +833,7 @@ impl<'a> InferenceContext<'a> { } fn make_ty(&mut self, type_ref: &TypeRef) -> Ty { - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); + let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into()); let ty = ctx.lower_ty(type_ref); let ty = self.insert_type_vars(ty); self.normalize_associated_types_in(ty) @@ -850,7 +860,21 @@ impl<'a> InferenceContext<'a> { } fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { - self.table.unify(ty1, ty2) + let ty1 = ty1 + .clone() + .try_fold_with( + &mut UnevaluatedConstEvaluatorFolder { db: self.db }, + DebruijnIndex::INNERMOST, + ) + .unwrap(); + let ty2 = ty2 + .clone() + .try_fold_with( + &mut UnevaluatedConstEvaluatorFolder { db: self.db }, + DebruijnIndex::INNERMOST, + ) + .unwrap(); + self.table.unify(&ty1, &ty2) } /// Attempts to returns the deeply last field of nested structures, but @@ -973,7 +997,7 @@ impl<'a> InferenceContext<'a> { Some(path) => path, None => return (self.err_ty(), None), }; - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); + let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into()); let (resolution, unresolved) = if value_ns { match self.resolver.resolve_path_in_value_ns(self.db.upcast(), path) { Some(ResolveValueResult::ValueNs(value)) => match value { diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index 33e98ac86cf6..e1efa0b6d8cc 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -1715,6 +1715,7 @@ impl<'a> InferenceContext<'a> { const_or_path_to_chalk( this.db, &this.resolver, + this.owner.into(), ty, c, ParamLoweringMode::Placeholder, diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs index 95a20f983f1b..79d9e21e797c 100644 --- a/crates/hir-ty/src/infer/path.rs +++ b/crates/hir-ty/src/infer/path.rs @@ -44,7 +44,8 @@ impl InferenceContext<'_> { let last = path.segments().last()?; // Don't use `self.make_ty()` here as we need `orig_ns`. - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); + let ctx = + crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into()); let (ty, orig_ns) = ctx.lower_ty_ext(type_ref); let ty = self.table.insert_type_vars(ty); let ty = self.table.normalize_associated_types_in(ty); @@ -108,7 +109,7 @@ impl InferenceContext<'_> { } }; - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); + let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into()); let substs = ctx.substs_from_path(path, value_def, true); let substs = substs.as_slice(Interner); let parent_substs = self_subst.or_else(|| { @@ -190,7 +191,11 @@ impl InferenceContext<'_> { (TypeNs::TraitId(trait_), true) => { let segment = remaining_segments.last().expect("there should be at least one segment here"); - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); + let ctx = crate::lower::TyLoweringContext::new( + self.db, + &self.resolver, + self.owner.into(), + ); let trait_ref = ctx.lower_trait_ref_from_resolved_path(trait_, resolved_segment, None); self.resolve_trait_assoc_item(trait_ref, segment, id) @@ -202,7 +207,11 @@ impl InferenceContext<'_> { // as Iterator>::Item::default`) let remaining_segments_for_ty = remaining_segments.take(remaining_segments.len() - 1); - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); + let ctx = crate::lower::TyLoweringContext::new( + self.db, + &self.resolver, + self.owner.into(), + ); let (ty, _) = ctx.lower_partly_resolved_path( def, resolved_segment, diff --git a/crates/hir-ty/src/interner.rs b/crates/hir-ty/src/interner.rs index 89f7d9c4f4ab..e4dd4b86cf99 100644 --- a/crates/hir-ty/src/interner.rs +++ b/crates/hir-ty/src/interner.rs @@ -266,7 +266,7 @@ impl chalk_ir::interner::Interner for Interner { c1: &Self::InternedConcreteConst, c2: &Self::InternedConcreteConst, ) -> bool { - (c1 == &ConstScalar::Unknown) || (c2 == &ConstScalar::Unknown) || (c1 == c2) + !matches!(c1, ConstScalar::Bytes(..)) || !matches!(c2, ConstScalar::Bytes(..)) || (c1 == c2) } fn intern_generic_arg( diff --git a/crates/hir-ty/src/layout/tests.rs b/crates/hir-ty/src/layout/tests.rs index fca2e09ff0a9..0ff8c532d47c 100644 --- a/crates/hir-ty/src/layout/tests.rs +++ b/crates/hir-ty/src/layout/tests.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use base_db::fixture::WithFixture; use chalk_ir::{AdtId, TyKind}; +use either::Either; use hir_def::db::DefDatabase; use triomphe::Arc; @@ -25,27 +26,38 @@ fn eval_goal(ra_fixture: &str, minicore: &str) -> Result, LayoutErro ); let (db, file_ids) = TestDB::with_many_files(&ra_fixture); - let (adt_id, module_id) = file_ids + let (adt_or_type_alias_id, module_id) = file_ids .into_iter() .find_map(|file_id| { let module_id = db.module_for_file(file_id); let def_map = module_id.def_map(&db); let scope = &def_map[module_id.local_id].scope; - let adt_id = scope.declarations().find_map(|x| match x { + let adt_or_type_alias_id = scope.declarations().find_map(|x| match x { hir_def::ModuleDefId::AdtId(x) => { let name = match x { hir_def::AdtId::StructId(x) => db.struct_data(x).name.to_smol_str(), hir_def::AdtId::UnionId(x) => db.union_data(x).name.to_smol_str(), hir_def::AdtId::EnumId(x) => db.enum_data(x).name.to_smol_str(), }; - (name == "Goal").then_some(x) + (name == "Goal").then_some(Either::Left(x)) + } + hir_def::ModuleDefId::TypeAliasId(x) => { + let name = db.type_alias_data(x).name.to_smol_str(); + (name == "Goal").then_some(Either::Right(x)) } _ => None, })?; - Some((adt_id, module_id)) + Some((adt_or_type_alias_id, module_id)) }) .unwrap(); - let goal_ty = TyKind::Adt(AdtId(adt_id), Substitution::empty(Interner)).intern(Interner); + let goal_ty = match adt_or_type_alias_id { + Either::Left(adt_id) => { + TyKind::Adt(AdtId(adt_id), Substitution::empty(Interner)).intern(Interner) + } + Either::Right(ty_id) => { + db.ty(ty_id.into()).substitute(Interner, &Substitution::empty(Interner)) + } + }; db.layout_of_ty(goal_ty, module_id.krate()) } @@ -379,10 +391,23 @@ fn niche_optimization() { #[test] fn const_eval() { + size_and_align! { + struct Goal([i32; 2 + 2]); + } size_and_align! { const X: usize = 5; struct Goal([i32; X]); } + size_and_align! { + mod foo { + pub(super) const BAR: usize = 5; + } + struct Ar([T; foo::BAR]); + struct Goal(Ar>); + } + size_and_align! { + type Goal = [u8; 2 + 2]; + } } #[test] diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index 0c68891fe493..c0bcf790b1f7 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -27,10 +27,11 @@ use hir_def::{ nameres::MacroSubNs, path::{GenericArg, GenericArgs, ModPath, Path, PathKind, PathSegment, PathSegments}, resolver::{HasResolver, Resolver, TypeNs}, - type_ref::{ConstRefOrPath, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef}, + type_ref::{ConstRef, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef}, AdtId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, LocalFieldId, Lookup, ModuleDefId, StaticId, - StructId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, VariantId, + StructId, TraitId, TypeAliasId, TypeOrConstParamId, TypeOwnerId, TypeParamId, UnionId, + VariantId, }; use hir_expand::{name::Name, ExpandResult}; use intern::Interned; @@ -43,17 +44,24 @@ use triomphe::Arc; use crate::{ all_super_traits, - consteval::{intern_const_ref, path_to_const, unknown_const, unknown_const_as_generic}, + consteval::{ + intern_const_ref, intern_const_scalar, path_to_const, unknown_const, + unknown_const_as_generic, + }, db::HirDatabase, make_binders, mapping::{from_chalk_trait_id, ToChalk}, static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx, utils::Generics, - utils::{all_super_trait_refs, associated_type_by_name_including_super_traits, generics}, - AliasEq, AliasTy, Binders, BoundVar, CallableSig, Const, DebruijnIndex, DynTy, FnPointer, - FnSig, FnSubst, GenericArgData, ImplTraitId, Interner, ParamKind, PolyFnSig, ProjectionTy, - QuantifiedWhereClause, QuantifiedWhereClauses, ReturnTypeImplTrait, ReturnTypeImplTraits, - Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, WhereClause, + utils::{ + all_super_trait_refs, associated_type_by_name_including_super_traits, generics, + InTypeConstIdMetadata, + }, + AliasEq, AliasTy, Binders, BoundVar, CallableSig, Const, ConstScalar, DebruijnIndex, DynTy, + FnPointer, FnSig, FnSubst, GenericArgData, ImplTraitId, Interner, ParamKind, PolyFnSig, + ProjectionTy, QuantifiedWhereClause, QuantifiedWhereClauses, ReturnTypeImplTrait, + ReturnTypeImplTraits, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, + TyKind, WhereClause, }; #[derive(Debug)] @@ -106,6 +114,7 @@ pub struct TyLoweringContext<'a> { pub db: &'a dyn HirDatabase, resolver: &'a Resolver, in_binders: DebruijnIndex, + owner: TypeOwnerId, /// Note: Conceptually, it's thinkable that we could be in a location where /// some type params should be represented as placeholders, and others /// should be converted to variables. I think in practice, this isn't @@ -118,13 +127,14 @@ pub struct TyLoweringContext<'a> { } impl<'a> TyLoweringContext<'a> { - pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver) -> Self { + pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver, owner: TypeOwnerId) -> Self { let impl_trait_mode = ImplTraitLoweringState::Disallowed; let type_param_mode = ParamLoweringMode::Placeholder; let in_binders = DebruijnIndex::INNERMOST; Self { db, resolver, + owner, in_binders, impl_trait_mode, type_param_mode, @@ -235,6 +245,7 @@ impl<'a> TyLoweringContext<'a> { let const_len = const_or_path_to_chalk( self.db, self.resolver, + self.owner, TyBuilder::usize(), len, self.type_param_mode, @@ -840,6 +851,7 @@ impl<'a> TyLoweringContext<'a> { const_or_path_to_chalk( self.db, self.resolver, + self.owner, ty, c, self.type_param_mode, @@ -1356,8 +1368,8 @@ pub(crate) fn field_types_query( }; let generics = generics(db.upcast(), def); let mut res = ArenaMap::default(); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); + let ctx = TyLoweringContext::new(db, &resolver, GenericDefId::from(variant_id.adt_id()).into()) + .with_type_param_mode(ParamLoweringMode::Variable); for (field_id, field_data) in var_data.fields().iter() { res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(&field_data.type_ref))); } @@ -1379,8 +1391,8 @@ pub(crate) fn generic_predicates_for_param_query( assoc_name: Option, ) -> Arc<[Binders]> { let resolver = def.resolver(db.upcast()); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); + let ctx = TyLoweringContext::new(db, &resolver, def.into()) + .with_type_param_mode(ParamLoweringMode::Variable); let generics = generics(db.upcast(), def); let mut predicates: Vec<_> = resolver .where_predicates_in_scope() @@ -1468,8 +1480,8 @@ pub(crate) fn trait_environment_query( def: GenericDefId, ) -> Arc { let resolver = def.resolver(db.upcast()); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Placeholder); + let ctx = TyLoweringContext::new(db, &resolver, def.into()) + .with_type_param_mode(ParamLoweringMode::Placeholder); let mut traits_in_scope = Vec::new(); let mut clauses = Vec::new(); for pred in resolver.where_predicates_in_scope() { @@ -1527,8 +1539,8 @@ pub(crate) fn generic_predicates_query( def: GenericDefId, ) -> Arc<[Binders]> { let resolver = def.resolver(db.upcast()); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); + let ctx = TyLoweringContext::new(db, &resolver, def.into()) + .with_type_param_mode(ParamLoweringMode::Variable); let generics = generics(db.upcast(), def); let mut predicates = resolver @@ -1582,8 +1594,8 @@ pub(crate) fn generic_defaults_query( def: GenericDefId, ) -> Arc<[Binders>]> { let resolver = def.resolver(db.upcast()); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); + let ctx = TyLoweringContext::new(db, &resolver, def.into()) + .with_type_param_mode(ParamLoweringMode::Variable); let generic_params = generics(db.upcast(), def); let parent_start_idx = generic_params.len_self(); @@ -1648,11 +1660,11 @@ pub(crate) fn generic_defaults_recover( fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig { let data = db.function_data(def); let resolver = def.resolver(db.upcast()); - let ctx_params = TyLoweringContext::new(db, &resolver) + let ctx_params = TyLoweringContext::new(db, &resolver, def.into()) .with_impl_trait_mode(ImplTraitLoweringMode::Variable) .with_type_param_mode(ParamLoweringMode::Variable); let params = data.params.iter().map(|tr| ctx_params.lower_ty(tr)).collect::>(); - let ctx_ret = TyLoweringContext::new(db, &resolver) + let ctx_ret = TyLoweringContext::new(db, &resolver, def.into()) .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) .with_type_param_mode(ParamLoweringMode::Variable); let ret = ctx_ret.lower_ty(&data.ret_type); @@ -1683,8 +1695,8 @@ fn type_for_const(db: &dyn HirDatabase, def: ConstId) -> Binders { let data = db.const_data(def); let generics = generics(db.upcast(), def.into()); let resolver = def.resolver(db.upcast()); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); + let ctx = TyLoweringContext::new(db, &resolver, def.into()) + .with_type_param_mode(ParamLoweringMode::Variable); make_binders(db, &generics, ctx.lower_ty(&data.type_ref)) } @@ -1693,7 +1705,7 @@ fn type_for_const(db: &dyn HirDatabase, def: ConstId) -> Binders { fn type_for_static(db: &dyn HirDatabase, def: StaticId) -> Binders { let data = db.static_data(def); let resolver = def.resolver(db.upcast()); - let ctx = TyLoweringContext::new(db, &resolver); + let ctx = TyLoweringContext::new(db, &resolver, def.into()); Binders::empty(Interner, ctx.lower_ty(&data.type_ref)) } @@ -1702,8 +1714,8 @@ fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnS let struct_data = db.struct_data(def); let fields = struct_data.variant_data.fields(); let resolver = def.resolver(db.upcast()); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); + let ctx = TyLoweringContext::new(db, &resolver, AdtId::from(def).into()) + .with_type_param_mode(ParamLoweringMode::Variable); let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::>(); let (ret, binders) = type_for_adt(db, def.into()).into_value_and_skipped_binders(); Binders::new(binders, CallableSig::from_params_and_return(params, ret, false, Safety::Safe)) @@ -1715,7 +1727,7 @@ fn type_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> Binders>(); let (ret, binders) = type_for_adt(db, def.parent.into()).into_value_and_skipped_binders(); Binders::new(binders, CallableSig::from_params_and_return(params, ret, false, Safety::Safe)) @@ -1762,8 +1774,8 @@ fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders { fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders { let generics = generics(db.upcast(), t.into()); let resolver = t.resolver(db.upcast()); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); + let ctx = TyLoweringContext::new(db, &resolver, t.into()) + .with_type_param_mode(ParamLoweringMode::Variable); if db.type_alias_data(t).is_extern { Binders::empty(Interner, TyKind::Foreign(crate::to_foreign_def_id(t)).intern(Interner)) } else { @@ -1884,8 +1896,8 @@ pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binde "impl_self_ty_query({impl_id:?} -> {impl_loc:?} -> {impl_data:?})" )); let generics = generics(db.upcast(), impl_id.into()); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); + let ctx = TyLoweringContext::new(db, &resolver, impl_id.into()) + .with_type_param_mode(ParamLoweringMode::Variable); make_binders(db, &generics, ctx.lower_ty(&impl_data.self_ty)) } @@ -1894,7 +1906,7 @@ pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> T let parent_data = db.generic_params(def.parent()); let data = &parent_data.type_or_consts[def.local_id()]; let resolver = def.parent().resolver(db.upcast()); - let ctx = TyLoweringContext::new(db, &resolver); + let ctx = TyLoweringContext::new(db, &resolver, def.parent().into()); match data { TypeOrConstParamData::TypeParamData(_) => { never!(); @@ -1920,8 +1932,8 @@ pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option< let _cx = stdx::panic_context::enter(format!( "impl_trait_query({impl_id:?} -> {impl_loc:?} -> {impl_data:?})" )); - let ctx = - TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); + let ctx = TyLoweringContext::new(db, &resolver, impl_id.into()) + .with_type_param_mode(ParamLoweringMode::Variable); let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders(); let target_trait = impl_data.target_trait.as_ref()?; Some(Binders::new(binders, ctx.lower_trait_ref(target_trait, Some(self_ty))?)) @@ -1934,7 +1946,7 @@ pub(crate) fn return_type_impl_traits( // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe let data = db.function_data(def); let resolver = def.resolver(db.upcast()); - let ctx_ret = TyLoweringContext::new(db, &resolver) + let ctx_ret = TyLoweringContext::new(db, &resolver, def.into()) .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) .with_type_param_mode(ParamLoweringMode::Variable); let _ret = ctx_ret.lower_ty(&data.ret_type); @@ -1969,7 +1981,7 @@ pub(crate) fn generic_arg_to_chalk<'a, T>( arg: &'a GenericArg, this: &mut T, for_type: impl FnOnce(&mut T, &TypeRef) -> Ty + 'a, - for_const: impl FnOnce(&mut T, &ConstRefOrPath, Ty) -> Const + 'a, + for_const: impl FnOnce(&mut T, &ConstRef, Ty) -> Const + 'a, ) -> Option { let kind = match kind_id { Either::Left(_) => ParamKind::Type, @@ -1997,7 +2009,7 @@ pub(crate) fn generic_arg_to_chalk<'a, T>( let p = p.mod_path()?; if p.kind == PathKind::Plain { if let [n] = p.segments() { - let c = ConstRefOrPath::Path(n.clone()); + let c = ConstRef::Path(n.clone()); return Some( GenericArgData::Const(for_const(this, &c, c_ty)).intern(Interner), ); @@ -2013,15 +2025,16 @@ pub(crate) fn generic_arg_to_chalk<'a, T>( pub(crate) fn const_or_path_to_chalk( db: &dyn HirDatabase, resolver: &Resolver, + owner: TypeOwnerId, expected_ty: Ty, - value: &ConstRefOrPath, + value: &ConstRef, mode: ParamLoweringMode, args: impl FnOnce() -> Generics, debruijn: DebruijnIndex, ) -> Const { match value { - ConstRefOrPath::Scalar(s) => intern_const_ref(db, s, expected_ty, resolver.krate()), - ConstRefOrPath::Path(n) => { + ConstRef::Scalar(s) => intern_const_ref(db, s, expected_ty, resolver.krate()), + ConstRef::Path(n) => { let path = ModPath::from_segments(PathKind::Plain, Some(n.clone())); path_to_const( db, @@ -2034,6 +2047,26 @@ pub(crate) fn const_or_path_to_chalk( ) .unwrap_or_else(|| unknown_const(expected_ty)) } + &ConstRef::Complex(x) => { + let crate_data = &db.crate_graph()[owner.module(db.upcast()).krate()]; + if crate_data.env.get("__ra_is_test_fixture").is_none() && crate_data.origin.is_local() + { + // FIXME: current `InTypeConstId` is very unstable, so we only use it in non local crate + // that are unlikely to be edited. + return unknown_const(expected_ty); + } + let c = db + .intern_in_type_const(( + x, + owner, + Box::new(InTypeConstIdMetadata(expected_ty.clone())), + )) + .into(); + intern_const_scalar( + ConstScalar::UnevaluatedConst(c, Substitution::empty(Interner)), + expected_ty, + ) + } } } diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index 6fa3d1351a91..ab6430e8f195 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -570,7 +570,7 @@ impl ReceiverAdjustments { .intern(Interner); } } - never!("unsize_array with non-reference-to-array {:?}", ty); + // FIXME: report diagnostic if array unsizing happens without indirection. ty }; adjust.push(Adjustment { diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index aad1a82f2981..e3401a36ceba 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -1876,6 +1876,7 @@ pub fn mir_body_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Result { db.enum_data(it.parent).variants[it.local_id].name.display(db.upcast()).to_string() } + DefWithBodyId::InTypeConstId(it) => format!("in type const {it:?}"), }); let body = db.body(def); let infer = db.infer(def); diff --git a/crates/hir-ty/src/mir/pretty.rs b/crates/hir-ty/src/mir/pretty.rs index 58662b01b99b..ac23e77bd2bb 100644 --- a/crates/hir-ty/src/mir/pretty.rs +++ b/crates/hir-ty/src/mir/pretty.rs @@ -60,6 +60,9 @@ impl MirBody { let data = db.enum_data(id.parent); w!(this, "enum {} = ", data.name.display(db.upcast())); } + hir_def::DefWithBodyId::InTypeConstId(id) => { + w!(this, "in type const {id:?} = "); + } }); ctx.result } diff --git a/crates/hir-ty/src/tests.rs b/crates/hir-ty/src/tests.rs index 2db04024b7b6..857141280061 100644 --- a/crates/hir-ty/src/tests.rs +++ b/crates/hir-ty/src/tests.rs @@ -146,6 +146,7 @@ fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_sour let loc = db.lookup_intern_enum(it.parent); loc.source(&db).value.syntax().text_range().start() } + DefWithBodyId::InTypeConstId(it) => it.source(&db).syntax().text_range().start(), }); let mut unexpected_type_mismatches = String::new(); for def in defs { @@ -391,6 +392,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { let loc = db.lookup_intern_enum(it.parent); loc.source(&db).value.syntax().text_range().start() } + DefWithBodyId::InTypeConstId(it) => it.source(&db).syntax().text_range().start(), }); for def in defs { let (body, source_map) = db.body_with_source_map(def); diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs index f18c953a7afd..047900a324e9 100644 --- a/crates/hir-ty/src/tests/regression.rs +++ b/crates/hir-ty/src/tests/regression.rs @@ -1955,3 +1955,26 @@ impl Inner<1> { "#, ); } + +#[test] +fn dont_crash_on_slice_unsizing() { + check_no_mismatches( + r#" +//- minicore: slice, unsize, coerce_unsized +trait Tr { + fn f(self); +} + +impl Tr for [i32] { + fn f(self) { + let t; + x(t); + } +} + +fn x(a: [i32; 4]) { + let b = a.f(); +} + "#, + ); +} diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs index 3ece40486dde..fb0aa2faf1f2 100644 --- a/crates/hir-ty/src/tests/simple.rs +++ b/crates/hir-ty/src/tests/simple.rs @@ -1828,6 +1828,38 @@ impl Foo for u8 { ); } +#[test] +fn const_eval_in_function_signature() { + check_types( + r#" +const fn foo() -> usize { + 5 +} + +fn f() -> [u8; foo()] { + loop {} +} + +fn main() { + let t = f(); + //^ [u8; 5] +}"#, + ); + check_types( + r#" +//- minicore: default, builtin_impls +fn f() -> [u8; Default::default()] { + loop {} +} + +fn main() { + let t = f(); + //^ [u8; 0] +} + "#, + ); +} + #[test] fn shadowing_primitive_with_inner_items() { check_types( diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs index 681d087ede6e..3636580630df 100644 --- a/crates/hir-ty/src/utils.rs +++ b/crates/hir-ty/src/utils.rs @@ -1,7 +1,7 @@ //! Helper functions for working with def, which don't need to be a separate //! query, but can't be computed directly from `*Data` (ie, which need a `db`). -use std::iter; +use std::{hash::Hash, iter}; use base_db::CrateId; use chalk_ir::{ @@ -20,7 +20,8 @@ use hir_def::{ resolver::{HasResolver, TypeNs}, type_ref::{TraitBoundModifier, TypeRef}, ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId, ItemContainerId, - LocalEnumVariantId, Lookup, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, + LocalEnumVariantId, Lookup, OpaqueInternableThing, TraitId, TypeAliasId, TypeOrConstParamId, + TypeParamId, }; use hir_expand::name::Name; use intern::Interned; @@ -464,3 +465,28 @@ pub(crate) fn detect_variant_from_bytes<'a>( }; Some((var_id, var_layout)) } + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub(crate) struct InTypeConstIdMetadata(pub(crate) Ty); + +impl OpaqueInternableThing for InTypeConstIdMetadata { + fn dyn_hash(&self, mut state: &mut dyn std::hash::Hasher) { + self.hash(&mut state); + } + + fn dyn_eq(&self, other: &dyn OpaqueInternableThing) -> bool { + other.as_any().downcast_ref::().map_or(false, |x| self == x) + } + + fn dyn_clone(&self) -> Box { + Box::new(self.clone()) + } + + fn as_any(&self) -> &dyn std::any::Any { + self + } + + fn box_any(&self) -> Box { + Box::new(self.clone()) + } +} diff --git a/crates/hir/src/from_id.rs b/crates/hir/src/from_id.rs index 883e6a29b06a..de23902199f5 100644 --- a/crates/hir/src/from_id.rs +++ b/crates/hir/src/from_id.rs @@ -40,6 +40,7 @@ from_id![ (hir_def::TraitAliasId, crate::TraitAlias), (hir_def::StaticId, crate::Static), (hir_def::ConstId, crate::Const), + (hir_def::InTypeConstId, crate::InTypeConst), (hir_def::FunctionId, crate::Function), (hir_def::ImplId, crate::Impl), (hir_def::TypeOrConstParamId, crate::TypeOrConstParam), @@ -144,6 +145,7 @@ impl From for DefWithBodyId { DefWithBody::Static(it) => DefWithBodyId::StaticId(it.id), DefWithBody::Const(it) => DefWithBodyId::ConstId(it.id), DefWithBody::Variant(it) => DefWithBodyId::VariantId(it.into()), + DefWithBody::InTypeConst(it) => DefWithBodyId::InTypeConstId(it.id), } } } @@ -155,6 +157,7 @@ impl From for DefWithBody { DefWithBodyId::StaticId(it) => DefWithBody::Static(it.into()), DefWithBodyId::ConstId(it) => DefWithBody::Const(it.into()), DefWithBodyId::VariantId(it) => DefWithBody::Variant(it.into()), + DefWithBodyId::InTypeConstId(it) => DefWithBody::InTypeConst(it.into()), } } } diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 5527eb59387a..a11e25c79a21 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -52,9 +52,10 @@ use hir_def::{ resolver::{HasResolver, Resolver}, src::HasSource as _, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, - EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, LifetimeParamId, - LocalEnumVariantId, LocalFieldId, Lookup, MacroExpander, MacroId, ModuleId, StaticId, StructId, - TraitAliasId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, + EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, InTypeConstId, ItemContainerId, + LifetimeParamId, LocalEnumVariantId, LocalFieldId, Lookup, MacroExpander, MacroId, ModuleId, + StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, + UnionId, }; use hir_expand::{name::name, MacroCallKind}; use hir_ty::{ @@ -1375,8 +1376,9 @@ pub enum DefWithBody { Static(Static), Const(Const), Variant(Variant), + InTypeConst(InTypeConst), } -impl_from!(Function, Const, Static, Variant for DefWithBody); +impl_from!(Function, Const, Static, Variant, InTypeConst for DefWithBody); impl DefWithBody { pub fn module(self, db: &dyn HirDatabase) -> Module { @@ -1385,6 +1387,7 @@ impl DefWithBody { DefWithBody::Function(f) => f.module(db), DefWithBody::Static(s) => s.module(db), DefWithBody::Variant(v) => v.module(db), + DefWithBody::InTypeConst(c) => c.module(db), } } @@ -1394,6 +1397,7 @@ impl DefWithBody { DefWithBody::Static(s) => Some(s.name(db)), DefWithBody::Const(c) => c.name(db), DefWithBody::Variant(v) => Some(v.name(db)), + DefWithBody::InTypeConst(_) => None, } } @@ -1404,6 +1408,11 @@ impl DefWithBody { DefWithBody::Static(it) => it.ty(db), DefWithBody::Const(it) => it.ty(db), DefWithBody::Variant(it) => it.parent.variant_body_ty(db), + DefWithBody::InTypeConst(it) => Type::new_with_resolver_inner( + db, + &DefWithBodyId::from(it.id).resolver(db.upcast()), + TyKind::Error.intern(Interner), + ), } } @@ -1413,6 +1422,7 @@ impl DefWithBody { DefWithBody::Static(it) => it.id.into(), DefWithBody::Const(it) => it.id.into(), DefWithBody::Variant(it) => it.into(), + DefWithBody::InTypeConst(it) => it.id.into(), } } @@ -1797,6 +1807,8 @@ impl DefWithBody { DefWithBody::Static(it) => it.into(), DefWithBody::Const(it) => it.into(), DefWithBody::Variant(it) => it.into(), + // FIXME: don't ignore diagnostics for in type const + DefWithBody::InTypeConst(_) => return, }; for diag in hir_ty::diagnostics::incorrect_case(db, krate, def.into()) { acc.push(diag.into()) @@ -2085,6 +2097,17 @@ impl HasVisibility for Function { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct InTypeConst { + pub(crate) id: InTypeConstId, +} + +impl InTypeConst { + pub fn module(self, db: &dyn HirDatabase) -> Module { + Module { id: self.id.lookup(db.upcast()).1.module(db.upcast()) } + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Const { pub(crate) id: ConstId, @@ -2515,7 +2538,7 @@ impl AsAssocItem for DefWithBody { match self { DefWithBody::Function(it) => it.as_assoc_item(db), DefWithBody::Const(it) => it.as_assoc_item(db), - DefWithBody::Static(_) | DefWithBody::Variant(_) => None, + DefWithBody::Static(_) | DefWithBody::Variant(_) | DefWithBody::InTypeConst(_) => None, } } } diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 2d2b00b147e5..d29d73387a90 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -1074,8 +1074,12 @@ impl<'db> SemanticsImpl<'db> { fn resolve_type(&self, ty: &ast::Type) -> Option { let analyze = self.analyze(ty.syntax())?; let ctx = LowerCtx::with_file_id(self.db.upcast(), analyze.file_id); - let ty = hir_ty::TyLoweringContext::new(self.db, &analyze.resolver) - .lower_ty(&crate::TypeRef::from_ast(&ctx, ty.clone())); + let ty = hir_ty::TyLoweringContext::new( + self.db, + &analyze.resolver, + analyze.resolver.module().into(), + ) + .lower_ty(&crate::TypeRef::from_ast(&ctx, ty.clone())); Some(Type::new_with_resolver(self.db, &analyze.resolver, ty)) } diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 1374fa332c64..ecb1b306a668 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -38,8 +38,8 @@ use hir_ty::{ UnsafeExpr, }, lang_items::lang_items_for_bin_op, - method_resolution::{self}, - Adjustment, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind, TyLoweringContext, + method_resolution, Adjustment, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind, + TyLoweringContext, }; use itertools::Itertools; use smallvec::SmallVec; @@ -978,7 +978,8 @@ fn resolve_hir_path_( let types = || { let (ty, unresolved) = match path.type_anchor() { Some(type_ref) => { - let (_, res) = TyLoweringContext::new(db, resolver).lower_ty_ext(type_ref); + let (_, res) = TyLoweringContext::new(db, resolver, resolver.module().into()) + .lower_ty_ext(type_ref); res.map(|ty_ns| (ty_ns, path.segments().first())) } None => { diff --git a/crates/hir/src/symbols.rs b/crates/hir/src/symbols.rs index 207e8206c92d..43d957412bc8 100644 --- a/crates/hir/src/symbols.rs +++ b/crates/hir/src/symbols.rs @@ -233,6 +233,7 @@ impl<'a> SymbolCollector<'a> { DefWithBodyId::VariantId(id) => { Some(self.db.enum_data(id.parent).variants[id.local_id].name.to_smol_str()) } + DefWithBodyId::InTypeConstId(_) => Some("in type const".into()), } } diff --git a/crates/ide-assists/src/handlers/extract_type_alias.rs b/crates/ide-assists/src/handlers/extract_type_alias.rs index 71b45d88cb8c..b6e7d6209c9c 100644 --- a/crates/ide-assists/src/handlers/extract_type_alias.rs +++ b/crates/ide-assists/src/handlers/extract_type_alias.rs @@ -158,7 +158,7 @@ fn collect_used_generics<'gp>( .and_then(|lt| known_generics.iter().find(find_lifetime(<.text()))), ), ast::Type::ArrayType(ar) => { - if let Some(ast::Expr::PathExpr(p)) = ar.expr() { + if let Some(ast::Expr::PathExpr(p)) = ar.const_arg().and_then(|x| x.expr()) { if let Some(path) = p.path() { if let Some(name_ref) = path.as_single_name_ref() { if let Some(param) = known_generics.iter().find(|gp| { diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs index 73cd5dcaf23f..e8ff107bd495 100644 --- a/crates/ide-db/src/search.rs +++ b/crates/ide-db/src/search.rs @@ -243,6 +243,8 @@ impl Definition { DefWithBody::Const(c) => c.source(db).map(|src| src.syntax().cloned()), DefWithBody::Static(s) => s.source(db).map(|src| src.syntax().cloned()), DefWithBody::Variant(v) => v.source(db).map(|src| src.syntax().cloned()), + // FIXME: implement + DefWithBody::InTypeConst(_) => return SearchScope::empty(), }; return match def { Some(def) => SearchScope::file_range(def.as_ref().original_file_range_full(db)), diff --git a/crates/ide/src/inlay_hints/chaining.rs b/crates/ide/src/inlay_hints/chaining.rs index ce1e03a069b2..fd4e347d259f 100644 --- a/crates/ide/src/inlay_hints/chaining.rs +++ b/crates/ide/src/inlay_hints/chaining.rs @@ -474,7 +474,7 @@ fn main() { file_id: FileId( 1, ), - range: 9332..9340, + range: 9333..9341, }, ), tooltip: "", @@ -487,7 +487,7 @@ fn main() { file_id: FileId( 1, ), - range: 9364..9368, + range: 9365..9369, }, ), tooltip: "", @@ -511,7 +511,7 @@ fn main() { file_id: FileId( 1, ), - range: 9332..9340, + range: 9333..9341, }, ), tooltip: "", @@ -524,7 +524,7 @@ fn main() { file_id: FileId( 1, ), - range: 9364..9368, + range: 9365..9369, }, ), tooltip: "", @@ -548,7 +548,7 @@ fn main() { file_id: FileId( 1, ), - range: 9332..9340, + range: 9333..9341, }, ), tooltip: "", @@ -561,7 +561,7 @@ fn main() { file_id: FileId( 1, ), - range: 9364..9368, + range: 9365..9369, }, ), tooltip: "", diff --git a/crates/parser/src/grammar/types.rs b/crates/parser/src/grammar/types.rs index 93ef48350270..96a6cdeaafff 100644 --- a/crates/parser/src/grammar/types.rs +++ b/crates/parser/src/grammar/types.rs @@ -153,7 +153,9 @@ fn array_or_slice_type(p: &mut Parser<'_>) { // type T = [(); 92]; T![;] => { p.bump(T![;]); + let m = p.start(); expressions::expr(p); + m.complete(p, CONST_ARG); p.expect(T![']']); ARRAY_TYPE } diff --git a/crates/parser/test_data/parser/inline/ok/0017_array_type.rast b/crates/parser/test_data/parser/inline/ok/0017_array_type.rast index 2a5c644d4671..0d50144b7300 100644 --- a/crates/parser/test_data/parser/inline/ok/0017_array_type.rast +++ b/crates/parser/test_data/parser/inline/ok/0017_array_type.rast @@ -14,8 +14,9 @@ SOURCE_FILE R_PAREN ")" SEMICOLON ";" WHITESPACE " " - LITERAL - INT_NUMBER "92" + CONST_ARG + LITERAL + INT_NUMBER "92" R_BRACK "]" SEMICOLON ";" WHITESPACE "\n" diff --git a/crates/parser/test_data/parser/ok/0030_traits.rast b/crates/parser/test_data/parser/ok/0030_traits.rast index 44423581e6ab..3965ae9596b5 100644 --- a/crates/parser/test_data/parser/ok/0030_traits.rast +++ b/crates/parser/test_data/parser/ok/0030_traits.rast @@ -51,8 +51,9 @@ SOURCE_FILE IDENT "i32" SEMICOLON ";" WHITESPACE " " - LITERAL - INT_NUMBER "1" + CONST_ARG + LITERAL + INT_NUMBER "1" R_BRACK "]" R_PAREN ")" SEMICOLON ";" diff --git a/crates/parser/test_data/parser/ok/0043_complex_assignment.rast b/crates/parser/test_data/parser/ok/0043_complex_assignment.rast index 3b02c3f96ae0..f3c85b45b6bd 100644 --- a/crates/parser/test_data/parser/ok/0043_complex_assignment.rast +++ b/crates/parser/test_data/parser/ok/0043_complex_assignment.rast @@ -24,8 +24,9 @@ SOURCE_FILE IDENT "u8" SEMICOLON ";" WHITESPACE " " - LITERAL - INT_NUMBER "1" + CONST_ARG + LITERAL + INT_NUMBER "1" R_BRACK "]" WHITESPACE " " R_CURLY "}" diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index 0aca620a6755..b5fe237fc4c1 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -1403,6 +1403,12 @@ fn handle_hack_cargo_workspace( .unwrap(); crate_graph.remove_and_replace(fake, original).unwrap(); } + for (_, c) in crate_graph.iter_mut() { + if c.origin.is_local() { + // LangCrateOrigin::Other is good enough for a hack. + c.origin = CrateOrigin::Lang(LangCrateOrigin::Other); + } + } sysroot .crates() .filter_map(|krate| { diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index 2c2a9a18d2e3..4c0a08d926bd 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -328,14 +328,21 @@ impl flags::AnalysisStats { let analysis = host.analysis(); for f in funcs.iter().copied() { let name = f.name(db); - let full_name = f - .module(db) - .path_to_root(db) + let module = f.module(db); + let full_name = module + .krate() + .display_name(db) + .map(|x| x.canonical_name().to_string()) .into_iter() - .rev() - .filter_map(|it| it.name(db)) - .chain(Some(f.name(db))) - .map(|it| it.display(db).to_string()) + .chain( + module + .path_to_root(db) + .into_iter() + .filter_map(|it| it.name(db)) + .rev() + .chain(Some(f.name(db))) + .map(|it| it.display(db).to_string()), + ) .join("::"); if let Some(only_name) = self.only.as_deref() { if name.display(db).to_string() != only_name && full_name != only_name { diff --git a/crates/syntax/rust.ungram b/crates/syntax/rust.ungram index 4c9027dec68e..b096c9974489 100644 --- a/crates/syntax/rust.ungram +++ b/crates/syntax/rust.ungram @@ -565,7 +565,7 @@ RefType = '&' Lifetime? 'mut'? Type ArrayType = - '[' Type ';' Expr ']' + '[' Type ';' ConstArg ']' SliceType = '[' Type ']' diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs index 61f6a04c98d3..e520801ea2ed 100644 --- a/crates/syntax/src/ast/generated/nodes.rs +++ b/crates/syntax/src/ast/generated/nodes.rs @@ -1207,7 +1207,7 @@ impl ArrayType { pub fn l_brack_token(&self) -> Option { support::token(&self.syntax, T!['[']) } pub fn ty(&self) -> Option { support::child(&self.syntax) } pub fn semicolon_token(&self) -> Option { support::token(&self.syntax, T![;]) } - pub fn expr(&self) -> Option { support::child(&self.syntax) } + pub fn const_arg(&self) -> Option { support::child(&self.syntax) } pub fn r_brack_token(&self) -> Option { support::token(&self.syntax, T![']']) } } diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index c79b4e966d67..1484a4497a41 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -32,6 +32,7 @@ //! include: //! index: sized //! infallible: +//! int_impl: size_of, transmute //! iterator: option //! iterators: iterator, fn //! manually_drop: drop @@ -44,6 +45,7 @@ //! range: //! result: //! send: sized +//! size_of: sized //! sized: //! slice: //! sync: sized @@ -345,6 +347,12 @@ pub mod mem { pub fn transmute(src: Src) -> Dst; } // endregion:transmute + + // region:size_of + extern "rust-intrinsic" { + pub fn size_of() -> usize; + } + // endregion:size_of } pub mod ptr { @@ -1307,6 +1315,25 @@ impl bool { } // endregion:bool_impl +// region:int_impl +macro_rules! impl_int { + ($($t:ty)*) => { + $( + impl $t { + pub const fn from_ne_bytes(bytes: [u8; mem::size_of::()]) -> Self { + unsafe { mem::transmute(bytes) } + } + } + )* + } +} + +impl_int! { + usize u8 u16 u32 u64 u128 + isize i8 i16 i32 i64 i128 +} +// endregion:int_impl + // region:error pub mod error { #[rustc_has_incoherent_inherent_impls]