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:
commit
dcd31550e2
@ -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,
|
||||
|
@ -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> {
|
||||
|
@ -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);
|
||||
|
@ -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];
|
||||
|
@ -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)]
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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]>,
|
||||
|
@ -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('_'),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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(
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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(
|
||||
|
@ -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]
|
||||
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -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(
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
@ -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()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
|
||||
|
@ -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 => {
|
||||
|
@ -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()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -158,7 +158,7 @@ fn find_lifetime(text: &str) -> impl Fn(&&ast::GenericParam) -> bool + '_ {
|
||||
.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| {
|
||||
|
@ -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)),
|
||||
|
@ -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: "",
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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 ";"
|
||||
|
@ -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 "}"
|
||||
|
@ -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| {
|
||||
|
@ -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 {
|
||||
|
@ -565,7 +565,7 @@ RefType =
|
||||
'&' Lifetime? 'mut'? Type
|
||||
|
||||
ArrayType =
|
||||
'[' Type ';' Expr ']'
|
||||
'[' Type ';' ConstArg ']'
|
||||
|
||||
SliceType =
|
||||
'[' Type ']'
|
||||
|
@ -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![']']) }
|
||||
}
|
||||
|
||||
|
@ -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]
|
||||
|
Loading…
Reference in New Issue
Block a user