summaryrefslogtreecommitdiffstats
path: root/src/tools/rust-analyzer/crates/hir-ty
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:26:03 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:26:03 +0000
commit9918693037dce8aa4bb6f08741b6812923486c18 (patch)
tree21d2b40bec7e6a7ea664acee056eb3d08e15a1cf /src/tools/rust-analyzer/crates/hir-ty
parentReleasing progress-linux version 1.75.0+dfsg1-5~progress7.99u1. (diff)
downloadrustc-9918693037dce8aa4bb6f08741b6812923486c18.tar.xz
rustc-9918693037dce8aa4bb6f08741b6812923486c18.zip
Merging upstream version 1.76.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/tools/rust-analyzer/crates/hir-ty')
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/Cargo.toml29
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs28
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/db.rs26
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs157
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check/case_conv.rs54
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/display.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer.rs37
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs33
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs101
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs42
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs64
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout.rs138
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs30
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs7
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout/tests/closure.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lib.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower.rs234
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs134
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir.rs37
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs88
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs77
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs72
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs62
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs84
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/traits.rs24
39 files changed, 1083 insertions, 607 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
index b95ae05cc..bbcb76a43 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
@@ -13,27 +13,27 @@ doctest = false
[dependencies]
cov-mark = "2.0.0-pre.1"
-itertools = "0.10.5"
+itertools.workspace = true
arrayvec = "0.7.2"
-bitflags = "2.1.0"
+bitflags.workspace = true
smallvec.workspace = true
ena = "0.14.0"
-either = "1.7.0"
+either.workspace = true
oorandom = "11.1.3"
-tracing = "0.1.35"
+tracing.workspace = true
rustc-hash = "1.1.0"
scoped-tls = "1.0.0"
-chalk-solve = { version = "0.92.0", default-features = false }
-chalk-ir = "0.92.0"
-chalk-recursive = { version = "0.92.0", default-features = false }
-chalk-derive = "0.92.0"
+chalk-solve = { version = "0.95.0", default-features = false }
+chalk-ir = "0.95.0"
+chalk-recursive = { version = "0.95.0", default-features = false }
+chalk-derive = "0.95.0"
la-arena.workspace = true
once_cell = "1.17.0"
triomphe.workspace = true
nohash-hasher.workspace = true
typed-arena = "2.0.1"
-rustc_index.workspace = true
+rustc-dependencies.workspace = true
# local deps
stdx.workspace = true
@@ -47,12 +47,13 @@ limit.workspace = true
[dev-dependencies]
expect-test = "1.4.0"
-tracing = "0.1.35"
-tracing-subscriber = { version = "0.3.16", default-features = false, features = [
- "registry",
-] }
-tracing-tree = "0.2.1"
+tracing.workspace = true
+tracing-subscriber.workspace = true
+tracing-tree.workspace = true
project-model = { path = "../project-model" }
# local deps
test-utils.workspace = true
+
+[features]
+in-rust-tree = ["rustc-dependencies/in-rust-tree"]
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
index c0b243ea2..c9ab35685 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
@@ -28,6 +28,7 @@ pub trait TyExt {
fn is_unknown(&self) -> bool;
fn contains_unknown(&self) -> bool;
fn is_ty_var(&self) -> bool;
+ fn is_union(&self) -> bool;
fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)>;
fn as_builtin(&self) -> Option<BuiltinType>;
@@ -96,6 +97,10 @@ impl TyExt for Ty {
matches!(self.kind(Interner), TyKind::InferenceVar(_, _))
}
+ fn is_union(&self) -> bool {
+ matches!(self.adt_id(Interner), Some(AdtId(hir_def::AdtId::UnionId(_))))
+ }
+
fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)> {
match self.kind(Interner) {
TyKind::Adt(AdtId(adt), parameters) => Some((*adt, parameters)),
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
index 0348680e5..9792d945e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
@@ -1,9 +1,10 @@
//! Constant evaluation details
-use base_db::CrateId;
+use base_db::{salsa::Cycle, CrateId};
use chalk_ir::{cast::Cast, BoundVar, DebruijnIndex};
use hir_def::{
- hir::Expr,
+ body::Body,
+ hir::{Expr, ExprId},
path::Path,
resolver::{Resolver, ValueNs},
type_ref::LiteralConstRef,
@@ -136,7 +137,7 @@ pub fn intern_const_ref(
ty: Ty,
krate: CrateId,
) -> Const {
- let layout = db.layout_of_ty(ty.clone(), Arc::new(TraitEnvironment::empty(krate)));
+ let layout = db.layout_of_ty(ty.clone(), TraitEnvironment::empty(krate));
let bytes = match value {
LiteralConstRef::Int(i) => {
// FIXME: We should handle failure of layout better.
@@ -184,7 +185,7 @@ pub fn try_const_usize(db: &dyn HirDatabase, c: &Const) -> Option<u128> {
pub(crate) fn const_eval_recover(
_: &dyn HirDatabase,
- _: &[String],
+ _: &Cycle,
_: &GeneralConstId,
_: &Substitution,
_: &Option<Arc<TraitEnvironment>>,
@@ -194,7 +195,7 @@ pub(crate) fn const_eval_recover(
pub(crate) fn const_eval_static_recover(
_: &dyn HirDatabase,
- _: &[String],
+ _: &Cycle,
_: &StaticId,
) -> Result<Const, ConstEvalError> {
Err(ConstEvalError::MirLowerError(MirLowerError::Loop))
@@ -202,7 +203,7 @@ pub(crate) fn const_eval_static_recover(
pub(crate) fn const_eval_discriminant_recover(
_: &dyn HirDatabase,
- _: &[String],
+ _: &Cycle,
_: &EnumVariantId,
) -> Result<i128, ConstEvalError> {
Err(ConstEvalError::MirLowerError(MirLowerError::Loop))
@@ -280,7 +281,7 @@ pub(crate) fn const_eval_discriminant_variant(
// get an `InferenceResult` instead of an `InferenceContext`. And we should remove `ctx.clone().resolve_all()` here
// and make this function private. See the fixme comment on `InferenceContext::resolve_all`.
pub(crate) fn eval_to_const(
- expr: Idx<Expr>,
+ expr: ExprId,
mode: ParamLoweringMode,
ctx: &mut InferenceContext<'_>,
args: impl FnOnce() -> Generics,
@@ -288,13 +289,24 @@ pub(crate) fn eval_to_const(
) -> Const {
let db = ctx.db;
let infer = ctx.clone().resolve_all();
+ fn has_closure(body: &Body, expr: ExprId) -> bool {
+ if matches!(body[expr], Expr::Closure { .. }) {
+ return true;
+ }
+ let mut r = false;
+ body[expr].walk_child_exprs(|idx| r |= has_closure(body, idx));
+ r
+ }
+ if has_closure(&ctx.body, expr) {
+ // Type checking clousres need an isolated body (See the above FIXME). Bail out early to prevent panic.
+ return unknown_const(infer[expr].clone());
+ }
if let Expr::Path(p) = &ctx.body.exprs[expr] {
let resolver = &ctx.resolver;
if let Some(c) = path_to_const(db, resolver, p, mode, args, debruijn, infer[expr].clone()) {
return c;
}
}
- let infer = ctx.clone().resolve_all();
if let Ok(mir_body) = lower_to_mir(ctx.db, ctx.owner, &ctx.body, &infer, expr) {
if let Ok(result) = interpret_mir(db, Arc::new(mir_body), true, None).0 {
return result;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
index 7ad3659a4..b395e7f4a 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
@@ -1159,6 +1159,20 @@ fn pattern_matching_slice() {
"#,
33213,
);
+ check_number(
+ r#"
+ //- minicore: slice, index, coerce_unsized, copy
+ const fn f(mut slice: &[u32]) -> usize {
+ slice = match slice {
+ [0, rest @ ..] | rest => rest,
+ };
+ slice.len()
+ }
+ const GOAL: usize = f(&[]) + f(&[10]) + f(&[0, 100])
+ + f(&[1000, 1000, 1000]) + f(&[0, 57, 34, 46, 10000, 10000]);
+ "#,
+ 10,
+ );
}
#[test]
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
index 9c96b5ab8..410bcbf03 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
@@ -20,8 +20,8 @@ use crate::{
method_resolution::{InherentImpls, TraitImpls, TyFingerprint},
mir::{BorrowckResult, MirBody, MirLowerError},
Binders, CallableDefId, ClosureId, Const, FnDefId, GenericArg, ImplTraitId, InferenceResult,
- Interner, PolyFnSig, QuantifiedWhereClause, ReturnTypeImplTraits, Substitution, TraitRef, Ty,
- TyDefId, ValueTyDefId,
+ Interner, PolyFnSig, QuantifiedWhereClause, ReturnTypeImplTraits, Substitution,
+ TraitEnvironment, TraitRef, Ty, TyDefId, ValueTyDefId,
};
use hir_expand::name::Name;
@@ -47,7 +47,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
&self,
def: DefWithBodyId,
subst: Substitution,
- env: Arc<crate::TraitEnvironment>,
+ env: Arc<TraitEnvironment>,
) -> Result<Arc<MirBody>, MirLowerError>;
#[salsa::invoke(crate::mir::monomorphized_mir_body_for_closure_query)]
@@ -55,7 +55,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
&self,
def: ClosureId,
subst: Substitution,
- env: Arc<crate::TraitEnvironment>,
+ env: Arc<TraitEnvironment>,
) -> Result<Arc<MirBody>, MirLowerError>;
#[salsa::invoke(crate::mir::borrowck_query)]
@@ -81,7 +81,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
&self,
def: GeneralConstId,
subst: Substitution,
- trait_env: Option<Arc<crate::TraitEnvironment>>,
+ trait_env: Option<Arc<TraitEnvironment>>,
) -> Result<Const, ConstEvalError>;
#[salsa::invoke(crate::consteval::const_eval_static_query)]
@@ -104,16 +104,12 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
&self,
def: AdtId,
subst: Substitution,
- env: Arc<crate::TraitEnvironment>,
+ env: Arc<TraitEnvironment>,
) -> Result<Arc<Layout>, LayoutError>;
#[salsa::invoke(crate::layout::layout_of_ty_query)]
#[salsa::cycle(crate::layout::layout_of_ty_recover)]
- fn layout_of_ty(
- &self,
- ty: Ty,
- env: Arc<crate::TraitEnvironment>,
- ) -> Result<Arc<Layout>, LayoutError>;
+ fn layout_of_ty(&self, ty: Ty, env: Arc<TraitEnvironment>) -> Result<Arc<Layout>, LayoutError>;
#[salsa::invoke(crate::layout::target_data_layout_query)]
fn target_data_layout(&self, krate: CrateId) -> Option<Arc<TargetDataLayout>>;
@@ -121,7 +117,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
#[salsa::invoke(crate::method_resolution::lookup_impl_method_query)]
fn lookup_impl_method(
&self,
- env: Arc<crate::TraitEnvironment>,
+ env: Arc<TraitEnvironment>,
func: FunctionId,
fn_subst: Substitution,
) -> (FunctionId, Substitution);
@@ -149,10 +145,10 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
#[salsa::invoke(crate::lower::trait_environment_for_body_query)]
#[salsa::transparent]
- fn trait_environment_for_body(&self, def: DefWithBodyId) -> Arc<crate::TraitEnvironment>;
+ fn trait_environment_for_body(&self, def: DefWithBodyId) -> Arc<TraitEnvironment>;
#[salsa::invoke(crate::lower::trait_environment_query)]
- fn trait_environment(&self, def: GenericDefId) -> Arc<crate::TraitEnvironment>;
+ fn trait_environment(&self, def: GenericDefId) -> Arc<TraitEnvironment>;
#[salsa::invoke(crate::lower::generic_defaults_query)]
#[salsa::cycle(crate::lower::generic_defaults_recover)]
@@ -249,7 +245,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
fn normalize_projection(
&self,
projection: crate::ProjectionTy,
- env: Arc<crate::TraitEnvironment>,
+ env: Arc<TraitEnvironment>,
) -> Ty;
#[salsa::invoke(trait_solve_wait)]
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs
index ef43ed5c4..c1b361900 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs
@@ -11,9 +11,3 @@ pub use crate::diagnostics::{
},
unsafe_check::{missing_unsafe, unsafe_expressions, UnsafeExpr},
};
-
-#[derive(Debug, PartialEq, Eq)]
-pub struct IncoherentImpl {
- pub file_id: hir_expand::HirFileId,
- pub impl_: syntax::AstPtr<syntax::ast::Impl>,
-}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
index 36d69edf9..51a044d8e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
@@ -9,6 +9,7 @@
//! - constants (e.g. `const FOO: u8 = 10;`)
//! - static items (e.g. `static FOO: u8 = 10;`)
//! - match arm bindings (e.g. `foo @ Some(_)`)
+//! - modules (e.g. `mod foo { ... }` or `mod foo;`)
mod case_conv;
@@ -18,12 +19,12 @@ use hir_def::{
data::adt::VariantData,
hir::{Pat, PatId},
src::HasSource,
- AdtId, AttrDefId, ConstId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, ItemContainerId,
- Lookup, ModuleDefId, StaticId, StructId,
+ AdtId, AttrDefId, ConstId, EnumId, FunctionId, ItemContainerId, Lookup, ModuleDefId, ModuleId,
+ StaticId, StructId,
};
use hir_expand::{
name::{AsName, Name},
- HirFileId,
+ HirFileId, MacroFileIdExt,
};
use stdx::{always, never};
use syntax::{
@@ -83,6 +84,7 @@ pub enum IdentType {
Structure,
Variable,
Variant,
+ Module,
}
impl fmt::Display for IdentType {
@@ -97,6 +99,7 @@ impl fmt::Display for IdentType {
IdentType::Structure => "Structure",
IdentType::Variable => "Variable",
IdentType::Variant => "Variant",
+ IdentType::Module => "Module",
};
repr.fmt(f)
@@ -132,6 +135,7 @@ impl<'a> DeclValidator<'a> {
pub(super) fn validate_item(&mut self, item: ModuleDefId) {
match item {
+ ModuleDefId::ModuleId(module_id) => self.validate_module(module_id),
ModuleDefId::FunctionId(func) => self.validate_func(func),
ModuleDefId::AdtId(adt) => self.validate_adt(adt),
ModuleDefId::ConstId(const_id) => self.validate_const(const_id),
@@ -192,7 +196,7 @@ impl<'a> DeclValidator<'a> {
AttrDefId::GenericParamId(_) => None,
}
.map_or(false, |file_id| {
- file_id.is_custom_derive(db.upcast()) || file_id.is_builtin_derive(db.upcast())
+ matches!(file_id.macro_file(), Some(file_id) if file_id.is_custom_derive(db.upcast()) || file_id.is_builtin_derive(db.upcast()))
})
};
@@ -230,6 +234,55 @@ impl<'a> DeclValidator<'a> {
|| parent()
}
+ fn validate_module(&mut self, module_id: ModuleId) {
+ // Check whether non-snake case identifiers are allowed for this module.
+ if self.allowed(module_id.into(), allow::NON_SNAKE_CASE, false) {
+ return;
+ }
+
+ // Check the module name.
+ let Some(module_name) = module_id.name(self.db.upcast()) else { return };
+ let module_name_replacement =
+ module_name.as_str().and_then(to_lower_snake_case).map(|new_name| Replacement {
+ current_name: module_name,
+ suggested_text: new_name,
+ expected_case: CaseType::LowerSnakeCase,
+ });
+
+ if let Some(module_name_replacement) = module_name_replacement {
+ let module_data = &module_id.def_map(self.db.upcast())[module_id.local_id];
+ let module_src = module_data.declaration_source(self.db.upcast());
+
+ if let Some(module_src) = module_src {
+ let ast_ptr = match module_src.value.name() {
+ Some(name) => name,
+ None => {
+ never!(
+ "Replacement ({:?}) was generated for a module without a name: {:?}",
+ module_name_replacement,
+ module_src
+ );
+ return;
+ }
+ };
+
+ let diagnostic = IncorrectCase {
+ file: module_src.file_id,
+ ident_type: IdentType::Module,
+ ident: AstPtr::new(&ast_ptr),
+ expected_case: module_name_replacement.expected_case,
+ ident_text: module_name_replacement
+ .current_name
+ .display(self.db.upcast())
+ .to_string(),
+ suggested_text: module_name_replacement.suggested_text,
+ };
+
+ self.sink.push(diagnostic);
+ }
+ }
+ }
+
fn validate_func(&mut self, func: FunctionId) {
let data = self.db.function_data(func);
if matches!(func.lookup(self.db.upcast()).container, ItemContainerId::ExternBlockId(_)) {
@@ -237,8 +290,6 @@ impl<'a> DeclValidator<'a> {
return;
}
- self.validate_body_inner_items(func.into());
-
// Check whether non-snake case identifiers are allowed for this function.
if self.allowed(func.into(), allow::NON_SNAKE_CASE, false) {
return;
@@ -336,48 +387,44 @@ impl<'a> DeclValidator<'a> {
for (id, replacement) in pats_replacements {
if let Ok(source_ptr) = source_map.pat_syntax(id) {
- if let Some(expr) = source_ptr.value.as_ref().left() {
+ if let Some(ptr) = source_ptr.value.clone().cast::<ast::IdentPat>() {
let root = source_ptr.file_syntax(self.db.upcast());
- if let ast::Pat::IdentPat(ident_pat) = expr.to_node(&root) {
- let parent = match ident_pat.syntax().parent() {
- Some(parent) => parent,
- None => continue,
- };
- let name_ast = match ident_pat.name() {
- Some(name_ast) => name_ast,
- None => continue,
- };
+ let ident_pat = ptr.to_node(&root);
+ let parent = match ident_pat.syntax().parent() {
+ Some(parent) => parent,
+ None => continue,
+ };
+ let name_ast = match ident_pat.name() {
+ Some(name_ast) => name_ast,
+ None => continue,
+ };
+
+ let is_param = ast::Param::can_cast(parent.kind());
+
+ // We have to check that it's either `let var = ...` or `var @ Variant(_)` statement,
+ // because e.g. match arms are patterns as well.
+ // In other words, we check that it's a named variable binding.
+ let is_binding = ast::LetStmt::can_cast(parent.kind())
+ || (ast::MatchArm::can_cast(parent.kind())
+ && ident_pat.at_token().is_some());
+ if !(is_param || is_binding) {
+ // This pattern is not an actual variable declaration, e.g. `Some(val) => {..}` match arm.
+ continue;
+ }
- let is_param = ast::Param::can_cast(parent.kind());
-
- // We have to check that it's either `let var = ...` or `var @ Variant(_)` statement,
- // because e.g. match arms are patterns as well.
- // In other words, we check that it's a named variable binding.
- let is_binding = ast::LetStmt::can_cast(parent.kind())
- || (ast::MatchArm::can_cast(parent.kind())
- && ident_pat.at_token().is_some());
- if !(is_param || is_binding) {
- // This pattern is not an actual variable declaration, e.g. `Some(val) => {..}` match arm.
- continue;
- }
+ let ident_type =
+ if is_param { IdentType::Parameter } else { IdentType::Variable };
- let ident_type =
- if is_param { IdentType::Parameter } else { IdentType::Variable };
-
- let diagnostic = IncorrectCase {
- file: source_ptr.file_id,
- ident_type,
- ident: AstPtr::new(&name_ast),
- expected_case: replacement.expected_case,
- ident_text: replacement
- .current_name
- .display(self.db.upcast())
- .to_string(),
- suggested_text: replacement.suggested_text,
- };
+ let diagnostic = IncorrectCase {
+ file: source_ptr.file_id,
+ ident_type,
+ ident: AstPtr::new(&name_ast),
+ expected_case: replacement.expected_case,
+ ident_text: replacement.current_name.display(self.db.upcast()).to_string(),
+ suggested_text: replacement.suggested_text,
+ };
- self.sink.push(diagnostic);
- }
+ self.sink.push(diagnostic);
}
}
}
@@ -519,11 +566,6 @@ impl<'a> DeclValidator<'a> {
fn validate_enum(&mut self, enum_id: EnumId) {
let data = self.db.enum_data(enum_id);
- for (local_id, _) in data.variants.iter() {
- let variant_id = EnumVariantId { parent: enum_id, local_id };
- self.validate_body_inner_items(variant_id.into());
- }
-
// Check whether non-camel case names are allowed for this enum.
if self.allowed(enum_id.into(), allow::NON_CAMEL_CASE_TYPES, false) {
return;
@@ -648,8 +690,6 @@ impl<'a> DeclValidator<'a> {
fn validate_const(&mut self, const_id: ConstId) {
let data = self.db.const_data(const_id);
- self.validate_body_inner_items(const_id.into());
-
if self.allowed(const_id.into(), allow::NON_UPPER_CASE_GLOBAL, false) {
return;
}
@@ -698,8 +738,6 @@ impl<'a> DeclValidator<'a> {
return;
}
- self.validate_body_inner_items(static_id.into());
-
if self.allowed(static_id.into(), allow::NON_UPPER_CASE_GLOBAL, false) {
return;
}
@@ -737,17 +775,4 @@ impl<'a> DeclValidator<'a> {
self.sink.push(diagnostic);
}
-
- // FIXME: We don't currently validate names within `DefWithBodyId::InTypeConstId`.
- /// Recursively validates inner scope items, such as static variables and constants.
- fn validate_body_inner_items(&mut self, body_id: DefWithBodyId) {
- let body = self.db.body(body_id);
- for (_, block_def_map) in body.blocks(self.db.upcast()) {
- for (_, module) in block_def_map.modules() {
- for def_id in module.scope.declarations() {
- self.validate_item(def_id);
- }
- }
- }
- }
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check/case_conv.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check/case_conv.rs
index 2c1368962..cbe1af157 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check/case_conv.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check/case_conv.rs
@@ -11,50 +11,7 @@ pub(crate) fn to_camel_case(ident: &str) -> Option<String> {
return None;
}
- // Taken from rustc.
- let ret = ident
- .trim_matches('_')
- .split('_')
- .filter(|component| !component.is_empty())
- .map(|component| {
- let mut camel_cased_component = String::with_capacity(component.len());
-
- let mut new_word = true;
- let mut prev_is_lower_case = true;
-
- for c in component.chars() {
- // Preserve the case if an uppercase letter follows a lowercase letter, so that
- // `camelCase` is converted to `CamelCase`.
- if prev_is_lower_case && c.is_uppercase() {
- new_word = true;
- }
-
- if new_word {
- camel_cased_component.extend(c.to_uppercase());
- } else {
- camel_cased_component.extend(c.to_lowercase());
- }
-
- prev_is_lower_case = c.is_lowercase();
- new_word = false;
- }
-
- camel_cased_component
- })
- .fold((String::new(), None), |(acc, prev): (_, Option<String>), next| {
- // separate two components with an underscore if their boundary cannot
- // be distinguished using an uppercase/lowercase case distinction
- let join = prev
- .and_then(|prev| {
- let f = next.chars().next()?;
- let l = prev.chars().last()?;
- Some(!char_has_case(l) && !char_has_case(f))
- })
- .unwrap_or(false);
- (acc + if join { "_" } else { "" } + &next, Some(next))
- })
- .0;
- Some(ret)
+ Some(stdx::to_camel_case(ident))
}
/// Converts an identifier to a lower_snake_case form.
@@ -97,7 +54,9 @@ fn is_camel_case(name: &str) -> bool {
&& !name.chars().any(|snd| {
let ret = match fst {
None => false,
- Some(fst) => char_has_case(fst) && snd == '_' || char_has_case(snd) && fst == '_',
+ Some(fst) => {
+ stdx::char_has_case(fst) && snd == '_' || stdx::char_has_case(snd) && fst == '_'
+ }
};
fst = Some(snd);
@@ -135,11 +94,6 @@ fn is_snake_case<F: Fn(char) -> bool>(ident: &str, wrong_case: F) -> bool {
})
}
-// Taken from rustc.
-fn char_has_case(c: char) -> bool {
- c.is_lowercase() || c.is_uppercase()
-}
-
#[cfg(test)]
mod tests {
use super::*;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs
index f8cdeaa5e..2e04bbfee 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs
@@ -147,7 +147,7 @@ impl<'a> PatCtxt<'a> {
}
hir_def::hir::Pat::Bind { id, subpat, .. } => {
- let bm = self.infer.binding_modes[id];
+ let bm = self.infer.binding_modes[pat];
ty = &self.infer[id];
let name = &self.body.bindings[id].name;
match (bm, ty.kind(Interner)) {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
index f6d6b00d7..d81926f7c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -23,7 +23,7 @@ use hir_def::{
EnumVariantId, HasModule, ItemContainerId, LocalFieldId, Lookup, ModuleDefId, ModuleId,
TraitId,
};
-use hir_expand::{hygiene::Hygiene, name::Name};
+use hir_expand::name::Name;
use intern::{Internable, Interned};
use itertools::Itertools;
use la_arena::ArenaMap;
@@ -448,9 +448,8 @@ fn render_const_scalar(
) -> Result<(), HirDisplayError> {
// FIXME: We need to get krate from the final callers of the hir display
// infrastructure and have it here as a field on `f`.
- let trait_env = Arc::new(TraitEnvironment::empty(
- *f.db.crate_graph().crates_in_topological_order().last().unwrap(),
- ));
+ let trait_env =
+ TraitEnvironment::empty(*f.db.crate_graph().crates_in_topological_order().last().unwrap());
match ty.kind(Interner) {
TyKind::Scalar(s) => match s {
Scalar::Bool => write!(f, "{}", if b[0] == 0 { false } else { true }),
@@ -945,6 +944,7 @@ impl HirDisplay for Ty {
ItemInNs::Types((*def_id).into()),
module_id,
false,
+ true,
) {
write!(f, "{}", path.display(f.db.upcast()))?;
} else {
@@ -1731,13 +1731,13 @@ impl HirDisplay for TypeRef {
f.write_joined(bounds, " + ")?;
}
TypeRef::Macro(macro_call) => {
- let macro_call = macro_call.to_node(f.db.upcast());
- let ctx = hir_def::lower::LowerCtx::with_hygiene(
+ let ctx = hir_def::lower::LowerCtx::with_span_map(
f.db.upcast(),
- &Hygiene::new_unhygienic(),
+ f.db.span_map(macro_call.file_id),
);
+ let macro_call = macro_call.to_node(f.db.upcast());
match macro_call.path() {
- Some(path) => match Path::from_src(path, &ctx) {
+ Some(path) => match Path::from_src(&ctx, path) {
Some(path) => path.hir_fmt(f)?,
None => write!(f, "{{macro}}")?,
},
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
index 78d3c667a..6f724e458 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
@@ -113,7 +113,7 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<Infer
// FIXME(const-generic-body): We should not get the return type in this way.
ctx.return_ty = c
.lookup(db.upcast())
- .thing
+ .expected_ty
.box_any()
.downcast::<InTypeConstIdMetadata>()
.unwrap()
@@ -420,7 +420,19 @@ pub struct InferenceResult {
standard_types: InternedStandardTypes,
/// Stores the types which were implicitly dereferenced in pattern binding modes.
pub pat_adjustments: FxHashMap<PatId, Vec<Ty>>,
- pub binding_modes: ArenaMap<BindingId, BindingMode>,
+ /// Stores the binding mode (`ref` in `let ref x = 2`) of bindings.
+ ///
+ /// This one is tied to the `PatId` instead of `BindingId`, because in some rare cases, a binding in an
+ /// or pattern can have multiple binding modes. For example:
+ /// ```
+ /// fn foo(mut slice: &[u32]) -> usize {
+ /// slice = match slice {
+ /// [0, rest @ ..] | rest => rest,
+ /// };
+ /// }
+ /// ```
+ /// the first `rest` has implicit `ref` binding mode, but the second `rest` binding mode is `move`.
+ pub binding_modes: ArenaMap<PatId, BindingMode>,
pub expr_adjustments: FxHashMap<ExprId, Vec<Adjustment>>,
pub(crate) closure_info: FxHashMap<ClosureId, (Vec<CapturedItem>, FnTrait)>,
// FIXME: remove this field
@@ -1140,20 +1152,15 @@ impl<'a> InferenceContext<'a> {
(ty, variant)
}
TypeNs::TypeAliasId(it) => {
- let container = it.lookup(self.db.upcast()).container;
- let parent_subst = match container {
- ItemContainerId::TraitId(id) => {
- let subst = TyBuilder::subst_for_def(self.db, id, None)
- .fill_with_inference_vars(&mut self.table)
- .build();
- Some(subst)
- }
- // Type aliases do not exist in impls.
- _ => None,
+ let resolved_seg = match unresolved {
+ None => path.segments().last().unwrap(),
+ Some(n) => path.segments().get(path.segments().len() - n - 1).unwrap(),
};
- let ty = TyBuilder::def_ty(self.db, it.into(), parent_subst)
- .fill_with_inference_vars(&mut self.table)
- .build();
+ let substs =
+ ctx.substs_from_path_segment(resolved_seg, Some(it.into()), true, None);
+ let ty = self.db.ty(it.into());
+ let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
+
self.resolve_variant_on_alias(ty, unresolved, mod_path)
}
TypeNs::AdtSelfType(_) => {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
index 13d6b5643..af74df103 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
@@ -679,7 +679,7 @@ impl InferenceContext<'_> {
| Pat::Range { .. } => {
update_result(CaptureKind::ByRef(BorrowKind::Shared));
}
- Pat::Bind { id, .. } => match self.result.binding_modes[*id] {
+ Pat::Bind { id, .. } => match self.result.binding_modes[p] {
crate::BindingMode::Move => {
if self.is_ty_copy(self.result.type_of_binding[*id].clone()) {
update_result(CaptureKind::ByRef(BorrowKind::Shared));
@@ -735,6 +735,32 @@ impl InferenceContext<'_> {
self.walk_expr(expr);
}
+ fn restrict_precision_for_unsafe(&mut self) {
+ for capture in &mut self.current_captures {
+ let mut ty = self.table.resolve_completely(self.result[capture.place.local].clone());
+ if ty.as_raw_ptr().is_some() || ty.is_union() {
+ capture.kind = CaptureKind::ByRef(BorrowKind::Shared);
+ capture.place.projections.truncate(0);
+ continue;
+ }
+ for (i, p) in capture.place.projections.iter().enumerate() {
+ ty = p.projected_ty(
+ ty,
+ self.db,
+ |_, _, _| {
+ unreachable!("Closure field only happens in MIR");
+ },
+ self.owner.module(self.db.upcast()).krate(),
+ );
+ if ty.as_raw_ptr().is_some() || ty.is_union() {
+ capture.kind = CaptureKind::ByRef(BorrowKind::Shared);
+ capture.place.projections.truncate(i + 1);
+ break;
+ }
+ }
+ }
+ }
+
fn adjust_for_move_closure(&mut self) {
for capture in &mut self.current_captures {
if let Some(first_deref) =
@@ -838,8 +864,8 @@ impl InferenceContext<'_> {
| Pat::ConstBlock(_)
| Pat::Path(_)
| Pat::Lit(_) => self.consume_place(place, pat.into()),
- Pat::Bind { id, subpat: _ } => {
- let mode = self.result.binding_modes[*id];
+ Pat::Bind { id: _, subpat: _ } => {
+ let mode = self.result.binding_modes[pat];
let capture_kind = match mode {
BindingMode::Move => {
self.consume_place(place, pat.into());
@@ -924,6 +950,7 @@ impl InferenceContext<'_> {
self.result.mutated_bindings_in_closure.insert(item.place.local);
}
}
+ self.restrict_precision_for_unsafe();
// closure_kind should be done before adjust_for_move_closure
let closure_kind = self.closure_kind();
match capture_by {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
index 0c3c725a7..a5e77a12d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
@@ -18,7 +18,6 @@ use hir_def::{
use hir_expand::name::{name, Name};
use stdx::always;
use syntax::ast::RangeOp;
-use triomphe::Arc;
use crate::{
autoderef::{builtin_deref, deref_by_trait, Autoderef},
@@ -40,7 +39,8 @@ use crate::{
traits::FnTrait,
utils::{generics, Generics},
Adjust, Adjustment, AdtId, AutoBorrow, Binders, CallableDefId, FnPointer, FnSig, FnSubst,
- Interner, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
+ Interner, Rawness, Scalar, Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt,
+ TyKind,
};
use super::{
@@ -579,7 +579,7 @@ impl InferenceContext<'_> {
}
ty
}
- Expr::Field { expr, name } => self.infer_field_access(tgt_expr, *expr, name),
+ Expr::Field { expr, name } => self.infer_field_access(tgt_expr, *expr, name, expected),
Expr::Await { expr } => {
let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
self.resolve_associated_type(inner_ty, self.resolve_future_future_output())
@@ -1291,7 +1291,7 @@ impl InferenceContext<'_> {
let g = self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, expr);
let prev_env = block_id.map(|block_id| {
let prev_env = self.table.trait_env.clone();
- Arc::make_mut(&mut self.table.trait_env).block = Some(block_id);
+ TraitEnvironment::with_block(&mut self.table.trait_env, block_id);
prev_env
});
@@ -1456,7 +1456,13 @@ impl InferenceContext<'_> {
})
}
- fn infer_field_access(&mut self, tgt_expr: ExprId, receiver: ExprId, name: &Name) -> Ty {
+ fn infer_field_access(
+ &mut self,
+ tgt_expr: ExprId,
+ receiver: ExprId,
+ name: &Name,
+ expected: &Expectation,
+ ) -> Ty {
let receiver_ty = self.infer_expr_inner(receiver, &Expectation::none());
if name.is_missing() {
@@ -1482,28 +1488,42 @@ impl InferenceContext<'_> {
ty
}
None => {
- // no field found,
- let method_with_same_name_exists = {
- self.get_traits_in_scope();
-
- let canonicalized_receiver = self.canonicalize(receiver_ty.clone());
- method_resolution::lookup_method(
- self.db,
- &canonicalized_receiver.value,
- self.table.trait_env.clone(),
- self.get_traits_in_scope().as_ref().left_or_else(|&it| it),
- VisibleFromModule::Filter(self.resolver.module()),
- name,
- )
- .is_some()
- };
+ // no field found, lets attempt to resolve it like a function so that IDE things
+ // work out while people are typing
+ let canonicalized_receiver = self.canonicalize(receiver_ty.clone());
+ let resolved = method_resolution::lookup_method(
+ self.db,
+ &canonicalized_receiver.value,
+ self.table.trait_env.clone(),
+ self.get_traits_in_scope().as_ref().left_or_else(|&it| it),
+ VisibleFromModule::Filter(self.resolver.module()),
+ name,
+ );
self.result.diagnostics.push(InferenceDiagnostic::UnresolvedField {
expr: tgt_expr,
- receiver: receiver_ty,
+ receiver: receiver_ty.clone(),
name: name.clone(),
- method_with_same_name_exists,
+ method_with_same_name_exists: resolved.is_some(),
});
- self.err_ty()
+ match resolved {
+ Some((adjust, func, _)) => {
+ let (ty, adjustments) = adjust.apply(&mut self.table, receiver_ty);
+ let generics = generics(self.db.upcast(), func.into());
+ let substs = self.substs_for_method_call(generics, None);
+ self.write_expr_adj(receiver, adjustments);
+ self.write_method_resolution(tgt_expr, func, substs.clone());
+
+ self.check_method_call(
+ tgt_expr,
+ &[],
+ self.db.value_ty(func.into()),
+ substs,
+ ty,
+ expected,
+ )
+ }
+ None => self.err_ty(),
+ }
}
}
}
@@ -1517,7 +1537,7 @@ impl InferenceContext<'_> {
generic_args: Option<&GenericArgs>,
expected: &Expectation,
) -> Ty {
- let receiver_ty = self.infer_expr(receiver, &Expectation::none());
+ let receiver_ty = self.infer_expr_inner(receiver, &Expectation::none());
let canonicalized_receiver = self.canonicalize(receiver_ty.clone());
let resolved = method_resolution::lookup_method(
@@ -1568,23 +1588,32 @@ impl InferenceContext<'_> {
)
}
};
+ self.check_method_call(tgt_expr, args, method_ty, substs, receiver_ty, expected)
+ }
+
+ fn check_method_call(
+ &mut self,
+ tgt_expr: ExprId,
+ args: &[ExprId],
+ method_ty: Binders<Ty>,
+ substs: Substitution,
+ receiver_ty: Ty,
+ expected: &Expectation,
+ ) -> Ty {
let method_ty = method_ty.substitute(Interner, &substs);
self.register_obligations_for_call(&method_ty);
- let (formal_receiver_ty, param_tys, ret_ty, is_varargs) =
+ let ((formal_receiver_ty, param_tys), ret_ty, is_varargs) =
match method_ty.callable_sig(self.db) {
- Some(sig) => {
+ Some(sig) => (
if !sig.params().is_empty() {
- (
- sig.params()[0].clone(),
- sig.params()[1..].to_vec(),
- sig.ret().clone(),
- sig.is_varargs,
- )
+ (sig.params()[0].clone(), sig.params()[1..].to_vec())
} else {
- (self.err_ty(), Vec::new(), sig.ret().clone(), sig.is_varargs)
- }
- }
- None => (self.err_ty(), Vec::new(), self.err_ty(), true),
+ (self.err_ty(), Vec::new())
+ },
+ sig.ret().clone(),
+ sig.is_varargs,
+ ),
+ None => ((self.err_ty(), Vec::new()), self.err_ty(), true),
};
self.unify(&formal_receiver_ty, &receiver_ty);
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
index 4e28ec060..acdb54028 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
@@ -262,7 +262,7 @@ impl InferenceContext<'_> {
fn infer_pat(&mut self, pat: PatId, expected: &Ty, mut default_bm: BindingMode) -> Ty {
let mut expected = self.resolve_ty_shallow(expected);
- if is_non_ref_pat(self.body, pat) {
+ if self.is_non_ref_pat(self.body, pat) {
let mut pat_adjustments = Vec::new();
while let Some((inner, _lifetime, mutability)) = expected.as_reference() {
pat_adjustments.push(expected.clone());
@@ -421,7 +421,7 @@ impl InferenceContext<'_> {
} else {
BindingMode::convert(mode)
};
- self.result.binding_modes.insert(binding, mode);
+ self.result.binding_modes.insert(pat, mode);
let inner_ty = match subpat {
Some(subpat) => self.infer_pat(subpat, &expected, default_bm),
@@ -496,24 +496,28 @@ impl InferenceContext<'_> {
self.infer_expr(expr, &Expectation::has_type(expected.clone()))
}
-}
-fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool {
- match &body[pat] {
- Pat::Tuple { .. }
- | Pat::TupleStruct { .. }
- | Pat::Record { .. }
- | Pat::Range { .. }
- | Pat::Slice { .. } => true,
- Pat::Or(pats) => pats.iter().all(|p| is_non_ref_pat(body, *p)),
- // FIXME: ConstBlock/Path/Lit might actually evaluate to ref, but inference is unimplemented.
- Pat::Path(..) => true,
- Pat::ConstBlock(..) => true,
- Pat::Lit(expr) => !matches!(
- body[*expr],
- Expr::Literal(Literal::String(..) | Literal::CString(..) | Literal::ByteString(..))
- ),
- Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Box { .. } | Pat::Missing => false,
+ fn is_non_ref_pat(&mut self, body: &hir_def::body::Body, pat: PatId) -> bool {
+ match &body[pat] {
+ Pat::Tuple { .. }
+ | Pat::TupleStruct { .. }
+ | Pat::Record { .. }
+ | Pat::Range { .. }
+ | Pat::Slice { .. } => true,
+ Pat::Or(pats) => pats.iter().all(|p| self.is_non_ref_pat(body, *p)),
+ Pat::Path(p) => {
+ let v = self.resolve_value_path_inner(p, pat.into());
+ v.is_some_and(|x| !matches!(x.0, hir_def::resolver::ValueNs::ConstId(_)))
+ }
+ Pat::ConstBlock(..) => false,
+ Pat::Lit(expr) => !matches!(
+ body[*expr],
+ Expr::Literal(Literal::String(..) | Literal::CString(..) | Literal::ByteString(..))
+ ),
+ Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Box { .. } | Pat::Missing => {
+ false
+ }
+ }
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
index c6bbf2f61..49fb78f67 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
@@ -40,33 +40,7 @@ impl InferenceContext<'_> {
}
fn resolve_value_path(&mut self, path: &Path, id: ExprOrPatId) -> Option<ValuePathResolution> {
- let (value, self_subst) = if let Some(type_ref) = path.type_anchor() {
- 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, 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);
-
- let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1);
- let (ty, _) = ctx.lower_ty_relative_path(ty, orig_ns, remaining_segments_for_ty);
- let ty = self.table.insert_type_vars(ty);
- let ty = self.table.normalize_associated_types_in(ty);
- self.resolve_ty_assoc_item(ty, last.name, id).map(|(it, substs)| (it, Some(substs)))?
- } else {
- // FIXME: report error, unresolved first path segment
- let value_or_partial =
- self.resolver.resolve_path_in_value_ns(self.db.upcast(), path)?;
-
- match value_or_partial {
- ResolveValueResult::ValueNs(it, _) => (it, None),
- ResolveValueResult::Partial(def, remaining_index, _) => self
- .resolve_assoc_item(def, path, remaining_index, id)
- .map(|(it, substs)| (it, Some(substs)))?,
- }
- };
+ let (value, self_subst) = self.resolve_value_path_inner(path, id)?;
let value_def = match value {
ValueNs::LocalBinding(pat) => match self.result.type_of_binding.get(pat) {
@@ -144,6 +118,41 @@ impl InferenceContext<'_> {
Some(ValuePathResolution::GenericDef(value_def, generic_def, substs))
}
+ pub(super) fn resolve_value_path_inner(
+ &mut self,
+ path: &Path,
+ id: ExprOrPatId,
+ ) -> Option<(ValueNs, Option<chalk_ir::Substitution<Interner>>)> {
+ let (value, self_subst) = if let Some(type_ref) = path.type_anchor() {
+ 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, 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);
+
+ let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1);
+ let (ty, _) = ctx.lower_ty_relative_path(ty, orig_ns, remaining_segments_for_ty);
+ let ty = self.table.insert_type_vars(ty);
+ let ty = self.table.normalize_associated_types_in(ty);
+ self.resolve_ty_assoc_item(ty, last.name, id).map(|(it, substs)| (it, Some(substs)))?
+ } else {
+ // FIXME: report error, unresolved first path segment
+ let value_or_partial =
+ self.resolver.resolve_path_in_value_ns(self.db.upcast(), path)?;
+
+ match value_or_partial {
+ ResolveValueResult::ValueNs(it, _) => (it, None),
+ ResolveValueResult::Partial(def, remaining_index, _) => self
+ .resolve_assoc_item(def, path, remaining_index, id)
+ .map(|(it, substs)| (it, Some(substs)))?,
+ }
+ };
+ Some((value, self_subst))
+ }
+
fn add_required_obligations_for_value_path(&mut self, def: GenericDefId, subst: &Substitution) {
let predicates = self.db.generic_predicates(def);
for predicate in predicates.iter() {
@@ -390,6 +399,7 @@ impl InferenceContext<'_> {
}
}
+#[derive(Debug)]
enum ValuePathResolution {
// It's awkward to wrap a single ID in two enums, but we need both and this saves fallible
// conversion between them + `unwrap()`.
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
index 0a68a9f3b..ac39bdf5b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
@@ -43,7 +43,7 @@ where
}
impl<T: HasInterner<Interner = Interner>> Canonicalized<T> {
- pub(super) fn apply_solution(
+ pub(crate) fn apply_solution(
&self,
ctx: &mut InferenceTable<'_>,
solution: Canonical<Substitution>,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
index 1a6106c02..bfc4f1383 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
@@ -1,5 +1,8 @@
//! Compute the binary representation of a type
+use std::fmt;
+
+use base_db::salsa::Cycle;
use chalk_ir::{AdtId, FloatTy, IntTy, TyKind, UintTy};
use hir_def::{
layout::{
@@ -9,6 +12,10 @@ use hir_def::{
LocalEnumVariantId, LocalFieldId, StructId,
};
use la_arena::{Idx, RawIdx};
+use rustc_dependencies::{
+ abi::AddressSpace,
+ index::{IndexSlice, IndexVec},
+};
use stdx::never;
use triomphe::Arc;
@@ -22,19 +29,13 @@ pub use self::{
target::target_data_layout_query,
};
-macro_rules! user_error {
- ($it: expr) => {
- return Err(LayoutError::UserError(format!($it).into()))
- };
-}
-
mod adt;
mod target;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct RustcEnumVariantIdx(pub LocalEnumVariantId);
-impl rustc_index::vec::Idx for RustcEnumVariantIdx {
+impl rustc_dependencies::index::Idx for RustcEnumVariantIdx {
fn new(idx: usize) -> Self {
RustcEnumVariantIdx(Idx::from_raw(RawIdx::from(idx as u32)))
}
@@ -44,19 +45,63 @@ impl rustc_index::vec::Idx for RustcEnumVariantIdx {
}
}
-pub type Layout = LayoutS<RustcEnumVariantIdx>;
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct RustcFieldIdx(pub LocalFieldId);
+
+impl RustcFieldIdx {
+ pub fn new(idx: usize) -> Self {
+ RustcFieldIdx(Idx::from_raw(RawIdx::from(idx as u32)))
+ }
+}
+
+impl rustc_dependencies::index::Idx for RustcFieldIdx {
+ fn new(idx: usize) -> Self {
+ RustcFieldIdx(Idx::from_raw(RawIdx::from(idx as u32)))
+ }
+
+ fn index(self) -> usize {
+ u32::from(self.0.into_raw()) as usize
+ }
+}
+
+pub type Layout = LayoutS<RustcFieldIdx, RustcEnumVariantIdx>;
pub type TagEncoding = hir_def::layout::TagEncoding<RustcEnumVariantIdx>;
-pub type Variants = hir_def::layout::Variants<RustcEnumVariantIdx>;
+pub type Variants = hir_def::layout::Variants<RustcFieldIdx, RustcEnumVariantIdx>;
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum LayoutError {
- UserError(Box<str>),
- SizeOverflow,
- TargetLayoutNotAvailable,
- HasPlaceholder,
+ HasErrorConst,
HasErrorType,
+ HasPlaceholder,
+ InvalidSimdType,
NotImplemented,
+ RecursiveTypeWithoutIndirection,
+ SizeOverflow,
+ TargetLayoutNotAvailable,
Unknown,
+ UserReprTooSmall,
+}
+
+impl std::error::Error for LayoutError {}
+impl fmt::Display for LayoutError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ LayoutError::HasErrorConst => write!(f, "type contains an unevaluatable const"),
+ LayoutError::HasErrorType => write!(f, "type contains an error"),
+ LayoutError::HasPlaceholder => write!(f, "type contains placeholders"),
+ LayoutError::InvalidSimdType => write!(f, "invalid simd type definition"),
+ LayoutError::NotImplemented => write!(f, "not implemented"),
+ LayoutError::RecursiveTypeWithoutIndirection => {
+ write!(f, "recursive type without indirection")
+ }
+ LayoutError::SizeOverflow => write!(f, "size overflow"),
+ LayoutError::TargetLayoutNotAvailable => write!(f, "target layout not available"),
+ LayoutError::Unknown => write!(f, "unknown"),
+ LayoutError::UserReprTooSmall => {
+ write!(f, "the `#[repr]` hint is too small to hold the discriminants of the enum")
+ }
+ }
+ }
}
struct LayoutCx<'a> {
@@ -66,7 +111,7 @@ struct LayoutCx<'a> {
impl<'a> LayoutCalculator for LayoutCx<'a> {
type TargetDataLayoutRef = &'a TargetDataLayout;
- fn delay_bug(&self, txt: &str) {
+ fn delayed_bug(&self, txt: String) {
never!("{}", txt);
}
@@ -95,9 +140,7 @@ fn layout_of_simd_ty(
let f0_ty = match fields.iter().next() {
Some(it) => it.1.clone().substitute(Interner, subst),
- None => {
- user_error!("simd type with zero fields");
- }
+ None => return Err(LayoutError::InvalidSimdType),
};
// The element type and number of elements of the SIMD vector
@@ -111,7 +154,7 @@ fn layout_of_simd_ty(
// Extract the number of elements from the layout of the array field:
let FieldsShape::Array { count, .. } = db.layout_of_ty(f0_ty.clone(), env.clone())?.fields
else {
- user_error!("Array with non array layout");
+ return Err(LayoutError::Unknown);
};
(e_ty.clone(), count, true)
@@ -123,7 +166,7 @@ fn layout_of_simd_ty(
// Compute the ABI of the element type:
let e_ly = db.layout_of_ty(e_ty, env.clone())?;
let Abi::Scalar(e_abi) = e_ly.abi else {
- user_error!("simd type with inner non scalar type");
+ return Err(LayoutError::Unknown);
};
// Compute the size and alignment of the vector:
@@ -145,6 +188,8 @@ fn layout_of_simd_ty(
largest_niche: e_ly.largest_niche,
size,
align,
+ max_repr_align: None,
+ unadjusted_abi_align: align.abi,
}))
}
@@ -230,13 +275,11 @@ pub fn layout_of_ty_query(
.map(|k| db.layout_of_ty(k.assert_ty_ref(Interner).clone(), trait_env.clone()))
.collect::<Result<Vec<_>, _>>()?;
let fields = fields.iter().map(|it| &**it).collect::<Vec<_>>();
- let fields = fields.iter().collect::<Vec<_>>();
+ let fields = fields.iter().collect::<IndexVec<_, _>>();
cx.univariant(dl, &fields, &ReprOptions::default(), kind).ok_or(LayoutError::Unknown)?
}
TyKind::Array(element, count) => {
- let count = try_const_usize(db, &count).ok_or(LayoutError::UserError(Box::from(
- "unevaluated or mistyped const generic parameter",
- )))? as u64;
+ let count = try_const_usize(db, &count).ok_or(LayoutError::HasErrorConst)? as u64;
let element = db.layout_of_ty(element.clone(), trait_env.clone())?;
let size = element.size.checked_mul(count, dl).ok_or(LayoutError::SizeOverflow)?;
@@ -255,6 +298,8 @@ pub fn layout_of_ty_query(
largest_niche,
align: element.align,
size,
+ max_repr_align: None,
+ unadjusted_abi_align: element.align.abi,
}
}
TyKind::Slice(element) => {
@@ -266,11 +311,23 @@ pub fn layout_of_ty_query(
largest_niche: None,
align: element.align,
size: Size::ZERO,
+ max_repr_align: None,
+ unadjusted_abi_align: element.align.abi,
}
}
+ TyKind::Str => Layout {
+ variants: Variants::Single { index: struct_variant_idx() },
+ fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 },
+ abi: Abi::Aggregate { sized: false },
+ largest_niche: None,
+ align: dl.i8_align,
+ size: Size::ZERO,
+ max_repr_align: None,
+ unadjusted_abi_align: dl.i8_align.abi,
+ },
// Potentially-wide pointers.
TyKind::Ref(_, _, pointee) | TyKind::Raw(_, pointee) => {
- let mut data_ptr = scalar_unit(dl, Primitive::Pointer);
+ let mut data_ptr = scalar_unit(dl, Primitive::Pointer(AddressSpace::DATA));
if matches!(ty.kind(Interner), TyKind::Ref(..)) {
data_ptr.valid_range_mut().start = 1;
}
@@ -294,7 +351,7 @@ pub fn layout_of_ty_query(
scalar_unit(dl, Primitive::Int(dl.ptr_sized_integer(), false))
}
TyKind::Dyn(..) => {
- let mut vtable = scalar_unit(dl, Primitive::Pointer);
+ let mut vtable = scalar_unit(dl, Primitive::Pointer(AddressSpace::DATA));
vtable.valid_range_mut().start = 1;
vtable
}
@@ -308,32 +365,17 @@ pub fn layout_of_ty_query(
cx.scalar_pair(data_ptr, metadata)
}
TyKind::FnDef(_, _) => layout_of_unit(&cx, dl)?,
- TyKind::Str => Layout {
- variants: Variants::Single { index: struct_variant_idx() },
- fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 },
- abi: Abi::Aggregate { sized: false },
- largest_niche: None,
- align: dl.i8_align,
- size: Size::ZERO,
- },
- TyKind::Never => Layout {
- variants: Variants::Single { index: struct_variant_idx() },
- fields: FieldsShape::Primitive,
- abi: Abi::Uninhabited,
- largest_niche: None,
- align: dl.i8_align,
- size: Size::ZERO,
- },
+ TyKind::Never => cx.layout_of_never_type(),
TyKind::Dyn(_) | TyKind::Foreign(_) => {
let mut unit = layout_of_unit(&cx, dl)?;
match unit.abi {
Abi::Aggregate { ref mut sized } => *sized = false,
- _ => user_error!("bug"),
+ _ => return Err(LayoutError::Unknown),
}
unit
}
TyKind::Function(_) => {
- let mut ptr = scalar_unit(dl, Primitive::Pointer);
+ let mut ptr = scalar_unit(dl, Primitive::Pointer(dl.instruction_address_space));
ptr.valid_range_mut().start = 1;
Layout::scalar(dl, ptr)
}
@@ -363,7 +405,7 @@ pub fn layout_of_ty_query(
})
.collect::<Result<Vec<_>, _>>()?;
let fields = fields.iter().map(|it| &**it).collect::<Vec<_>>();
- let fields = fields.iter().collect::<Vec<_>>();
+ let fields = fields.iter().collect::<IndexVec<_, _>>();
cx.univariant(dl, &fields, &ReprOptions::default(), StructKind::AlwaysSized)
.ok_or(LayoutError::Unknown)?
}
@@ -390,17 +432,17 @@ pub fn layout_of_ty_query(
pub fn layout_of_ty_recover(
_: &dyn HirDatabase,
- _: &[String],
+ _: &Cycle,
_: &Ty,
_: &Arc<TraitEnvironment>,
) -> Result<Arc<Layout>, LayoutError> {
- user_error!("infinite sized recursive type");
+ Err(LayoutError::RecursiveTypeWithoutIndirection)
}
fn layout_of_unit(cx: &LayoutCx<'_>, dl: &TargetDataLayout) -> Result<Layout, LayoutError> {
- cx.univariant::<RustcEnumVariantIdx, &&Layout>(
+ cx.univariant::<RustcFieldIdx, RustcEnumVariantIdx, &&Layout>(
dl,
- &[],
+ IndexSlice::empty(),
&ReprOptions::default(),
StructKind::AlwaysSized,
)
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs
index 85ef649b8..39788a950 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs
@@ -2,12 +2,14 @@
use std::{cmp, ops::Bound};
+use base_db::salsa::Cycle;
use hir_def::{
data::adt::VariantData,
layout::{Integer, LayoutCalculator, ReprOptions, TargetDataLayout},
AdtId, EnumVariantId, LocalEnumVariantId, VariantId,
};
use la_arena::RawIdx;
+use rustc_dependencies::index::IndexVec;
use smallvec::SmallVec;
use triomphe::Arc;
@@ -20,8 +22,8 @@ use crate::{
use super::LayoutCx;
-pub(crate) fn struct_variant_idx() -> RustcEnumVariantIdx {
- RustcEnumVariantIdx(LocalEnumVariantId::from_raw(RawIdx::from(0)))
+pub(crate) const fn struct_variant_idx() -> RustcEnumVariantIdx {
+ RustcEnumVariantIdx(LocalEnumVariantId::from_raw(RawIdx::from_u32(0)))
}
pub fn layout_of_adt_query(
@@ -74,7 +76,7 @@ pub fn layout_of_adt_query(
.iter()
.map(|it| it.iter().map(|it| &**it).collect::<Vec<_>>())
.collect::<SmallVec<[_; 1]>>();
- let variants = variants.iter().map(|it| it.iter().collect()).collect();
+ let variants = variants.iter().map(|it| it.iter().collect()).collect::<IndexVec<_, _>>();
let result = if matches!(def, AdtId::UnionId(..)) {
cx.layout_of_union(&repr, &variants).ok_or(LayoutError::Unknown)?
} else {
@@ -105,7 +107,7 @@ pub fn layout_of_adt_query(
&& variants
.iter()
.next()
- .and_then(|it| it.last().map(|it| !it.is_unsized()))
+ .and_then(|it| it.iter().last().map(|it| !it.is_unsized()))
.unwrap_or(true),
)
.ok_or(LayoutError::SizeOverflow)?
@@ -119,7 +121,15 @@ fn layout_scalar_valid_range(db: &dyn HirDatabase, def: AdtId) -> (Bound<u128>,
let attr = attrs.by_key(name).tt_values();
for tree in attr {
if let Some(it) = tree.token_trees.first() {
- if let Ok(it) = it.to_string().parse() {
+ let text = it.to_string().replace('_', "");
+ let (text, base) = match text.as_bytes() {
+ [b'0', b'x', ..] => (&text[2..], 16),
+ [b'0', b'o', ..] => (&text[2..], 8),
+ [b'0', b'b', ..] => (&text[2..], 2),
+ _ => (&*text, 10),
+ };
+
+ if let Ok(it) = u128::from_str_radix(text, base) {
return Bound::Included(it);
}
}
@@ -131,12 +141,12 @@ fn layout_scalar_valid_range(db: &dyn HirDatabase, def: AdtId) -> (Bound<u128>,
pub fn layout_of_adt_recover(
_: &dyn HirDatabase,
- _: &[String],
+ _: &Cycle,
_: &AdtId,
_: &Substitution,
_: &Arc<TraitEnvironment>,
) -> Result<Arc<Layout>, LayoutError> {
- user_error!("infinite sized recursive type");
+ Err(LayoutError::RecursiveTypeWithoutIndirection)
}
/// Finds the appropriate Integer type and signedness for the given
@@ -160,11 +170,7 @@ fn repr_discr(
let discr = Integer::from_attr(dl, ity);
let fit = if ity.is_signed() { signed_fit } else { unsigned_fit };
if discr < fit {
- return Err(LayoutError::UserError(
- "Integer::repr_discr: `#[repr]` hint too small for \
- discriminant range of enum "
- .into(),
- ));
+ return Err(LayoutError::UserReprTooSmall);
}
return Ok((discr, ity.is_signed()));
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs
index ffdbb9de9..5e3a86c80 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs
@@ -210,16 +210,13 @@ fn recursive() {
struct BoxLike<T: ?Sized>(*mut T);
struct Goal(BoxLike<Goal>);
}
- check_fail(
- r#"struct Goal(Goal);"#,
- LayoutError::UserError("infinite sized recursive type".into()),
- );
+ check_fail(r#"struct Goal(Goal);"#, LayoutError::RecursiveTypeWithoutIndirection);
check_fail(
r#"
struct Foo<T>(Foo<T>);
struct Goal(Foo<i32>);
"#,
- LayoutError::UserError("infinite sized recursive type".into()),
+ LayoutError::RecursiveTypeWithoutIndirection,
);
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests/closure.rs
index bbe855a14..939025461 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests/closure.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests/closure.rs
@@ -186,9 +186,9 @@ fn capture_specific_fields() {
fn match_pattern() {
size_and_align_expr! {
struct X(i64, i32, (u8, i128));
- let y: X = X(2, 5, (7, 3));
+ let _y: X = X(2, 5, (7, 3));
move |x: i64| {
- match y {
+ match _y {
_ => x,
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
index 405bb001b..cf174feed 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
@@ -1,6 +1,7 @@
//! The type system. We currently use this to infer types for completion, hover
//! information and various assists.
-#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
+#![warn(rust_2018_idioms, unused_lifetimes)]
+#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
#[allow(unused)]
macro_rules! eprintln {
@@ -72,14 +73,15 @@ pub use infer::{
};
pub use interner::Interner;
pub use lower::{
- associated_type_shorthand_candidates, CallableDefId, ImplTraitLoweringMode, TyDefId,
- TyLoweringContext, ValueTyDefId,
+ associated_type_shorthand_candidates, CallableDefId, ImplTraitLoweringMode, ParamLoweringMode,
+ TyDefId, TyLoweringContext, ValueTyDefId,
};
pub use mapping::{
from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx,
lt_from_placeholder_idx, to_assoc_type_id, to_chalk_trait_id, to_foreign_def_id,
to_placeholder_idx,
};
+pub use method_resolution::check_orphan_rules;
pub use traits::TraitEnvironment;
pub use utils::{all_super_traits, is_fn_unsafe_to_call};
@@ -120,7 +122,7 @@ pub type TyKind = chalk_ir::TyKind<Interner>;
pub type TypeFlags = chalk_ir::TypeFlags;
pub type DynTy = chalk_ir::DynTy<Interner>;
pub type FnPointer = chalk_ir::FnPointer<Interner>;
-// pub type FnSubst = chalk_ir::FnSubst<Interner>;
+// pub type FnSubst = chalk_ir::FnSubst<Interner>; // a re-export so we don't lose the tuple constructor
pub use chalk_ir::FnSubst;
pub type ProjectionTy = chalk_ir::ProjectionTy<Interner>;
pub type AliasTy = chalk_ir::AliasTy<Interner>;
@@ -320,8 +322,7 @@ impl CallableSig {
pub fn from_fn_ptr(fn_ptr: &FnPointer) -> CallableSig {
CallableSig {
// FIXME: what to do about lifetime params? -> return PolyFnSig
- // FIXME: use `Arc::from_iter` when it becomes available
- params_and_return: Arc::from(
+ params_and_return: Arc::from_iter(
fn_ptr
.substitution
.clone()
@@ -330,8 +331,7 @@ impl CallableSig {
.0
.as_slice(Interner)
.iter()
- .map(|arg| arg.assert_ty_ref(Interner).clone())
- .collect::<Vec<_>>(),
+ .map(|arg| arg.assert_ty_ref(Interner).clone()),
),
is_varargs: fn_ptr.sig.variadic,
safety: fn_ptr.sig.safety,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
index 9a61f1535..97c4a741f 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -10,7 +10,7 @@ use std::{
iter,
};
-use base_db::CrateId;
+use base_db::{salsa::Cycle, CrateId};
use chalk_ir::{
cast::Cast, fold::Shift, fold::TypeFoldable, interner::HasInterner, Mutability, Safety,
};
@@ -113,7 +113,9 @@ pub struct TyLoweringContext<'a> {
pub db: &'a dyn HirDatabase,
resolver: &'a Resolver,
in_binders: DebruijnIndex,
- owner: TypeOwnerId,
+ // FIXME: Should not be an `Option` but `Resolver` currently does not return owners in all cases
+ // where expected
+ owner: Option<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
@@ -127,6 +129,14 @@ pub struct TyLoweringContext<'a> {
impl<'a> TyLoweringContext<'a> {
pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver, owner: TypeOwnerId) -> Self {
+ Self::new_maybe_unowned(db, resolver, Some(owner))
+ }
+
+ pub fn new_maybe_unowned(
+ db: &'a dyn HirDatabase,
+ resolver: &'a Resolver,
+ owner: Option<TypeOwnerId>,
+ ) -> Self {
let impl_trait_mode = ImplTraitLoweringState::Disallowed;
let type_param_mode = ParamLoweringMode::Placeholder;
let in_binders = DebruijnIndex::INNERMOST;
@@ -213,10 +223,11 @@ impl<'a> TyLoweringContext<'a> {
}
pub fn lower_const(&self, const_ref: &ConstRef, const_type: Ty) -> Const {
+ let Some(owner) = self.owner else { return unknown_const(const_type) };
const_or_path_to_chalk(
self.db,
self.resolver,
- self.owner,
+ owner,
const_type,
const_ref,
self.type_param_mode,
@@ -407,11 +418,7 @@ impl<'a> TyLoweringContext<'a> {
drop(expander);
let ty = self.lower_ty(&type_ref);
- self.expander
- .borrow_mut()
- .as_mut()
- .unwrap()
- .exit(self.db.upcast(), mark);
+ self.expander.borrow_mut().as_mut().unwrap().exit(mark);
Some(ty)
}
_ => {
@@ -768,7 +775,7 @@ impl<'a> TyLoweringContext<'a> {
}
}
- fn substs_from_path_segment(
+ pub(super) fn substs_from_path_segment(
&self,
segment: PathSegment<'_>,
def: Option<GenericDefId>,
@@ -1097,10 +1104,25 @@ impl<'a> TyLoweringContext<'a> {
binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
);
if let Some(type_ref) = &binding.type_ref {
- let ty = self.lower_ty(type_ref);
- let alias_eq =
- AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty };
- predicates.push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq)));
+ if let (TypeRef::ImplTrait(bounds), ImplTraitLoweringState::Disallowed) =
+ (type_ref, &self.impl_trait_mode)
+ {
+ for bound in bounds {
+ predicates.extend(
+ self.lower_type_bound(
+ bound,
+ TyKind::Alias(AliasTy::Projection(projection_ty.clone()))
+ .intern(Interner),
+ false,
+ ),
+ );
+ }
+ } else {
+ let ty = self.lower_ty(type_ref);
+ let alias_eq =
+ AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty };
+ predicates.push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq)));
+ }
}
for bound in binding.bounds.iter() {
predicates.extend(self.lower_type_bound(
@@ -1383,51 +1405,50 @@ pub(crate) fn generic_predicates_for_param_query(
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()
- // we have to filter out all other predicates *first*, before attempting to lower them
- .filter(|pred| match pred {
- WherePredicate::ForLifetime { target, bound, .. }
- | WherePredicate::TypeBound { target, bound, .. } => {
- match target {
- WherePredicateTypeTarget::TypeRef(type_ref) => {
- if ctx.lower_ty_only_param(type_ref) != Some(param_id) {
- return false;
- }
- }
- &WherePredicateTypeTarget::TypeOrConstParam(local_id) => {
- let target_id = TypeOrConstParamId { parent: def, local_id };
- if target_id != param_id {
- return false;
- }
- }
- };
- match &**bound {
- TypeBound::ForLifetime(_, path) | TypeBound::Path(path, _) => {
- // Only lower the bound if the trait could possibly define the associated
- // type we're looking for.
+ // we have to filter out all other predicates *first*, before attempting to lower them
+ let predicate = |pred: &&_| match pred {
+ WherePredicate::ForLifetime { target, bound, .. }
+ | WherePredicate::TypeBound { target, bound, .. } => {
+ let invalid_target = match target {
+ WherePredicateTypeTarget::TypeRef(type_ref) => {
+ ctx.lower_ty_only_param(type_ref) != Some(param_id)
+ }
+ &WherePredicateTypeTarget::TypeOrConstParam(local_id) => {
+ let target_id = TypeOrConstParamId { parent: def, local_id };
+ target_id != param_id
+ }
+ };
+ if invalid_target {
+ return false;
+ }
+
+ match &**bound {
+ TypeBound::ForLifetime(_, path) | TypeBound::Path(path, _) => {
+ // Only lower the bound if the trait could possibly define the associated
+ // type we're looking for.
- let assoc_name = match &assoc_name {
- Some(it) => it,
- None => return true,
- };
- let tr = match resolver.resolve_path_in_type_ns_fully(db.upcast(), path) {
- Some(TypeNs::TraitId(tr)) => tr,
- _ => return false,
- };
+ let Some(assoc_name) = &assoc_name else { return true };
+ let Some(TypeNs::TraitId(tr)) =
+ resolver.resolve_path_in_type_ns_fully(db.upcast(), path)
+ else {
+ return false;
+ };
- all_super_traits(db.upcast(), tr).iter().any(|tr| {
- db.trait_data(*tr).items.iter().any(|(name, item)| {
- matches!(item, AssocItemId::TypeAliasId(_)) && name == assoc_name
- })
+ all_super_traits(db.upcast(), tr).iter().any(|tr| {
+ db.trait_data(*tr).items.iter().any(|(name, item)| {
+ matches!(item, AssocItemId::TypeAliasId(_)) && name == assoc_name
})
- }
- TypeBound::Lifetime(_) | TypeBound::Error => false,
+ })
}
+ TypeBound::Lifetime(_) | TypeBound::Error => false,
}
- WherePredicate::Lifetime { .. } => false,
- })
+ }
+ WherePredicate::Lifetime { .. } => false,
+ };
+ let mut predicates: Vec<_> = resolver
+ .where_predicates_in_scope()
+ .filter(predicate)
.flat_map(|pred| {
ctx.lower_where_predicate(pred, true).map(|p| make_binders(db, &generics, p))
})
@@ -1444,13 +1465,12 @@ pub(crate) fn generic_predicates_for_param_query(
pub(crate) fn generic_predicates_for_param_recover(
_db: &dyn HirDatabase,
- _cycle: &[String],
+ _cycle: &Cycle,
_def: &GenericDefId,
_param_id: &TypeOrConstParamId,
_assoc_name: &Option<Name>,
) -> Arc<[Binders<QuantifiedWhereClause>]> {
- // FIXME: use `Arc::from_iter` when it becomes available
- Arc::from(vec![])
+ Arc::from_iter(None)
}
pub(crate) fn trait_environment_for_body_query(
@@ -1459,7 +1479,7 @@ pub(crate) fn trait_environment_for_body_query(
) -> Arc<TraitEnvironment> {
let Some(def) = def.as_generic_def_id() else {
let krate = def.module(db.upcast()).krate();
- return Arc::new(TraitEnvironment::empty(krate));
+ return TraitEnvironment::empty(krate);
};
db.trait_environment(def)
}
@@ -1519,7 +1539,7 @@ pub(crate) fn trait_environment_query(
let env = chalk_ir::Environment::new(Interner).add_clauses(Interner, clauses);
- Arc::new(TraitEnvironment { krate, block: None, traits_from_clauses: traits_in_scope, env })
+ TraitEnvironment::new(krate, None, traits_in_scope.into_boxed_slice(), env)
}
/// Resolve the where clause(s) of an item with generics.
@@ -1588,69 +1608,54 @@ pub(crate) fn generic_defaults_query(
let generic_params = generics(db.upcast(), def);
let parent_start_idx = generic_params.len_self();
- let defaults = Arc::from(
- generic_params
- .iter()
- .enumerate()
- .map(|(idx, (id, p))| {
- match p {
- TypeOrConstParamData::TypeParamData(p) => {
- let mut ty = p
- .default
- .as_ref()
- .map_or(TyKind::Error.intern(Interner), |t| ctx.lower_ty(t));
- // Each default can only refer to previous parameters.
- // Type variable default referring to parameter coming
- // after it is forbidden (FIXME: report diagnostic)
- ty = fallback_bound_vars(ty, idx, parent_start_idx);
- crate::make_binders(db, &generic_params, ty.cast(Interner))
- }
- TypeOrConstParamData::ConstParamData(p) => {
- let mut val = p.default.as_ref().map_or_else(
- || {
- unknown_const_as_generic(
- db.const_param_ty(ConstParamId::from_unchecked(id)),
- )
- },
- |c| {
- let c = ctx.lower_const(c, ctx.lower_ty(&p.ty));
- c.cast(Interner)
- },
- );
- // Each default can only refer to previous parameters, see above.
- val = fallback_bound_vars(val, idx, parent_start_idx);
- make_binders(db, &generic_params, val)
- }
- }
- })
- // FIXME: use `Arc::from_iter` when it becomes available
- .collect::<Vec<_>>(),
- );
+ let defaults = Arc::from_iter(generic_params.iter().enumerate().map(|(idx, (id, p))| {
+ match p {
+ TypeOrConstParamData::TypeParamData(p) => {
+ let mut ty =
+ p.default.as_ref().map_or(TyKind::Error.intern(Interner), |t| ctx.lower_ty(t));
+ // Each default can only refer to previous parameters.
+ // Type variable default referring to parameter coming
+ // after it is forbidden (FIXME: report diagnostic)
+ ty = fallback_bound_vars(ty, idx, parent_start_idx);
+ crate::make_binders(db, &generic_params, ty.cast(Interner))
+ }
+ TypeOrConstParamData::ConstParamData(p) => {
+ let mut val = p.default.as_ref().map_or_else(
+ || {
+ unknown_const_as_generic(
+ db.const_param_ty(ConstParamId::from_unchecked(id)),
+ )
+ },
+ |c| {
+ let c = ctx.lower_const(c, ctx.lower_ty(&p.ty));
+ c.cast(Interner)
+ },
+ );
+ // Each default can only refer to previous parameters, see above.
+ val = fallback_bound_vars(val, idx, parent_start_idx);
+ make_binders(db, &generic_params, val)
+ }
+ }
+ }));
defaults
}
pub(crate) fn generic_defaults_recover(
db: &dyn HirDatabase,
- _cycle: &[String],
+ _cycle: &Cycle,
def: &GenericDefId,
) -> Arc<[Binders<crate::GenericArg>]> {
let generic_params = generics(db.upcast(), *def);
// FIXME: this code is not covered in tests.
// we still need one default per parameter
- let defaults = Arc::from(
- generic_params
- .iter_id()
- .map(|id| {
- let val = match id {
- Either::Left(_) => TyKind::Error.intern(Interner).cast(Interner),
- Either::Right(id) => unknown_const_as_generic(db.const_param_ty(id)),
- };
- crate::make_binders(db, &generic_params, val)
- })
- // FIXME: use `Arc::from_iter` when it becomes available
- .collect::<Vec<_>>(),
- );
+ let defaults = Arc::from_iter(generic_params.iter_id().map(|id| {
+ let val = match id {
+ Either::Left(_) => TyKind::Error.intern(Interner).cast(Interner),
+ Either::Right(id) => unknown_const_as_generic(db.const_param_ty(id)),
+ };
+ crate::make_binders(db, &generic_params, val)
+ }));
defaults
}
@@ -1774,10 +1779,11 @@ fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> {
let resolver = t.resolver(db.upcast());
let ctx = TyLoweringContext::new(db, &resolver, t.into())
.with_type_param_mode(ParamLoweringMode::Variable);
- if db.type_alias_data(t).is_extern {
+ let type_alias_data = db.type_alias_data(t);
+ if type_alias_data.is_extern {
Binders::empty(Interner, TyKind::Foreign(crate::to_foreign_def_id(t)).intern(Interner))
} else {
- let type_ref = &db.type_alias_data(t).type_ref;
+ let type_ref = &type_alias_data.type_ref;
let inner = ctx.lower_ty(type_ref.as_deref().unwrap_or(&TypeRef::Error));
make_binders(db, &generics, inner)
}
@@ -1866,7 +1872,7 @@ pub(crate) fn ty_query(db: &dyn HirDatabase, def: TyDefId) -> Binders<Ty> {
}
}
-pub(crate) fn ty_recover(db: &dyn HirDatabase, _cycle: &[String], def: &TyDefId) -> Binders<Ty> {
+pub(crate) fn ty_recover(db: &dyn HirDatabase, _cycle: &Cycle, def: &TyDefId) -> Binders<Ty> {
let generics = match *def {
TyDefId::BuiltinType(_) => return Binders::empty(Interner, TyKind::Error.intern(Interner)),
TyDefId::AdtId(it) => generics(db.upcast(), it.into()),
@@ -1916,7 +1922,7 @@ pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> T
pub(crate) fn impl_self_ty_recover(
db: &dyn HirDatabase,
- _cycle: &[String],
+ _cycle: &Cycle,
impl_id: &ImplId,
) -> Binders<Ty> {
let generics = generics(db.upcast(), (*impl_id).into());
@@ -2048,7 +2054,7 @@ pub(crate) fn const_or_path_to_chalk(
.intern_in_type_const(InTypeConstLoc {
id: it,
owner,
- thing: Box::new(InTypeConstIdMetadata(expected_ty.clone())),
+ expected_ty: Box::new(InTypeConstIdMetadata(expected_ty.clone())),
})
.into();
intern_const_scalar(
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
index f3a5f69b2..041d61c1b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
@@ -27,8 +27,9 @@ use crate::{
primitive::{FloatTy, IntTy, UintTy},
static_lifetime, to_chalk_trait_id,
utils::all_super_traits,
- AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, InEnvironment,
- Interner, Scalar, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt,
+ AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, Goal, Guidance,
+ InEnvironment, Interner, Scalar, Solution, Substitution, TraitEnvironment, TraitRef,
+ TraitRefExt, Ty, TyBuilder, TyExt,
};
/// This is used as a key for indexing impls.
@@ -167,12 +168,9 @@ impl TraitImpls {
) -> Arc<[Arc<Self>]> {
let _p = profile::span("trait_impls_in_deps_query").detail(|| format!("{krate:?}"));
let crate_graph = db.crate_graph();
- // FIXME: use `Arc::from_iter` when it becomes available
- Arc::from(
- crate_graph
- .transitive_deps(krate)
- .map(|krate| db.trait_impls_in_crate(krate))
- .collect::<Vec<_>>(),
+
+ Arc::from_iter(
+ crate_graph.transitive_deps(krate).map(|krate| db.trait_impls_in_crate(krate)),
)
}
@@ -862,6 +860,62 @@ fn is_inherent_impl_coherent(
}
}
+/// Checks whether the impl satisfies the orphan rules.
+///
+/// Given `impl<P1..=Pn> Trait<T1..=Tn> for T0`, an `impl`` is valid only if at least one of the following is true:
+/// - Trait is a local trait
+/// - All of
+/// - At least one of the types `T0..=Tn`` must be a local type. Let `Ti`` be the first such type.
+/// - No uncovered type parameters `P1..=Pn` may appear in `T0..Ti`` (excluding `Ti`)
+pub fn check_orphan_rules(db: &dyn HirDatabase, impl_: ImplId) -> bool {
+ let substs = TyBuilder::placeholder_subst(db, impl_);
+ let Some(impl_trait) = db.impl_trait(impl_) else {
+ // not a trait impl
+ return true;
+ };
+
+ let local_crate = impl_.lookup(db.upcast()).container.krate();
+ let is_local = |tgt_crate| tgt_crate == local_crate;
+
+ let trait_ref = impl_trait.substitute(Interner, &substs);
+ let trait_id = from_chalk_trait_id(trait_ref.trait_id);
+ if is_local(trait_id.module(db.upcast()).krate()) {
+ // trait to be implemented is local
+ return true;
+ }
+
+ let unwrap_fundamental = |ty: Ty| match ty.kind(Interner) {
+ TyKind::Ref(_, _, referenced) => referenced.clone(),
+ &TyKind::Adt(AdtId(hir_def::AdtId::StructId(s)), ref subs) => {
+ let struct_data = db.struct_data(s);
+ if struct_data.flags.contains(StructFlags::IS_FUNDAMENTAL) {
+ let next = subs.type_parameters(Interner).next();
+ match next {
+ Some(ty) => ty,
+ None => ty,
+ }
+ } else {
+ ty
+ }
+ }
+ _ => ty,
+ };
+ // - At least one of the types `T0..=Tn`` must be a local type. Let `Ti`` be the first such type.
+ let is_not_orphan = trait_ref.substitution.type_parameters(Interner).any(|ty| {
+ match unwrap_fundamental(ty).kind(Interner) {
+ &TyKind::Adt(AdtId(id), _) => is_local(id.module(db.upcast()).krate()),
+ TyKind::Error => true,
+ TyKind::Dyn(it) => it.principal().map_or(false, |trait_ref| {
+ is_local(from_chalk_trait_id(trait_ref.trait_id).module(db.upcast()).krate())
+ }),
+ _ => false,
+ }
+ });
+ // FIXME: param coverage
+ // - No uncovered type parameters `P1..=Pn` may appear in `T0..Ti`` (excluding `Ti`)
+ is_not_orphan
+}
+
pub fn iterate_path_candidates(
ty: &Canonical<Ty>,
db: &dyn HirDatabase,
@@ -1422,26 +1476,52 @@ fn is_valid_fn_candidate(
// We need to consider the bounds on the impl to distinguish functions of the same name
// for a type.
let predicates = db.generic_predicates(impl_id.into());
- let valid = predicates
- .iter()
- .map(|predicate| {
- let (p, b) = predicate
- .clone()
- .substitute(Interner, &impl_subst)
- // Skipping the inner binders is ok, as we don't handle quantified where
- // clauses yet.
- .into_value_and_skipped_binders();
- stdx::always!(b.len(Interner) == 0);
- p
- })
- // It's ok to get ambiguity here, as we may not have enough information to prove
- // obligations. We'll check if the user is calling the selected method properly
- // later anyway.
- .all(|p| table.try_obligation(p.cast(Interner)).is_some());
- match valid {
- true => IsValidCandidate::Yes,
- false => IsValidCandidate::No,
+ let goals = predicates.iter().map(|p| {
+ let (p, b) = p
+ .clone()
+ .substitute(Interner, &impl_subst)
+ // Skipping the inner binders is ok, as we don't handle quantified where
+ // clauses yet.
+ .into_value_and_skipped_binders();
+ stdx::always!(b.len(Interner) == 0);
+
+ p.cast::<Goal>(Interner)
+ });
+
+ for goal in goals.clone() {
+ let in_env = InEnvironment::new(&table.trait_env.env, goal);
+ let canonicalized = table.canonicalize(in_env);
+ let solution = table.db.trait_solve(
+ table.trait_env.krate,
+ table.trait_env.block,
+ canonicalized.value.clone(),
+ );
+
+ match solution {
+ Some(Solution::Unique(canonical_subst)) => {
+ canonicalized.apply_solution(
+ table,
+ Canonical {
+ binders: canonical_subst.binders,
+ value: canonical_subst.value.subst,
+ },
+ );
+ }
+ Some(Solution::Ambig(Guidance::Definite(substs))) => {
+ canonicalized.apply_solution(table, substs);
+ }
+ Some(_) => (),
+ None => return IsValidCandidate::No,
+ }
}
+
+ for goal in goals {
+ if table.try_obligation(goal).is_none() {
+ return IsValidCandidate::No;
+ }
+ }
+
+ IsValidCandidate::Yes
} else {
// For `ItemContainerId::TraitId`, we check if `self_ty` implements the trait in
// `iterate_trait_method_candidates()`.
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
index e953058cc..f1795e71d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
@@ -40,7 +40,6 @@ pub use monomorphization::{
use rustc_hash::FxHashMap;
use smallvec::{smallvec, SmallVec};
use stdx::{impl_from, never};
-use triomphe::Arc;
use super::consteval::{intern_const_scalar, try_const_usize};
@@ -147,7 +146,7 @@ impl<V, T> ProjectionElem<V, T> {
base = normalize(
db,
// FIXME: we should get this from caller
- Arc::new(TraitEnvironment::empty(krate)),
+ TraitEnvironment::empty(krate),
base,
);
}
@@ -243,16 +242,16 @@ impl Default for ProjectionStore {
}
impl ProjectionStore {
- fn shrink_to_fit(&mut self) {
+ pub fn shrink_to_fit(&mut self) {
self.id_to_proj.shrink_to_fit();
self.proj_to_id.shrink_to_fit();
}
- fn intern_if_exist(&self, projection: &[PlaceElem]) -> Option<ProjectionId> {
+ pub fn intern_if_exist(&self, projection: &[PlaceElem]) -> Option<ProjectionId> {
self.proj_to_id.get(projection).copied()
}
- fn intern(&mut self, projection: Box<[PlaceElem]>) -> ProjectionId {
+ pub fn intern(&mut self, projection: Box<[PlaceElem]>) -> ProjectionId {
let new_id = ProjectionId(self.proj_to_id.len() as u32);
match self.proj_to_id.entry(projection) {
Entry::Occupied(id) => *id.get(),
@@ -267,20 +266,24 @@ impl ProjectionStore {
}
impl ProjectionId {
- const EMPTY: ProjectionId = ProjectionId(0);
+ pub const EMPTY: ProjectionId = ProjectionId(0);
+
+ pub fn is_empty(self) -> bool {
+ self == ProjectionId::EMPTY
+ }
- fn lookup(self, store: &ProjectionStore) -> &[PlaceElem] {
+ pub fn lookup(self, store: &ProjectionStore) -> &[PlaceElem] {
store.id_to_proj.get(&self).unwrap()
}
- fn project(self, projection: PlaceElem, store: &mut ProjectionStore) -> ProjectionId {
+ pub fn project(self, projection: PlaceElem, store: &mut ProjectionStore) -> ProjectionId {
let mut current = self.lookup(store).to_vec();
current.push(projection);
store.intern(current.into())
}
}
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Place {
pub local: LocalId,
pub projection: ProjectionId,
@@ -1007,7 +1010,7 @@ pub enum Rvalue {
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum StatementKind {
Assign(Place, Rvalue),
- //FakeRead(Box<(FakeReadCause, Place)>),
+ FakeRead(Place),
//SetDiscriminant {
// place: Box<Place>,
// variant_index: VariantIdx,
@@ -1069,6 +1072,10 @@ pub struct MirBody {
}
impl MirBody {
+ pub fn local_to_binding_map(&self) -> ArenaMap<LocalId, BindingId> {
+ self.binding_locals.iter().map(|(it, y)| (*y, it)).collect()
+ }
+
fn walk_places(&mut self, mut f: impl FnMut(&mut Place, &mut ProjectionStore)) {
fn for_operand(
op: &mut Operand,
@@ -1109,7 +1116,9 @@ impl MirBody {
}
}
}
- StatementKind::Deinit(p) => f(p, &mut self.projection_store),
+ StatementKind::FakeRead(p) | StatementKind::Deinit(p) => {
+ f(p, &mut self.projection_store)
+ }
StatementKind::StorageLive(_)
| StatementKind::StorageDead(_)
| StatementKind::Nop => (),
@@ -1186,3 +1195,9 @@ pub enum MirSpan {
}
impl_from!(ExprId, PatId for MirSpan);
+
+impl From<&ExprId> for MirSpan {
+ fn from(value: &ExprId) -> Self {
+ (*value).into()
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs
index 41fb12965..74c5efd6c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs
@@ -24,6 +24,7 @@ use super::{
pub enum MutabilityReason {
Mut { spans: Vec<MirSpan> },
Not,
+ Unused,
}
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -144,7 +145,8 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef>
}
}
},
- StatementKind::Deinit(_)
+ StatementKind::FakeRead(_)
+ | StatementKind::Deinit(_)
| StatementKind::StorageLive(_)
| StatementKind::StorageDead(_)
| StatementKind::Nop => (),
@@ -264,7 +266,10 @@ fn ever_initialized_map(
is_ever_initialized = false;
}
}
- StatementKind::Deinit(_) | StatementKind::Nop | StatementKind::StorageLive(_) => (),
+ StatementKind::Deinit(_)
+ | StatementKind::FakeRead(_)
+ | StatementKind::Nop
+ | StatementKind::StorageLive(_) => (),
}
}
let Some(terminator) = &block.terminator else {
@@ -331,16 +336,37 @@ fn ever_initialized_map(
result
}
+fn push_mut_span(local: LocalId, span: MirSpan, result: &mut ArenaMap<LocalId, MutabilityReason>) {
+ match &mut result[local] {
+ MutabilityReason::Mut { spans } => spans.push(span),
+ it @ (MutabilityReason::Not | MutabilityReason::Unused) => {
+ *it = MutabilityReason::Mut { spans: vec![span] }
+ }
+ };
+}
+
+fn record_usage(local: LocalId, result: &mut ArenaMap<LocalId, MutabilityReason>) {
+ match &mut result[local] {
+ it @ MutabilityReason::Unused => {
+ *it = MutabilityReason::Not;
+ }
+ _ => (),
+ };
+}
+
+fn record_usage_for_operand(arg: &Operand, result: &mut ArenaMap<LocalId, MutabilityReason>) {
+ if let Operand::Copy(p) | Operand::Move(p) = arg {
+ record_usage(p.local, result);
+ }
+}
+
fn mutability_of_locals(
db: &dyn HirDatabase,
body: &MirBody,
) -> ArenaMap<LocalId, MutabilityReason> {
let mut result: ArenaMap<LocalId, MutabilityReason> =
- body.locals.iter().map(|it| (it.0, MutabilityReason::Not)).collect();
- let mut push_mut_span = |local, span| match &mut result[local] {
- MutabilityReason::Mut { spans } => spans.push(span),
- it @ MutabilityReason::Not => *it = MutabilityReason::Mut { spans: vec![span] },
- };
+ body.locals.iter().map(|it| (it.0, MutabilityReason::Unused)).collect();
+
let ever_init_maps = ever_initialized_map(db, body);
for (block_id, mut ever_init_map) in ever_init_maps.into_iter() {
let block = &body.basic_blocks[block_id];
@@ -350,23 +376,51 @@ fn mutability_of_locals(
match place_case(db, body, place) {
ProjectionCase::Direct => {
if ever_init_map.get(place.local).copied().unwrap_or_default() {
- push_mut_span(place.local, statement.span);
+ push_mut_span(place.local, statement.span, &mut result);
} else {
ever_init_map.insert(place.local, true);
}
}
ProjectionCase::DirectPart => {
// Partial initialization is not supported, so it is definitely `mut`
- push_mut_span(place.local, statement.span);
+ push_mut_span(place.local, statement.span, &mut result);
+ }
+ ProjectionCase::Indirect => {
+ record_usage(place.local, &mut result);
}
- ProjectionCase::Indirect => (),
+ }
+ match value {
+ Rvalue::CopyForDeref(p)
+ | Rvalue::Discriminant(p)
+ | Rvalue::Len(p)
+ | Rvalue::Ref(_, p) => {
+ record_usage(p.local, &mut result);
+ }
+ Rvalue::Use(o)
+ | Rvalue::Repeat(o, _)
+ | Rvalue::Cast(_, o, _)
+ | Rvalue::UnaryOp(_, o) => record_usage_for_operand(o, &mut result),
+ Rvalue::CheckedBinaryOp(_, o1, o2) => {
+ for o in [o1, o2] {
+ record_usage_for_operand(o, &mut result);
+ }
+ }
+ Rvalue::Aggregate(_, args) => {
+ for arg in args.iter() {
+ record_usage_for_operand(arg, &mut result);
+ }
+ }
+ Rvalue::ShallowInitBox(_, _) | Rvalue::ShallowInitBoxWithAlloc(_) => (),
}
if let Rvalue::Ref(BorrowKind::Mut { .. }, p) = value {
if place_case(db, body, p) != ProjectionCase::Indirect {
- push_mut_span(p.local, statement.span);
+ push_mut_span(p.local, statement.span, &mut result);
}
}
}
+ StatementKind::FakeRead(p) => {
+ record_usage(p.local, &mut result);
+ }
StatementKind::StorageDead(p) => {
ever_init_map.insert(*p, false);
}
@@ -386,15 +440,21 @@ fn mutability_of_locals(
| TerminatorKind::FalseEdge { .. }
| TerminatorKind::FalseUnwind { .. }
| TerminatorKind::GeneratorDrop
- | TerminatorKind::SwitchInt { .. }
| TerminatorKind::Drop { .. }
| TerminatorKind::DropAndReplace { .. }
| TerminatorKind::Assert { .. }
| TerminatorKind::Yield { .. } => (),
- TerminatorKind::Call { destination, .. } => {
+ TerminatorKind::SwitchInt { discr, targets: _ } => {
+ record_usage_for_operand(discr, &mut result);
+ }
+ TerminatorKind::Call { destination, args, func, .. } => {
+ record_usage_for_operand(func, &mut result);
+ for arg in args.iter() {
+ record_usage_for_operand(arg, &mut result);
+ }
if destination.projection.lookup(&body.projection_store).len() == 0 {
if ever_init_map.get(destination.local).copied().unwrap_or_default() {
- push_mut_span(destination.local, MirSpan::Unknown);
+ push_mut_span(destination.local, MirSpan::Unknown, &mut result);
} else {
ever_init_map.insert(destination.local, true);
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
index 4364e0d32..fbfb6ff8c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
@@ -21,7 +21,7 @@ use hir_def::{
AdtId, ConstId, DefWithBodyId, EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup,
StaticId, VariantId,
};
-use hir_expand::{mod_path::ModPath, InFile};
+use hir_expand::{mod_path::ModPath, HirFileIdExt, InFile};
use intern::Interned;
use la_arena::ArenaMap;
use rustc_hash::{FxHashMap, FxHashSet};
@@ -162,7 +162,7 @@ pub struct Evaluator<'a> {
not_special_fn_cache: RefCell<FxHashSet<FunctionId>>,
mir_or_dyn_index_cache: RefCell<FxHashMap<(FunctionId, Substitution), MirOrDynIndex>>,
/// Constantly dropping and creating `Locals` is very costly. We store
- /// old locals that we normaly want to drop here, to reuse their allocations
+ /// old locals that we normally want to drop here, to reuse their allocations
/// later.
unused_locals_store: RefCell<FxHashMap<DefWithBodyId, Vec<Locals>>>,
cached_ptr_size: usize,
@@ -375,10 +375,7 @@ impl MirEvalError {
Err(_) => continue,
},
MirSpan::PatId(p) => match source_map.pat_syntax(*p) {
- Ok(s) => s.map(|it| match it {
- Either::Left(e) => e.into(),
- Either::Right(e) => e.into(),
- }),
+ Ok(s) => s.map(|it| it.syntax_node_ptr()),
Err(_) => continue,
},
MirSpan::Unknown => continue,
@@ -842,6 +839,7 @@ impl Evaluator<'_> {
}
StatementKind::Deinit(_) => not_supported!("de-init statement"),
StatementKind::StorageLive(_)
+ | StatementKind::FakeRead(_)
| StatementKind::StorageDead(_)
| StatementKind::Nop => (),
}
@@ -2301,7 +2299,7 @@ impl Evaluator<'_> {
match self.get_mir_or_dyn_index(def, generic_args.clone(), locals, span)? {
MirOrDynIndex::Dyn(self_ty_idx) => {
// In the layout of current possible receiver, which at the moment of writing this code is one of
- // `&T`, `&mut T`, `Box<T>`, `Rc<T>`, `Arc<T>`, and `Pin<P>` where `P` is one of possible recievers,
+ // `&T`, `&mut T`, `Box<T>`, `Rc<T>`, `Arc<T>`, and `Pin<P>` where `P` is one of possible receivers,
// the vtable is exactly in the `[ptr_size..2*ptr_size]` bytes. So we can use it without branching on
// the type.
let first_arg = arg_bytes.clone().next().unwrap();
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
index 803ef631f..2de99e416 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
@@ -1045,7 +1045,7 @@ impl Evaluator<'_> {
}
"transmute" => {
let [arg] = args else {
- return Err(MirEvalError::TypeError("trasmute arg is not provided"));
+ return Err(MirEvalError::TypeError("transmute arg is not provided"));
};
destination.write_from_interval(self, arg.interval)
}
@@ -1065,7 +1065,7 @@ impl Evaluator<'_> {
}
"ctlz" | "ctlz_nonzero" => {
let [arg] = args else {
- return Err(MirEvalError::TypeError("cttz arg is not provided"));
+ return Err(MirEvalError::TypeError("ctlz arg is not provided"));
};
let result =
u128::from_le_bytes(pad16(arg.get(self)?, false)).leading_zeros() as usize;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
index dd2dba717..639fabc19 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
@@ -2,7 +2,7 @@
use std::{fmt::Write, iter, mem};
-use base_db::FileId;
+use base_db::{salsa::Cycle, FileId};
use chalk_ir::{BoundVar, ConstData, DebruijnIndex, TyKind};
use hir_def::{
body::Body,
@@ -105,9 +105,14 @@ pub enum MirLowerError {
/// A token to ensuring that each drop scope is popped at most once, thanks to the compiler that checks moves.
struct DropScopeToken;
impl DropScopeToken {
- fn pop_and_drop(self, ctx: &mut MirLowerCtx<'_>, current: BasicBlockId) -> BasicBlockId {
+ fn pop_and_drop(
+ self,
+ ctx: &mut MirLowerCtx<'_>,
+ current: BasicBlockId,
+ span: MirSpan,
+ ) -> BasicBlockId {
std::mem::forget(self);
- ctx.pop_drop_scope_internal(current)
+ ctx.pop_drop_scope_internal(current, span)
}
/// It is useful when we want a drop scope is syntaxically closed, but we don't want to execute any drop
@@ -529,6 +534,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
else {
return Ok(None);
};
+ self.push_fake_read(current, cond_place, expr_id.into());
let (then_target, else_target) =
self.pattern_match(current, None, cond_place, *pat)?;
self.write_bytes_to_place(
@@ -581,7 +587,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
self.lower_loop(current, place, *label, expr_id.into(), |this, begin| {
let scope = this.push_drop_scope();
if let Some((_, mut current)) = this.lower_expr_as_place(begin, *body, true)? {
- current = scope.pop_and_drop(this, current);
+ current = scope.pop_and_drop(this, current, body.into());
this.set_goto(current, begin, expr_id.into());
} else {
scope.pop_assume_dropped(this);
@@ -668,6 +674,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
else {
return Ok(None);
};
+ self.push_fake_read(current, cond_place, expr_id.into());
let mut end = None;
for MatchArm { pat, guard, expr } in arms.iter() {
let (then, mut otherwise) =
@@ -718,7 +725,8 @@ impl<'ctx> MirLowerCtx<'ctx> {
.ok_or(MirLowerError::ContinueWithoutLoop)?,
};
let begin = loop_data.begin;
- current = self.drop_until_scope(loop_data.drop_scope_index, current);
+ current =
+ self.drop_until_scope(loop_data.drop_scope_index, current, expr_id.into());
self.set_goto(current, begin, expr_id.into());
Ok(None)
}
@@ -757,7 +765,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
self.current_loop_blocks.as_ref().unwrap().drop_scope_index,
),
};
- current = self.drop_until_scope(drop_scope, current);
+ current = self.drop_until_scope(drop_scope, current, expr_id.into());
self.set_goto(current, end, expr_id.into());
Ok(None)
}
@@ -771,7 +779,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
return Ok(None);
}
}
- current = self.drop_until_scope(0, current);
+ current = self.drop_until_scope(0, current, expr_id.into());
self.set_terminator(current, TerminatorKind::Return, expr_id.into());
Ok(None)
}
@@ -1299,6 +1307,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
return Ok(None);
};
if matches!(&self.body.exprs[lhs], Expr::Underscore) {
+ self.push_fake_read_for_operand(current, rhs_op, span);
return Ok(Some(current));
}
if matches!(
@@ -1575,6 +1584,16 @@ impl<'ctx> MirLowerCtx<'ctx> {
self.result.basic_blocks[block].statements.push(statement);
}
+ fn push_fake_read(&mut self, block: BasicBlockId, p: Place, span: MirSpan) {
+ self.push_statement(block, StatementKind::FakeRead(p).with_span(span));
+ }
+
+ fn push_fake_read_for_operand(&mut self, block: BasicBlockId, operand: Operand, span: MirSpan) {
+ if let Operand::Move(p) | Operand::Copy(p) = operand {
+ self.push_fake_read(block, p, span);
+ }
+ }
+
fn push_assignment(
&mut self,
block: BasicBlockId,
@@ -1733,6 +1752,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
return Ok(None);
};
current = c;
+ self.push_fake_read(current, init_place, span);
(current, else_block) =
self.pattern_match(current, None, init_place, *pat)?;
match (else_block, else_branch) {
@@ -1760,14 +1780,15 @@ impl<'ctx> MirLowerCtx<'ctx> {
}
}
}
- hir_def::hir::Statement::Expr { expr, has_semi: _ } => {
+ &hir_def::hir::Statement::Expr { expr, has_semi: _ } => {
let scope2 = self.push_drop_scope();
- let Some((_, c)) = self.lower_expr_as_place(current, *expr, true)? else {
+ let Some((p, c)) = self.lower_expr_as_place(current, expr, true)? else {
scope2.pop_assume_dropped(self);
scope.pop_assume_dropped(self);
return Ok(None);
};
- current = scope2.pop_and_drop(self, c);
+ self.push_fake_read(c, p, expr.into());
+ current = scope2.pop_and_drop(self, c, expr.into());
}
}
}
@@ -1778,7 +1799,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
};
current = c;
}
- current = scope.pop_and_drop(self, current);
+ current = scope.pop_and_drop(self, current, span);
Ok(Some(current))
}
@@ -1858,9 +1879,14 @@ impl<'ctx> MirLowerCtx<'ctx> {
}
}
- fn drop_until_scope(&mut self, scope_index: usize, mut current: BasicBlockId) -> BasicBlockId {
+ fn drop_until_scope(
+ &mut self,
+ scope_index: usize,
+ mut current: BasicBlockId,
+ span: MirSpan,
+ ) -> BasicBlockId {
for scope in self.drop_scopes[scope_index..].to_vec().iter().rev() {
- self.emit_drop_and_storage_dead_for_scope(scope, &mut current);
+ self.emit_drop_and_storage_dead_for_scope(scope, &mut current, span);
}
current
}
@@ -1876,17 +1902,22 @@ impl<'ctx> MirLowerCtx<'ctx> {
}
/// Don't call directly
- fn pop_drop_scope_internal(&mut self, mut current: BasicBlockId) -> BasicBlockId {
+ fn pop_drop_scope_internal(
+ &mut self,
+ mut current: BasicBlockId,
+ span: MirSpan,
+ ) -> BasicBlockId {
let scope = self.drop_scopes.pop().unwrap();
- self.emit_drop_and_storage_dead_for_scope(&scope, &mut current);
+ self.emit_drop_and_storage_dead_for_scope(&scope, &mut current, span);
current
}
fn pop_drop_scope_assert_finished(
&mut self,
mut current: BasicBlockId,
+ span: MirSpan,
) -> Result<BasicBlockId> {
- current = self.pop_drop_scope_internal(current);
+ current = self.pop_drop_scope_internal(current, span);
if !self.drop_scopes.is_empty() {
implementation_error!("Mismatched count between drop scope push and pops");
}
@@ -1897,6 +1928,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
&mut self,
scope: &DropScope,
current: &mut Idx<BasicBlock>,
+ span: MirSpan,
) {
for &l in scope.locals.iter().rev() {
if !self.result.locals[l].ty.clone().is_copy(self.db, self.owner) {
@@ -1904,13 +1936,10 @@ impl<'ctx> MirLowerCtx<'ctx> {
self.set_terminator(
prev,
TerminatorKind::Drop { place: l.into(), target: *current, unwind: None },
- MirSpan::Unknown,
+ span,
);
}
- self.push_statement(
- *current,
- StatementKind::StorageDead(l).with_span(MirSpan::Unknown),
- );
+ self.push_statement(*current, StatementKind::StorageDead(l).with_span(span));
}
}
}
@@ -1987,7 +2016,7 @@ pub fn mir_body_for_closure_query(
|_| true,
)?;
if let Some(current) = ctx.lower_expr_to_place(*root, return_slot().into(), current)? {
- let current = ctx.pop_drop_scope_assert_finished(current)?;
+ let current = ctx.pop_drop_scope_assert_finished(current, root.into())?;
ctx.set_terminator(current, TerminatorKind::Return, (*root).into());
}
let mut upvar_map: FxHashMap<LocalId, Vec<(&CapturedItem, usize)>> = FxHashMap::default();
@@ -2081,7 +2110,7 @@ pub fn mir_body_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Result<Arc<Mi
pub fn mir_body_recover(
_db: &dyn HirDatabase,
- _cycle: &[String],
+ _cycle: &Cycle,
_def: &DefWithBodyId,
) -> Result<Arc<MirBody>> {
Err(MirLowerError::Loop)
@@ -2131,7 +2160,7 @@ pub fn lower_to_mir(
ctx.lower_params_and_bindings([].into_iter(), binding_picker)?
};
if let Some(current) = ctx.lower_expr_to_place(root_expr, return_slot().into(), current)? {
- let current = ctx.pop_drop_scope_assert_finished(current)?;
+ let current = ctx.pop_drop_scope_assert_finished(current, root_expr.into())?;
ctx.set_terminator(current, TerminatorKind::Return, root_expr.into());
}
Ok(ctx.result)
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs
index 270f75ad9..1120bb1c1 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs
@@ -284,6 +284,7 @@ impl MirLowerCtx<'_> {
);
(current, current_else) = self.pattern_match_binding(
id,
+ *slice,
next_place,
(*slice).into(),
current,
@@ -395,6 +396,7 @@ impl MirLowerCtx<'_> {
if mode == MatchingMode::Bind {
self.pattern_match_binding(
*id,
+ pattern,
cond_place,
pattern.into(),
current,
@@ -431,13 +433,14 @@ impl MirLowerCtx<'_> {
fn pattern_match_binding(
&mut self,
id: BindingId,
+ pat: PatId,
cond_place: Place,
span: MirSpan,
current: BasicBlockId,
current_else: Option<BasicBlockId>,
) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
let target_place = self.binding_local(id)?;
- let mode = self.infer.binding_modes[id];
+ let mode = self.infer.binding_modes[pat];
self.push_storage_live(id, current)?;
self.push_assignment(
current,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs
index df16d0d82..8da03eef2 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs
@@ -9,6 +9,7 @@
use std::mem;
+use base_db::salsa::Cycle;
use chalk_ir::{
fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable},
ConstData, DebruijnIndex,
@@ -248,6 +249,7 @@ impl Filler<'_> {
| Rvalue::CopyForDeref(_) => (),
},
StatementKind::Deinit(_)
+ | StatementKind::FakeRead(_)
| StatementKind::StorageLive(_)
| StatementKind::StorageDead(_)
| StatementKind::Nop => (),
@@ -299,7 +301,7 @@ pub fn monomorphized_mir_body_query(
pub fn monomorphized_mir_body_recover(
_: &dyn HirDatabase,
- _: &[String],
+ _: &Cycle,
_: &DefWithBodyId,
_: &Substitution,
_: &Arc<crate::TraitEnvironment>,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs
index 0108859ff..a91f90bc2 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs
@@ -145,7 +145,7 @@ impl<'a> MirPrettyCtx<'a> {
let indent = mem::take(&mut self.indent);
let mut ctx = MirPrettyCtx {
body: &body,
- local_to_binding: body.binding_locals.iter().map(|(it, y)| (*y, it)).collect(),
+ local_to_binding: body.local_to_binding_map(),
result,
indent,
..*self
@@ -167,7 +167,7 @@ impl<'a> MirPrettyCtx<'a> {
}
fn new(body: &'a MirBody, hir_body: &'a Body, db: &'a dyn HirDatabase) -> Self {
- let local_to_binding = body.binding_locals.iter().map(|(it, y)| (*y, it)).collect();
+ let local_to_binding = body.local_to_binding_map();
MirPrettyCtx {
body,
db,
@@ -233,6 +233,11 @@ impl<'a> MirPrettyCtx<'a> {
this.place(p);
wln!(this, ");");
}
+ StatementKind::FakeRead(p) => {
+ w!(this, "FakeRead(");
+ this.place(p);
+ wln!(this, ");");
+ }
StatementKind::Nop => wln!(this, "Nop;"),
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs
index 7d19e0a19..6f4aef22d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs
@@ -30,6 +30,7 @@ pub(crate) struct TestDB {
impl Default for TestDB {
fn default() -> Self {
let mut this = Self { storage: Default::default(), events: Default::default() };
+ this.setup_syntax_context_root();
this.set_expand_proc_attr_macros_with_durability(true, Durability::HIGH);
this
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
index d22d0d85c..1446e83fa 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
@@ -269,12 +269,7 @@ fn pat_node(
Some(match body_source_map.pat_syntax(pat) {
Ok(sp) => {
let root = db.parse_or_expand(sp.file_id);
- sp.map(|ptr| {
- ptr.either(
- |it| it.to_node(&root).syntax().clone(),
- |it| it.to_node(&root).syntax().clone(),
- )
- })
+ sp.map(|ptr| ptr.to_node(&root).syntax().clone())
}
Err(SyntheticSyntax) => return None,
})
@@ -303,12 +298,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
let syntax_ptr = match body_source_map.pat_syntax(pat) {
Ok(sp) => {
let root = db.parse_or_expand(sp.file_id);
- sp.map(|ptr| {
- ptr.either(
- |it| it.to_node(&root).syntax().clone(),
- |it| it.to_node(&root).syntax().clone(),
- )
- })
+ sp.map(|ptr| ptr.to_node(&root).syntax().clone())
}
Err(SyntheticSyntax) => continue,
};
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs
index bb15ca8c4..28e84e480 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs
@@ -9,11 +9,10 @@ use super::visit_module;
fn typing_whitespace_inside_a_function_should_not_invalidate_types() {
let (mut db, pos) = TestDB::with_position(
"
- //- /lib.rs
- fn foo() -> i32 {
- $01 + 1
- }
- ",
+//- /lib.rs
+fn foo() -> i32 {
+ $01 + 1
+}",
);
{
let events = db.log_executed(|| {
@@ -27,12 +26,11 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() {
}
let new_text = "
- fn foo() -> i32 {
- 1
- +
- 1
- }
- ";
+fn foo() -> i32 {
+ 1
+ +
+ 1
+}";
db.set_file_text(pos.file_id, Arc::from(new_text));
@@ -47,3 +45,55 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() {
assert!(!format!("{events:?}").contains("infer"), "{events:#?}")
}
}
+
+#[test]
+fn typing_inside_a_function_should_not_invalidate_types_in_another() {
+ let (mut db, pos) = TestDB::with_position(
+ "
+//- /lib.rs
+fn foo() -> f32 {
+ 1.0 + 2.0
+}
+fn bar() -> i32 {
+ $01 + 1
+}
+fn baz() -> i32 {
+ 1 + 1
+}",
+ );
+ {
+ let events = db.log_executed(|| {
+ let module = db.module_for_file(pos.file_id);
+ let crate_def_map = module.def_map(&db);
+ visit_module(&db, &crate_def_map, module.local_id, &mut |def| {
+ db.infer(def);
+ });
+ });
+ assert!(format!("{events:?}").contains("infer"))
+ }
+
+ let new_text = "
+fn foo() -> f32 {
+ 1.0 + 2.0
+}
+fn bar() -> i32 {
+ 53
+}
+fn baz() -> i32 {
+ 1 + 1
+}
+";
+
+ db.set_file_text(pos.file_id, Arc::from(new_text));
+
+ {
+ let events = db.log_executed(|| {
+ let module = db.module_for_file(pos.file_id);
+ let crate_def_map = module.def_map(&db);
+ visit_module(&db, &crate_def_map, module.local_id, &mut |def| {
+ db.infer(def);
+ });
+ });
+ assert!(format!("{events:?}").matches("infer").count() == 1, "{events:#?}")
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs
index 1e6e946a1..d16e0eb01 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs
@@ -684,8 +684,7 @@ fn infer_builtin_macros_line() {
}
"#,
expect![[r#"
- !0..1 '0': i32
- !0..6 '0asu32': u32
+ !0..4 '0u32': u32
63..87 '{ ...!(); }': ()
73..74 'x': u32
"#]],
@@ -723,8 +722,7 @@ fn infer_builtin_macros_column() {
}
"#,
expect![[r#"
- !0..1 '0': i32
- !0..6 '0asu32': u32
+ !0..4 '0u32': u32
65..91 '{ ...!(); }': ()
75..76 'x': u32
"#]],
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs
index 0f5a3e175..7234af2d6 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs
@@ -1129,3 +1129,65 @@ fn foo() {
"#,
);
}
+
+#[test]
+fn generic_alias() {
+ check_types(
+ r#"
+type Wrap<T> = T;
+
+enum X {
+ A { cool: u32, stuff: u32 },
+ B,
+}
+
+fn main() {
+ let wrapped = Wrap::<X>::A {
+ cool: 100,
+ stuff: 100,
+ };
+
+ if let Wrap::<X>::A { cool, ..} = &wrapped {}
+ //^^^^ &u32
+}
+"#,
+ );
+}
+
+#[test]
+fn type_mismatch_pat_const_reference() {
+ check_no_mismatches(
+ r#"
+const TEST_STR: &'static str = "abcd";
+
+fn main() {
+ let s = "abcd";
+ match s {
+ TEST_STR => (),
+ _ => (),
+ }
+}
+
+ "#,
+ );
+ check(
+ r#"
+struct Foo<T>(T);
+
+impl<T> Foo<T> {
+ const TEST_I32_REF: &'static i32 = &3;
+ const TEST_I32: i32 = 3;
+}
+
+fn main() {
+ match &6 {
+ Foo::<i32>::TEST_I32_REF => (),
+ Foo::<i32>::TEST_I32 => (),
+ //^^^^^^^^^^^^^^^^^^^^ expected &i32, got i32
+ _ => (),
+ }
+}
+
+ "#,
+ );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
index 6ea059065..35079e709 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
@@ -2000,3 +2000,15 @@ fn test() {
"#,
);
}
+
+#[test]
+fn rustc_test_issue_52437() {
+ check_types(
+ r#"
+ fn main() {
+ let x = [(); &(&'static: loop { |x| {}; }) as *const _ as usize]
+ //^ [(); _]
+ }
+ "#,
+ );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
index d36b885ec..003ae60e8 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
@@ -2598,6 +2598,34 @@ fn test<T: Trait>() {
}
#[test]
+fn associated_type_in_type_bound() {
+ check_types(
+ r#"
+//- minicore: deref
+fn fb(f: Foo<&u8>) {
+ f.foobar();
+ //^^^^^^^^^^ u8
+}
+trait Bar {
+ fn bar(&self) -> u8;
+}
+impl Bar for u8 {
+ fn bar(&self) -> u8 { *self }
+}
+
+struct Foo<F> {
+ foo: F,
+}
+impl<F: core::ops::Deref<Target = impl Bar>> Foo<F> {
+ fn foobar(&self) -> u8 {
+ self.foo.deref().bar()
+ }
+}
+"#,
+ )
+}
+
+#[test]
fn dyn_trait_through_chalk() {
check_types(
r#"
@@ -4439,42 +4467,42 @@ fn test(v: S<i32>) {
fn associated_type_in_argument() {
check(
r#"
- trait A {
- fn m(&self) -> i32;
- }
+trait A {
+ fn m(&self) -> i32;
+}
- fn x<T: B>(k: &<T as B>::Ty) {
- k.m();
- }
+fn x<T: B>(k: &<T as B>::Ty) {
+ k.m();
+}
- struct X;
- struct Y;
+struct X;
+struct Y;
- impl A for X {
- fn m(&self) -> i32 {
- 8
- }
+impl A for X {
+ fn m(&self) -> i32 {
+ 8
}
+}
- impl A for Y {
- fn m(&self) -> i32 {
- 32
- }
+impl A for Y {
+ fn m(&self) -> i32 {
+ 32
}
+}
- trait B {
- type Ty: A;
- }
+trait B {
+ type Ty: A;
+}
- impl B for u16 {
- type Ty = X;
- }
+impl B for u16 {
+ type Ty = X;
+}
- fn ttt() {
- let inp = Y;
- x::<u16>(&inp);
- //^^^^ expected &X, got &Y
- }
- "#,
+fn ttt() {
+ let inp = Y;
+ x::<u16>(&inp);
+ //^^^^ expected &X, got &Y
+}
+"#,
);
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs
index 3c7cfbaed..b6bc76bc9 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs
@@ -48,18 +48,32 @@ pub struct TraitEnvironment {
pub krate: CrateId,
pub block: Option<BlockId>,
// FIXME make this a BTreeMap
- pub(crate) traits_from_clauses: Vec<(Ty, TraitId)>,
+ traits_from_clauses: Box<[(Ty, TraitId)]>,
pub env: chalk_ir::Environment<Interner>,
}
impl TraitEnvironment {
- pub fn empty(krate: CrateId) -> Self {
- TraitEnvironment {
+ pub fn empty(krate: CrateId) -> Arc<Self> {
+ Arc::new(TraitEnvironment {
krate,
block: None,
- traits_from_clauses: Vec::new(),
+ traits_from_clauses: Box::default(),
env: chalk_ir::Environment::new(Interner),
- }
+ })
+ }
+
+ pub fn new(
+ krate: CrateId,
+ block: Option<BlockId>,
+ traits_from_clauses: Box<[(Ty, TraitId)]>,
+ env: chalk_ir::Environment<Interner>,
+ ) -> Arc<Self> {
+ Arc::new(TraitEnvironment { krate, block, traits_from_clauses, env })
+ }
+
+ // pub fn with_block(self: &mut Arc<Self>, block: BlockId) {
+ pub fn with_block(this: &mut Arc<Self>, block: BlockId) {
+ Arc::make_mut(this).block = Some(block);
}
pub fn traits_in_scope_from_clauses(&self, ty: Ty) -> impl Iterator<Item = TraitId> + '_ {