Auto merge of #14932 - HKalbasi:dev, r=HKalbasi

Lower const params with a bad id

cc #7434

This PR adds an `InTypeConstId` which is a `DefWithBodyId` and lower const generic parameters into bodies using it, and evaluate them with the mir interpreter. I think this is the last unimplemented const generic feature relative to rustc stable.

But there is a problem: The id used in the `InTypeConstId` is the raw `FileAstId`, which changes frequently. So these ids and their bodies will be invalidated very frequently, which is bad for incremental analysis.

Due this problem, I disabled lowering for local crates (in library crate the id is stable since files won't be changed). This might be overreacting (const generic expressions are usually small, maybe it would be better enabled with bad performance than disabled) but it makes motivation for doing it in the correct way, and it splits the potential panic and breakages that usually comes with const generic PRs in two steps.

Other than the id, I think (at least I hope) other parts are in the right direction.
This commit is contained in:
bors 2023-06-12 08:49:02 +00:00
commit dcd31550e2
48 changed files with 718 additions and 216 deletions

View File

@ -215,7 +215,7 @@ pub fn parse_with_proc_macros(
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 @@ pub fn parse_with_proc_macros(
None,
Default::default(),
Default::default(),
Env::default(),
Env::new_for_test_fixture(),
false,
CrateOrigin::Lang(LangCrateOrigin::Core),
target_layout.clone(),
@ -298,7 +298,7 @@ pub fn parse_with_proc_macros(
None,
Default::default(),
Default::default(),
Env::default(),
Env::new_for_test_fixture(),
true,
CrateOrigin::Local { repo: None, name: None },
target_layout,

View File

@ -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<String, String>,
}
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 @@ pub fn iter(&self) -> impl Iterator<Item = CrateId> + '_ {
self.arena.iter().map(|(idx, _)| idx)
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = (CrateId, &mut CrateData)> + '_ {
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<Item = CrateId> {

View File

@ -118,7 +118,7 @@ pub(crate) fn body_with_source_map_query(
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 @@ pub(crate) fn body_with_source_map_query(
}),
)
});
(
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);

View File

@ -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];

View File

@ -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 @@
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<ast::ConstArg>, TypeOwnerId, Box<dyn OpaqueInternableThing>),
) -> InTypeConstId;
}
#[salsa::query_group(DefDatabaseStorage)]

View File

@ -155,7 +155,7 @@ pub fn current_file_id(&self) -> HirFileId {
}
pub(crate) fn parse_path(&mut self, db: &dyn DefDatabase, path: ast::Path) -> Option<Path> {
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)
}

View File

@ -26,7 +26,7 @@
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<ExprId>,
},
Const(AnonymousConstId),
Const(ConstBlockId),
Unsafe {
id: Option<BlockId>,
statements: Box<[Statement]>,

View File

@ -118,7 +118,7 @@ pub enum TypeRef {
Reference(Box<TypeRef>, Option<LifetimeRef>, 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<TypeRef>, ConstRefOrPath),
Array(Box<TypeRef>, ConstRef),
Slice(Box<TypeRef>),
/// A fn pointer. Last element of the vector is the return type.
Fn(Vec<(Option<Name>, TypeRef)>, bool /*varargs*/, bool /*is_unsafe*/),
@ -186,11 +186,7 @@ pub fn from_ast(ctx: &LowerCtx<'_>, node: ast::Type) -> Self {
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 @@ pub fn as_path(&self) -> Option<(&Path, &TraitBoundModifier)> {
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ConstRefOrPath {
Scalar(ConstRef),
pub enum ConstRef {
Scalar(LiteralConstRef),
Path(Name),
Complex(AstId<ast::ConstArg>),
}
impl ConstRefOrPath {
pub(crate) fn from_expr_opt(expr: Option<ast::Expr>) -> 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<ast::ConstArg>) -> 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 {
match expr {
ast::Expr::PathExpr(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),
// We special case literals and single identifiers, to speed up things.
fn from_expr(expr: ast::Expr, ast_id: Option<AstId<ast::ConstArg>>) -> 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;
}
}
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,
}
true
}
match expr {
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(LiteralConstRef::Unknown),
}
_ => 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<Literal> for ConstRef {
impl From<Literal> for LiteralConstRef {
fn from(literal: Literal) -> Self {
match literal {
Literal::Char(c) => Self::Char(c),
@ -483,14 +492,14 @@ fn from(literal: Literal) -> Self {
}
}
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('_'),
}
}
}

View File

@ -57,7 +57,10 @@ macro_rules! eprintln {
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 @@ macro_rules! eprintln {
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 @@ pub enum ModuleDefId {
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 AnonymousConstId(InternId);
impl_intern_key!(AnonymousConstId);
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<GenericDefId> {
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<DefWithBodyId> 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<GenericDefId> 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<dyn std::any::Any>;
fn dyn_hash(&self, state: &mut dyn Hasher);
fn dyn_eq(&self, other: &dyn OpaqueInternableThing) -> bool;
fn dyn_clone(&self) -> Box<dyn OpaqueInternableThing>;
}
impl Hash for dyn OpaqueInternableThing {
fn hash<H: Hasher>(&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<dyn OpaqueInternableThing> {
fn clone(&self) -> Self {
self.dyn_clone()
}
}
// FIXME(const-generic-body): Use an stable id for in type consts.
//
// The current id uses `AstId<ast::ConstArg>` 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 InTypeConstId(InternId);
type InTypeConstLoc = (AstId<ast::ConstArg>, TypeOwnerId, Box<dyn OpaqueInternableThing>);
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<GenericDefId> {
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 @@ pub fn name(self, db: &dyn db::DefDatabase) -> String {
.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<EnumVariantId> for DefWithBodyId {
fn from(id: EnumVariantId) -> Self {
@ -540,6 +699,9 @@ pub fn as_generic_def_id(self) -> Option<GenericDefId> {
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,6 +896,24 @@ fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
}
}
impl HasModule for TypeOwnerId {
fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
match self {
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 HasModule for DefWithBodyId {
fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
match self {
@ -741,17 +921,7 @@ fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
DefWithBodyId::StaticId(it) => it.lookup(db).module(db),
DefWithBodyId::ConstId(it) => it.lookup(db).module(db),
DefWithBodyId::VariantId(it) => it.parent.lookup(db).container,
}
}
}
impl DefWithBodyId {
pub fn as_mod_item(self, db: &dyn db::DefDatabase) -> ModItem {
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::InTypeConstId(it) => it.lookup(db).1.module(db),
}
}
}

View File

@ -9,7 +9,7 @@
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 {

View File

@ -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))
}
}

View File

@ -24,8 +24,8 @@
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 @@ fn resolver(self, db: &dyn DefDatabase) -> Resolver {
}
}
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 @@ fn resolver(self, db: &dyn DefDatabase) -> Resolver {
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),
}
}
}

View File

@ -98,6 +98,7 @@ pub(crate) fn from_source(node: &SyntaxNode) -> 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

View File

@ -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)

View File

@ -6,7 +6,7 @@
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<u128>, 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)

View File

@ -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(

View File

@ -278,6 +278,7 @@ fn infer_wait(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult>
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)
}

View File

@ -18,9 +18,10 @@ pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> Vec<ExprId> {
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;

View File

@ -41,10 +41,15 @@
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<Infer
},
});
}
DefWithBodyId::InTypeConstId(c) => {
// 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::<InTypeConstIdMetadata>().unwrap().0;
}
}
ctx.infer_body();
@ -684,7 +694,7 @@ fn collect_static(&mut self, data: &StaticData) {
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::<Vec<_>>();
@ -708,7 +718,7 @@ fn collect_fn(&mut self, func: FunctionId) {
}
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 @@ fn push_diagnostic(&mut self, diagnostic: InferenceDiagnostic) {
}
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 @@ fn push_obligation(&mut self, o: DomainGoal) {
}
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 @@ fn resolve_variant(&mut self, path: Option<&Path>, value_ns: bool) -> (Ty, Optio
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 {

View File

@ -1715,6 +1715,7 @@ fn substs_for_method_call(
const_or_path_to_chalk(
this.db,
&this.resolver,
this.owner.into(),
ty,
c,
ParamLoweringMode::Placeholder,

View File

@ -44,7 +44,8 @@ fn resolve_value_path(&mut self, path: &Path, id: ExprOrPatId) -> Option<ValuePa
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 @@ fn resolve_value_path(&mut self, path: &Path, id: ExprOrPatId) -> Option<ValuePa
}
};
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 @@ fn resolve_assoc_item(
(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 @@ fn resolve_assoc_item(
// 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,

View File

@ -266,7 +266,7 @@ fn const_eq(
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(

View File

@ -2,6 +2,7 @@
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<Arc<Layout>, 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>([T; foo::BAR]);
struct Goal(Ar<Ar<i32>>);
}
size_and_align! {
type Goal = [u8; 2 + 2];
}
}
#[test]

View File

@ -27,10 +27,11 @@
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 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 @@ pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) {
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 @@ fn substs_from_args_and_bindings(
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<Name>,
) -> Arc<[Binders<QuantifiedWhereClause>]> {
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<TraitEnvironment> {
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<QuantifiedWhereClause>]> {
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<chalk_ir::GenericArg<Interner>>]> {
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::<Vec<_>>();
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<Ty> {
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<Ty> {
fn type_for_static(db: &dyn HirDatabase, def: StaticId) -> Binders<Ty> {
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::<Vec<_>>();
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<T
if let StructKind::Unit = struct_data.variant_data.kind() {
return type_for_adt(db, def.into());
}
let generics = generics(db.upcast(), def.into());
let generics = generics(db.upcast(), AdtId::from(def).into());
let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
make_binders(
db,
@ -1729,8 +1741,8 @@ fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId)
let var_data = &enum_data.variants[def.local_id];
let fields = var_data.variant_data.fields();
let resolver = def.parent.resolver(db.upcast());
let ctx =
TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
let ctx = TyLoweringContext::new(db, &resolver, DefWithBodyId::VariantId(def).into())
.with_type_param_mode(ParamLoweringMode::Variable);
let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::<Vec<_>>();
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<Ty> {
fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> {
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<crate::GenericArg> {
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,
)
}
}
}

View File

@ -570,7 +570,7 @@ pub(crate) fn apply(&self, table: &mut InferenceTable<'_>, ty: Ty) -> (Ty, Vec<A
.intern(Interner);
}
}
never!("unsize_array with non-reference-to-array {:?}", ty);
// FIXME: report diagnostic if array unsizing happens without indirection.
ty
};
adjust.push(Adjustment {

View File

@ -1876,6 +1876,7 @@ pub fn mir_body_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Result<Arc<Mi
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:?}"),
});
let body = db.body(def);
let infer = db.infer(def);

View File

@ -60,6 +60,9 @@ pub fn pretty_print(&self, db: &dyn HirDatabase) -> String {
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
}

View File

@ -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);

View File

@ -1955,3 +1955,26 @@ fn map<F>(&self, func: F) -> bool
"#,
);
}
#[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();
}
"#,
);
}

View File

@ -1828,6 +1828,38 @@ fn x(self) {
);
}
#[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(

View File

@ -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 @@
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::<Self>().map_or(false, |x| self == x)
}
fn dyn_clone(&self) -> Box<dyn OpaqueInternableThing> {
Box::new(self.clone())
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn box_any(&self) -> Box<dyn std::any::Any> {
Box::new(self.clone())
}
}

View File

@ -40,6 +40,7 @@ fn from(ty: $ty) -> $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 @@ fn from(def: DefWithBody) -> Self {
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 @@ fn from(def: DefWithBodyId) -> Self {
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()),
}
}
}

View File

@ -52,9 +52,10 @@
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 @@ pub fn module(self, db: &dyn HirDatabase) -> Module {
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 @@ pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
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 @@ pub fn body_type(self, db: &dyn HirDatabase) -> Type {
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 @@ fn id(&self) -> DefWithBodyId {
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 @@ pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) {
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 @@ fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
}
}
#[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 @@ fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
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,
}
}
}

View File

@ -1070,8 +1070,12 @@ fn resolve_label(&self, lifetime: &ast::Lifetime) -> Option<Label> {
fn resolve_type(&self, ty: &ast::Type) -> Option<Type> {
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))
}

View File

@ -38,8 +38,8 @@
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 => {

View File

@ -233,6 +233,7 @@ fn def_with_body_id_name(&self, body_id: DefWithBodyId) -> Option<SmolStr> {
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()),
}
}

View File

@ -158,7 +158,7 @@ fn find_lifetime(text: &str) -> impl Fn(&&ast::GenericParam) -> bool + '_ {
.and_then(|lt| known_generics.iter().find(find_lifetime(&lt.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| {

View File

@ -243,6 +243,8 @@ fn search_scope(&self, db: &RootDatabase) -> SearchScope {
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)),

View File

@ -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: "",

View File

@ -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
}

View File

@ -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"

View File

@ -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 ";"

View File

@ -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 "}"

View File

@ -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| {

View File

@ -328,14 +328,21 @@ fn run_inference(
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 {

View File

@ -565,7 +565,7 @@ RefType =
'&' Lifetime? 'mut'? Type
ArrayType =
'[' Type ';' Expr ']'
'[' Type ';' ConstArg ']'
SliceType =
'[' Type ']'

View File

@ -1207,7 +1207,7 @@ impl ArrayType {
pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
pub fn const_arg(&self) -> Option<ConstArg> { support::child(&self.syntax) }
pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
}

View File

@ -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 const fn replace<T>(dest: &mut T, src: T) -> T {
pub fn transmute<Src, Dst>(src: Src) -> Dst;
}
// endregion:transmute
// region:size_of
extern "rust-intrinsic" {
pub fn size_of<T>() -> usize;
}
// endregion:size_of
}
pub mod ptr {
@ -1307,6 +1315,25 @@ pub fn then<T, F: FnOnce() -> T>(self, f: F) -> Option<T> {
}
// 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>()]) -> 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]