summaryrefslogtreecommitdiffstats
path: root/src/tools/rust-analyzer/crates/hir-ty
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
commitc23a457e72abe608715ac76f076f47dc42af07a5 (patch)
tree2772049aaf84b5c9d0ed12ec8d86812f7a7904b6 /src/tools/rust-analyzer/crates/hir-ty
parentReleasing progress-linux version 1.73.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-c23a457e72abe608715ac76f076f47dc42af07a5.tar.xz
rustc-c23a457e72abe608715ac76f076f47dc42af07a5.zip
Merging upstream version 1.74.1+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.toml3
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/builder.rs13
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs53
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs36
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs67
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/display.rs42
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs15
-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/mutability.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs132
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs27
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs48
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout.rs13
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout/tests/closure.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lib.rs17
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower.rs121
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir.rs145
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs98
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs116
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs246
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs42
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs219
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs60
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs104
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs28
35 files changed, 1242 insertions, 584 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
index abc19d63a..b95ae05cc 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
@@ -32,7 +32,8 @@ once_cell = "1.17.0"
triomphe.workspace = true
nohash-hasher.workspace = true
typed-arena = "2.0.1"
-rustc_index = { version = "0.0.20221221", package = "hkalbasi-rustc-ap-rustc_index", default-features = false }
+
+rustc_index.workspace = true
# local deps
stdx.workspace = true
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs b/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs
index eec57ba3f..967e028bf 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs
@@ -17,7 +17,8 @@ use smallvec::SmallVec;
use crate::{
consteval::unknown_const_as_generic, db::HirDatabase, infer::unify::InferenceTable, primitive,
to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, BoundVar, CallableSig,
- GenericArg, Interner, ProjectionTy, Substitution, TraitRef, Ty, TyDefId, TyExt, TyKind,
+ GenericArg, GenericArgData, Interner, ProjectionTy, Substitution, TraitRef, Ty, TyDefId, TyExt,
+ TyKind,
};
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -79,9 +80,9 @@ impl<D> TyBuilder<D> {
let expected_kind = &self.param_kinds[self.vec.len()];
let arg_kind = match arg.data(Interner) {
- chalk_ir::GenericArgData::Ty(_) => ParamKind::Type,
- chalk_ir::GenericArgData::Lifetime(_) => panic!("Got lifetime in TyBuilder::push"),
- chalk_ir::GenericArgData::Const(c) => {
+ GenericArgData::Ty(_) => ParamKind::Type,
+ GenericArgData::Lifetime(_) => panic!("Got lifetime in TyBuilder::push"),
+ GenericArgData::Const(c) => {
let c = c.data(Interner);
ParamKind::Const(c.ty.clone())
}
@@ -139,8 +140,8 @@ impl<D> TyBuilder<D> {
fn assert_match_kind(&self, a: &chalk_ir::GenericArg<Interner>, e: &ParamKind) {
match (a.data(Interner), e) {
- (chalk_ir::GenericArgData::Ty(_), ParamKind::Type)
- | (chalk_ir::GenericArgData::Const(_), ParamKind::Const(_)) => (),
+ (GenericArgData::Ty(_), ParamKind::Type)
+ | (GenericArgData::Const(_), ParamKind::Const(_)) => (),
_ => panic!("Mismatched kinds: {a:?}, {:?}, {:?}", self.vec, self.param_kinds),
}
}
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 1c0f7b08d..0348680e5 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
@@ -1,7 +1,7 @@
//! Constant evaluation details
use base_db::CrateId;
-use chalk_ir::{BoundVar, DebruijnIndex, GenericArgData};
+use chalk_ir::{cast::Cast, BoundVar, DebruijnIndex};
use hir_def::{
hir::Expr,
path::Path,
@@ -120,7 +120,7 @@ pub fn unknown_const(ty: Ty) -> Const {
}
pub fn unknown_const_as_generic(ty: Ty) -> GenericArg {
- GenericArgData::Const(unknown_const(ty)).intern(Interner)
+ unknown_const(ty).cast(Interner)
}
/// Interns a constant scalar with the given type
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 666955fa1..7ad3659a4 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
@@ -1203,6 +1203,27 @@ fn destructing_assignment() {
"#,
5,
);
+ check_number(
+ r#"
+ const GOAL: u8 = {
+ let (mut a, mut b) = (2, 5);
+ (a, b) = (b, a);
+ a * 10 + b
+ };
+ "#,
+ 52,
+ );
+ check_number(
+ r#"
+ struct Point { x: i32, y: i32 }
+ const GOAL: i32 = {
+ let mut p = Point { x: 5, y: 6 };
+ (p.x, _) = (p.y, p.x);
+ p.x * 10 + p.y
+ };
+ "#,
+ 66,
+ );
}
#[test]
@@ -1433,6 +1454,30 @@ fn from_trait() {
}
#[test]
+fn closure_clone() {
+ check_number(
+ r#"
+//- minicore: clone, fn
+struct S(u8);
+
+impl Clone for S(u8) {
+ fn clone(&self) -> S {
+ S(self.0 + 5)
+ }
+}
+
+const GOAL: u8 = {
+ let s = S(3);
+ let cl = move || s;
+ let cl = cl.clone();
+ cl().0
+}
+ "#,
+ 8,
+ );
+}
+
+#[test]
fn builtin_derive_macro() {
check_number(
r#"
@@ -2396,14 +2441,14 @@ fn const_loop() {
fn const_transfer_memory() {
check_number(
r#"
- //- minicore: slice, index, coerce_unsized
+ //- minicore: slice, index, coerce_unsized, option
const A1: &i32 = &1;
const A2: &i32 = &10;
const A3: [&i32; 3] = [&1, &2, &100];
- const A4: (i32, &i32) = (1, &1000);
- const GOAL: i32 = *A1 + *A2 + *A3[2] + *A4.1;
+ const A4: (i32, &i32, Option<&i32>) = (1, &1000, Some(&10000));
+ const GOAL: i32 = *A1 + *A2 + *A3[2] + *A4.1 + *A4.2.unwrap_or(&5);
"#,
- 1111,
+ 11111,
);
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs
index 2855f7890..44a4ac27a 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs
@@ -499,24 +499,26 @@ fn offset() {
r#"
//- minicore: coerce_unsized, index, slice
extern "rust-intrinsic" {
- pub fn offset<T>(dst: *const T, offset: isize) -> *const T;
+ pub fn offset<Ptr, Delta>(dst: Ptr, offset: Delta) -> Ptr;
+ pub fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
}
- const GOAL: u8 = unsafe {
- let ar: &[(u8, u8, u8)] = &[
+ const GOAL: i32 = unsafe {
+ let ar: &[(i32, i32, i32)] = &[
(10, 11, 12),
(20, 21, 22),
(30, 31, 32),
(40, 41, 42),
(50, 51, 52),
];
- let ar: *const [(u8, u8, u8)] = ar;
- let ar = ar as *const (u8, u8, u8);
- let element = *offset(ar, 2);
- element.1
+ let ar: *const [(i32, i32, i32)] = ar;
+ let ar = ar as *const (i32, i32, i32);
+ let element3 = *offset(ar, 2usize);
+ let element4 = *arith_offset(ar, 3);
+ element3.1 * 100 + element4.0
};
"#,
- 31,
+ 3140,
);
}
@@ -585,6 +587,24 @@ fn write_bytes() {
}
#[test]
+fn write_via_move() {
+ check_number(
+ r#"
+ extern "rust-intrinsic" {
+ fn write_via_move<T>(ptr: *mut T, value: T);
+ }
+
+ const GOAL: i32 = unsafe {
+ let mut x = 2;
+ write_via_move(&mut x, 100);
+ x
+ };
+ "#,
+ 100,
+ );
+}
+
+#[test]
fn copy() {
check_number(
r#"
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 a94a962c1..36d69edf9 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
@@ -163,25 +163,56 @@ impl<'a> DeclValidator<'a> {
|| allows.contains(allow::NONSTANDARD_STYLE)
})
};
+ let db = self.db.upcast();
+ let file_id_is_derive = || {
+ match id {
+ AttrDefId::ModuleId(m) => {
+ m.def_map(db)[m.local_id].origin.file_id().map(Into::into)
+ }
+ AttrDefId::FunctionId(f) => Some(f.lookup(db).id.file_id()),
+ AttrDefId::StaticId(sid) => Some(sid.lookup(db).id.file_id()),
+ AttrDefId::ConstId(cid) => Some(cid.lookup(db).id.file_id()),
+ AttrDefId::TraitId(tid) => Some(tid.lookup(db).id.file_id()),
+ AttrDefId::TraitAliasId(taid) => Some(taid.lookup(db).id.file_id()),
+ AttrDefId::ImplId(iid) => Some(iid.lookup(db).id.file_id()),
+ AttrDefId::ExternBlockId(id) => Some(id.lookup(db).id.file_id()),
+ AttrDefId::ExternCrateId(id) => Some(id.lookup(db).id.file_id()),
+ AttrDefId::UseId(id) => Some(id.lookup(db).id.file_id()),
+ // These warnings should not explore macro definitions at all
+ AttrDefId::MacroId(_) => None,
+ AttrDefId::AdtId(aid) => match aid {
+ AdtId::StructId(sid) => Some(sid.lookup(db).id.file_id()),
+ AdtId::EnumId(eid) => Some(eid.lookup(db).id.file_id()),
+ // Unions aren't yet supported
+ AdtId::UnionId(_) => None,
+ },
+ AttrDefId::FieldId(_) => None,
+ AttrDefId::EnumVariantId(_) => None,
+ AttrDefId::TypeAliasId(_) => None,
+ AttrDefId::GenericParamId(_) => None,
+ }
+ .map_or(false, |file_id| {
+ file_id.is_custom_derive(db.upcast()) || file_id.is_builtin_derive(db.upcast())
+ })
+ };
- is_allowed(id)
- // go upwards one step or give up
- || match id {
- AttrDefId::ModuleId(m) => m.containing_module(self.db.upcast()).map(|v| v.into()),
- AttrDefId::FunctionId(f) => Some(f.lookup(self.db.upcast()).container.into()),
- AttrDefId::StaticId(sid) => Some(sid.lookup(self.db.upcast()).container.into()),
- AttrDefId::ConstId(cid) => Some(cid.lookup(self.db.upcast()).container.into()),
- AttrDefId::TraitId(tid) => Some(tid.lookup(self.db.upcast()).container.into()),
- AttrDefId::TraitAliasId(taid) => Some(taid.lookup(self.db.upcast()).container.into()),
- AttrDefId::ImplId(iid) => Some(iid.lookup(self.db.upcast()).container.into()),
- AttrDefId::ExternBlockId(id) => Some(id.lookup(self.db.upcast()).container.into()),
- AttrDefId::ExternCrateId(id) => Some(id.lookup(self.db.upcast()).container.into()),
- AttrDefId::UseId(id) => Some(id.lookup(self.db.upcast()).container.into()),
+ let parent = || {
+ match id {
+ AttrDefId::ModuleId(m) => m.containing_module(db).map(|v| v.into()),
+ AttrDefId::FunctionId(f) => Some(f.lookup(db).container.into()),
+ AttrDefId::StaticId(sid) => Some(sid.lookup(db).container.into()),
+ AttrDefId::ConstId(cid) => Some(cid.lookup(db).container.into()),
+ AttrDefId::TraitId(tid) => Some(tid.lookup(db).container.into()),
+ AttrDefId::TraitAliasId(taid) => Some(taid.lookup(db).container.into()),
+ AttrDefId::ImplId(iid) => Some(iid.lookup(db).container.into()),
+ AttrDefId::ExternBlockId(id) => Some(id.lookup(db).container.into()),
+ AttrDefId::ExternCrateId(id) => Some(id.lookup(db).container.into()),
+ AttrDefId::UseId(id) => Some(id.lookup(db).container.into()),
// These warnings should not explore macro definitions at all
AttrDefId::MacroId(_) => None,
AttrDefId::AdtId(aid) => match aid {
- AdtId::StructId(sid) => Some(sid.lookup(self.db.upcast()).container.into()),
- AdtId::EnumId(eid) => Some(eid.lookup(self.db.upcast()).container.into()),
+ AdtId::StructId(sid) => Some(sid.lookup(db).container.into()),
+ AdtId::EnumId(eid) => Some(eid.lookup(db).container.into()),
// Unions aren't yet supported
AdtId::UnionId(_) => None,
},
@@ -191,6 +222,12 @@ impl<'a> DeclValidator<'a> {
AttrDefId::GenericParamId(_) => None,
}
.is_some_and(|mid| self.allowed(mid, allow_name, true))
+ };
+ is_allowed(id)
+ // FIXME: this is a hack to avoid false positives in derive macros currently
+ || file_id_is_derive()
+ // go upwards one step or give up
+ || parent()
}
fn validate_func(&mut self, func: FunctionId) {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs
index 9f9a56ffa..cbca0e801 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs
@@ -75,7 +75,7 @@ fn walk_unsafe(
Expr::Path(path) => {
let resolver = resolver_for_expr(db.upcast(), def, current);
let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path);
- if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id))) = value_or_partial {
+ if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id), _)) = value_or_partial {
if db.static_data(id).mutable {
unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block });
}
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 1b4ee4613..f6d6b00d7 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -1809,6 +1809,25 @@ impl HirDisplay for Path {
}
}
+ // Convert trait's `Self` bound back to the surface syntax. Note there is no associated
+ // trait, so there can only be one path segment that `has_self_type`. The `Self` type
+ // itself can contain further qualified path through, which will be handled by recursive
+ // `hir_fmt`s.
+ //
+ // `trait_mod::Trait<Self = type_mod::Type, Args>::Assoc`
+ // =>
+ // `<type_mod::Type as trait_mod::Trait<Args>>::Assoc`
+ let trait_self_ty = self.segments().iter().find_map(|seg| {
+ let generic_args = seg.args_and_bindings?;
+ generic_args.has_self_type.then(|| &generic_args.args[0])
+ });
+ if let Some(ty) = trait_self_ty {
+ write!(f, "<")?;
+ ty.hir_fmt(f)?;
+ write!(f, " as ")?;
+ // Now format the path of the trait...
+ }
+
for (seg_idx, segment) in self.segments().iter().enumerate() {
if !matches!(self.kind(), PathKind::Plain) || seg_idx > 0 {
write!(f, "::")?;
@@ -1840,15 +1859,12 @@ impl HirDisplay for Path {
return Ok(());
}
- write!(f, "<")?;
let mut first = true;
- for arg in generic_args.args.iter() {
+ // Skip the `Self` bound if exists. It's handled outside the loop.
+ for arg in &generic_args.args[generic_args.has_self_type as usize..] {
if first {
first = false;
- if generic_args.has_self_type {
- // FIXME: Convert to `<Ty as Trait>` form.
- write!(f, "Self = ")?;
- }
+ write!(f, "<")?;
} else {
write!(f, ", ")?;
}
@@ -1857,6 +1873,7 @@ impl HirDisplay for Path {
for binding in generic_args.bindings.iter() {
if first {
first = false;
+ write!(f, "<")?;
} else {
write!(f, ", ")?;
}
@@ -1872,9 +1889,20 @@ impl HirDisplay for Path {
}
}
}
- write!(f, ">")?;
+
+ // There may be no generic arguments to print, in case of a trait having only a
+ // single `Self` bound which is converted to `<Ty as Trait>::Assoc`.
+ if !first {
+ write!(f, ">")?;
+ }
+
+ // Current position: `<Ty as Trait<Args>|`
+ if generic_args.has_self_type {
+ write!(f, ">")?;
+ }
}
}
+
Ok(())
}
}
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 b4915dbf0..78d3c667a 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
@@ -194,7 +194,8 @@ pub(crate) type InferResult<T> = Result<InferOk<T>, TypeError>;
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum InferenceDiagnostic {
NoSuchField {
- expr: ExprId,
+ field: ExprOrPatId,
+ private: bool,
},
PrivateField {
expr: ExprId,
@@ -228,6 +229,11 @@ pub enum InferenceDiagnostic {
expected: usize,
found: usize,
},
+ MismatchedTupleStructPatArgCount {
+ pat: ExprOrPatId,
+ expected: usize,
+ found: usize,
+ },
ExpectedFunction {
call_expr: ExprId,
found: Ty,
@@ -1017,7 +1023,7 @@ impl<'a> InferenceContext<'a> {
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into());
let (resolution, unresolved) = if value_ns {
match self.resolver.resolve_path_in_value_ns(self.db.upcast(), path) {
- Some(ResolveValueResult::ValueNs(value)) => match value {
+ Some(ResolveValueResult::ValueNs(value, _)) => match value {
ValueNs::EnumVariantId(var) => {
let substs = ctx.substs_from_path(path, var.into(), true);
let ty = self.db.ty(var.parent.into());
@@ -1033,12 +1039,14 @@ impl<'a> InferenceContext<'a> {
ValueNs::ImplSelf(impl_id) => (TypeNs::SelfType(impl_id), None),
_ => return (self.err_ty(), None),
},
- Some(ResolveValueResult::Partial(typens, unresolved)) => (typens, Some(unresolved)),
+ Some(ResolveValueResult::Partial(typens, unresolved, _)) => {
+ (typens, Some(unresolved))
+ }
None => return (self.err_ty(), None),
}
} else {
match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path) {
- Some(it) => it,
+ Some((it, idx, _)) => (it, idx),
None => return (self.err_ty(), None),
}
};
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs
index 9e1c74b16..a116d4447 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs
@@ -39,8 +39,14 @@ impl CastCheck {
}
fn check_ref_to_ptr_cast(expr_ty: Ty, cast_ty: Ty, table: &mut InferenceTable<'_>) -> bool {
- let Some((expr_inner_ty, _, _)) = expr_ty.as_reference() else { return false; };
- let Some((cast_inner_ty, _)) = cast_ty.as_raw_ptr() else { return false; };
- let TyKind::Array(expr_elt_ty, _) = expr_inner_ty.kind(Interner) else { return false; };
+ let Some((expr_inner_ty, _, _)) = expr_ty.as_reference() else {
+ return false;
+ };
+ let Some((cast_inner_ty, _)) = cast_ty.as_raw_ptr() else {
+ return false;
+ };
+ let TyKind::Array(expr_elt_ty, _) = expr_inner_ty.kind(Interner) else {
+ return false;
+ };
table.coerce(expr_elt_ty, cast_inner_ty).is_ok()
}
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 1781f6c58..13d6b5643 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
@@ -322,7 +322,7 @@ impl InferenceContext<'_> {
Expr::Path(p) => {
let resolver = resolver_for_expr(self.db.upcast(), self.owner, tgt_expr);
if let Some(r) = resolver.resolve_path_in_value_ns(self.db.upcast(), p) {
- if let ResolveValueResult::ValueNs(v) = r {
+ if let ResolveValueResult::ValueNs(v, _) = r {
if let ValueNs::LocalBinding(b) = v {
return Some(HirPlace { local: b, projections: vec![] });
}
@@ -452,6 +452,8 @@ impl InferenceContext<'_> {
fn walk_expr_without_adjust(&mut self, tgt_expr: ExprId) {
match &self.body[tgt_expr] {
+ Expr::OffsetOf(_) => (),
+ Expr::InlineAsm(e) => self.walk_expr_without_adjust(e.e),
Expr::If { condition, then_branch, else_branch } => {
self.consume_expr(*condition);
self.consume_expr(*then_branch);
@@ -467,13 +469,13 @@ impl InferenceContext<'_> {
Statement::Let { pat, type_ref: _, initializer, else_branch } => {
if let Some(else_branch) = else_branch {
self.consume_expr(*else_branch);
- if let Some(initializer) = initializer {
- self.consume_expr(*initializer);
- }
- return;
}
if let Some(initializer) = initializer {
- self.walk_expr(*initializer);
+ if else_branch.is_some() {
+ self.consume_expr(*initializer);
+ } else {
+ self.walk_expr(*initializer);
+ }
if let Some(place) = self.place_of_expr(*initializer) {
self.consume_with_pat(place, *pat);
}
@@ -620,6 +622,7 @@ impl InferenceContext<'_> {
| Expr::Tuple { exprs, is_assignee_expr: _ } => {
self.consume_exprs(exprs.iter().copied())
}
+
Expr::Missing
| Expr::Continue { .. }
| Expr::Path(_)
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 8cbdae625..0c3c725a7 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
@@ -5,9 +5,7 @@ use std::{
mem,
};
-use chalk_ir::{
- cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyVariableKind,
-};
+use chalk_ir::{cast::Cast, fold::Shift, DebruijnIndex, Mutability, TyVariableKind};
use hir_def::{
generics::TypeOrConstParamData,
hir::{
@@ -516,9 +514,6 @@ impl InferenceContext<'_> {
}
Expr::RecordLit { path, fields, spread, .. } => {
let (ty, def_id) = self.resolve_variant(path.as_deref(), false);
- if let Some(variant) = def_id {
- self.write_variant_resolution(tgt_expr.into(), variant);
- }
if let Some(t) = expected.only_has_type(&mut self.table) {
self.unify(&ty, &t);
@@ -528,26 +523,56 @@ impl InferenceContext<'_> {
.as_adt()
.map(|(_, s)| s.clone())
.unwrap_or_else(|| Substitution::empty(Interner));
- let field_types = def_id.map(|it| self.db.field_types(it)).unwrap_or_default();
- let variant_data = def_id.map(|it| it.variant_data(self.db.upcast()));
- for field in fields.iter() {
- let field_def =
- variant_data.as_ref().and_then(|it| match it.field(&field.name) {
- Some(local_id) => Some(FieldId { parent: def_id.unwrap(), local_id }),
- None => {
- self.push_diagnostic(InferenceDiagnostic::NoSuchField {
- expr: field.expr,
- });
- None
- }
- });
- let field_ty = field_def.map_or(self.err_ty(), |it| {
- field_types[it.local_id].clone().substitute(Interner, &substs)
- });
- // Field type might have some unknown types
- // FIXME: we may want to emit a single type variable for all instance of type fields?
- let field_ty = self.insert_type_vars(field_ty);
- self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty));
+ if let Some(variant) = def_id {
+ self.write_variant_resolution(tgt_expr.into(), variant);
+ }
+ match def_id {
+ _ if fields.is_empty() => {}
+ Some(def) => {
+ let field_types = self.db.field_types(def);
+ let variant_data = def.variant_data(self.db.upcast());
+ let visibilities = self.db.field_visibilities(def);
+ for field in fields.iter() {
+ let field_def = {
+ match variant_data.field(&field.name) {
+ Some(local_id) => {
+ if !visibilities[local_id].is_visible_from(
+ self.db.upcast(),
+ self.resolver.module(),
+ ) {
+ self.push_diagnostic(
+ InferenceDiagnostic::NoSuchField {
+ field: field.expr.into(),
+ private: true,
+ },
+ );
+ }
+ Some(local_id)
+ }
+ None => {
+ self.push_diagnostic(InferenceDiagnostic::NoSuchField {
+ field: field.expr.into(),
+ private: false,
+ });
+ None
+ }
+ }
+ };
+ let field_ty = field_def.map_or(self.err_ty(), |it| {
+ field_types[it].clone().substitute(Interner, &substs)
+ });
+
+ // Field type might have some unknown types
+ // FIXME: we may want to emit a single type variable for all instance of type fields?
+ let field_ty = self.insert_type_vars(field_ty);
+ self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty));
+ }
+ }
+ None => {
+ for field in fields.iter() {
+ self.infer_expr_coerce(field.expr, &Expectation::None);
+ }
+ }
}
if let Some(expr) = spread {
self.infer_expr(*expr, &Expectation::has_type(ty.clone()));
@@ -750,7 +775,7 @@ impl InferenceContext<'_> {
self.resolve_associated_type_with_params(
self_ty,
self.resolve_ops_index_output(),
- &[GenericArgData::Ty(index_ty).intern(Interner)],
+ &[index_ty.cast(Interner)],
)
} else {
self.err_ty()
@@ -845,6 +870,11 @@ impl InferenceContext<'_> {
});
expected
}
+ Expr::OffsetOf(_) => TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner),
+ Expr::InlineAsm(it) => {
+ self.infer_expr_no_expect(it.e);
+ self.result.standard_types.unit.clone()
+ }
};
// use a new type variable if we got unknown here
let ty = self.insert_type_vars_shallow(ty);
@@ -1124,7 +1154,7 @@ impl InferenceContext<'_> {
Expr::Underscore => rhs_ty.clone(),
_ => {
// `lhs` is a place expression, a unit struct, or an enum variant.
- let lhs_ty = self.infer_expr(lhs, &Expectation::none());
+ let lhs_ty = self.infer_expr_inner(lhs, &Expectation::none());
// This is the only branch where this function may coerce any type.
// We are returning early to avoid the unifiability check below.
@@ -1721,16 +1751,13 @@ impl InferenceContext<'_> {
for (id, data) in def_generics.iter().skip(substs.len()) {
match data {
TypeOrConstParamData::TypeParamData(_) => {
- substs.push(GenericArgData::Ty(self.table.new_type_var()).intern(Interner))
- }
- TypeOrConstParamData::ConstParamData(_) => {
- substs.push(
- GenericArgData::Const(self.table.new_const_var(
- self.db.const_param_ty(ConstParamId::from_unchecked(id)),
- ))
- .intern(Interner),
- )
+ substs.push(self.table.new_type_var().cast(Interner))
}
+ TypeOrConstParamData::ConstParamData(_) => substs.push(
+ self.table
+ .new_const_var(self.db.const_param_ty(ConstParamId::from_unchecked(id)))
+ .cast(Interner),
+ ),
}
}
assert_eq!(substs.len(), total_len);
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs
index 396ca0044..b8a1af96f 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs
@@ -35,6 +35,8 @@ impl InferenceContext<'_> {
fn infer_mut_expr_without_adjust(&mut self, tgt_expr: ExprId, mutability: Mutability) {
match &self.body[tgt_expr] {
Expr::Missing => (),
+ Expr::InlineAsm(e) => self.infer_mut_expr_without_adjust(e.e, Mutability::Not),
+ Expr::OffsetOf(_) => (),
&Expr::If { condition, then_branch, else_branch } => {
self.infer_mut_expr(condition, Mutability::Not);
self.infer_mut_expr(then_branch, Mutability::Not);
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 5da0ab76b..4e28ec060 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
@@ -15,7 +15,8 @@ use crate::{
infer::{BindingMode, Expectation, InferenceContext, TypeMismatch},
lower::lower_to_chalk_mutability,
primitive::UintTy,
- static_lifetime, Interner, Scalar, Substitution, Ty, TyBuilder, TyExt, TyKind,
+ static_lifetime, InferenceDiagnostic, Interner, Scalar, Substitution, Ty, TyBuilder, TyExt,
+ TyKind,
};
/// Used to generalize patterns and assignee expressions.
@@ -74,29 +75,68 @@ impl InferenceContext<'_> {
if let Some(variant) = def {
self.write_variant_resolution(id.into(), variant);
}
+ if let Some(var) = &var_data {
+ let cmp = if ellipsis.is_some() { usize::gt } else { usize::ne };
+
+ if cmp(&subs.len(), &var.fields().len()) {
+ self.push_diagnostic(InferenceDiagnostic::MismatchedTupleStructPatArgCount {
+ pat: id.into(),
+ expected: var.fields().len(),
+ found: subs.len(),
+ });
+ }
+ }
+
self.unify(&ty, expected);
let substs =
ty.as_adt().map(|(_, s)| s.clone()).unwrap_or_else(|| Substitution::empty(Interner));
- let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default();
- let (pre, post) = match ellipsis {
- Some(idx) => subs.split_at(idx),
- None => (subs, &[][..]),
- };
- let post_idx_offset = field_tys.iter().count().saturating_sub(post.len());
-
- let pre_iter = pre.iter().enumerate();
- let post_iter = (post_idx_offset..).zip(post.iter());
- for (i, &subpat) in pre_iter.chain(post_iter) {
- let expected_ty = var_data
- .as_ref()
- .and_then(|d| d.field(&Name::new_tuple_field(i)))
- .map_or(self.err_ty(), |field| {
- field_tys[field].clone().substitute(Interner, &substs)
- });
- let expected_ty = self.normalize_associated_types_in(expected_ty);
- T::infer(self, subpat, &expected_ty, default_bm);
+ match def {
+ _ if subs.len() == 0 => {}
+ Some(def) => {
+ let field_types = self.db.field_types(def);
+ let variant_data = def.variant_data(self.db.upcast());
+ let visibilities = self.db.field_visibilities(def);
+
+ let (pre, post) = match ellipsis {
+ Some(idx) => subs.split_at(idx),
+ None => (subs, &[][..]),
+ };
+ let post_idx_offset = field_types.iter().count().saturating_sub(post.len());
+
+ let pre_iter = pre.iter().enumerate();
+ let post_iter = (post_idx_offset..).zip(post.iter());
+
+ for (i, &subpat) in pre_iter.chain(post_iter) {
+ let field_def = {
+ match variant_data.field(&Name::new_tuple_field(i)) {
+ Some(local_id) => {
+ if !visibilities[local_id]
+ .is_visible_from(self.db.upcast(), self.resolver.module())
+ {
+ // FIXME(DIAGNOSE): private tuple field
+ }
+ Some(local_id)
+ }
+ None => None,
+ }
+ };
+
+ let expected_ty = field_def.map_or(self.err_ty(), |f| {
+ field_types[f].clone().substitute(Interner, &substs)
+ });
+ let expected_ty = self.normalize_associated_types_in(expected_ty);
+
+ T::infer(self, subpat, &expected_ty, default_bm);
+ }
+ }
+ None => {
+ let err_ty = self.err_ty();
+ for &inner in subs {
+ T::infer(self, inner, &err_ty, default_bm);
+ }
+ }
}
ty
@@ -109,7 +149,7 @@ impl InferenceContext<'_> {
expected: &Ty,
default_bm: T::BindingMode,
id: T,
- subs: impl Iterator<Item = (Name, T)>,
+ subs: impl Iterator<Item = (Name, T)> + ExactSizeIterator,
) -> Ty {
let (ty, def) = self.resolve_variant(path, false);
if let Some(variant) = def {
@@ -121,17 +161,51 @@ impl InferenceContext<'_> {
let substs =
ty.as_adt().map(|(_, s)| s.clone()).unwrap_or_else(|| Substitution::empty(Interner));
- let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default();
- let var_data = def.map(|it| it.variant_data(self.db.upcast()));
+ match def {
+ _ if subs.len() == 0 => {}
+ Some(def) => {
+ let field_types = self.db.field_types(def);
+ let variant_data = def.variant_data(self.db.upcast());
+ let visibilities = self.db.field_visibilities(def);
+
+ for (name, inner) in subs {
+ let field_def = {
+ match variant_data.field(&name) {
+ Some(local_id) => {
+ if !visibilities[local_id]
+ .is_visible_from(self.db.upcast(), self.resolver.module())
+ {
+ self.push_diagnostic(InferenceDiagnostic::NoSuchField {
+ field: inner.into(),
+ private: true,
+ });
+ }
+ Some(local_id)
+ }
+ None => {
+ self.push_diagnostic(InferenceDiagnostic::NoSuchField {
+ field: inner.into(),
+ private: false,
+ });
+ None
+ }
+ }
+ };
- for (name, inner) in subs {
- let expected_ty = var_data
- .as_ref()
- .and_then(|it| it.field(&name))
- .map_or(self.err_ty(), |f| field_tys[f].clone().substitute(Interner, &substs));
- let expected_ty = self.normalize_associated_types_in(expected_ty);
+ let expected_ty = field_def.map_or(self.err_ty(), |f| {
+ field_types[f].clone().substitute(Interner, &substs)
+ });
+ let expected_ty = self.normalize_associated_types_in(expected_ty);
- T::infer(self, inner, &expected_ty, default_bm);
+ T::infer(self, inner, &expected_ty, default_bm);
+ }
+ }
+ None => {
+ let err_ty = self.err_ty();
+ for (_, inner) in subs {
+ T::infer(self, inner, &err_ty, default_bm);
+ }
+ }
}
ty
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 79d9e21e7..c6bbf2f61 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
@@ -61,8 +61,8 @@ impl InferenceContext<'_> {
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
+ 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)))?,
}
@@ -178,13 +178,30 @@ impl InferenceContext<'_> {
remaining_index: usize,
id: ExprOrPatId,
) -> Option<(ValueNs, Substitution)> {
- assert!(remaining_index < path.segments().len());
// there may be more intermediate segments between the resolved one and
// the end. Only the last segment needs to be resolved to a value; from
// the segments before that, we need to get either a type or a trait ref.
- let resolved_segment = path.segments().get(remaining_index - 1).unwrap();
- let remaining_segments = path.segments().skip(remaining_index);
+ let _d;
+ let (resolved_segment, remaining_segments) = match path {
+ Path::Normal { .. } => {
+ assert!(remaining_index < path.segments().len());
+ (
+ path.segments().get(remaining_index - 1).unwrap(),
+ path.segments().skip(remaining_index),
+ )
+ }
+ Path::LangItem(..) => (
+ PathSegment {
+ name: {
+ _d = hir_expand::name::known::Unknown;
+ &_d
+ },
+ args_and_bindings: None,
+ },
+ path.segments(),
+ ),
+ };
let is_before_last = remaining_segments.len() == 1;
match (def, is_before_last) {
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 0fb71135b..0a68a9f3b 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
@@ -10,7 +10,6 @@ use chalk_solve::infer::ParameterEnaVariableExt;
use either::Either;
use ena::unify::UnifyKey;
use hir_expand::name;
-use stdx::never;
use triomphe::Arc;
use super::{InferOk, InferResult, InferenceContext, TypeError};
@@ -92,15 +91,10 @@ pub(crate) fn unify(
let vars = Substitution::from_iter(
Interner,
tys.binders.iter(Interner).map(|it| match &it.kind {
- chalk_ir::VariableKind::Ty(_) => {
- GenericArgData::Ty(table.new_type_var()).intern(Interner)
- }
- chalk_ir::VariableKind::Lifetime => {
- GenericArgData::Ty(table.new_type_var()).intern(Interner)
- } // FIXME: maybe wrong?
- chalk_ir::VariableKind::Const(ty) => {
- GenericArgData::Const(table.new_const_var(ty.clone())).intern(Interner)
- }
+ chalk_ir::VariableKind::Ty(_) => table.new_type_var().cast(Interner),
+ // FIXME: maybe wrong?
+ chalk_ir::VariableKind::Lifetime => table.new_type_var().cast(Interner),
+ chalk_ir::VariableKind::Const(ty) => table.new_const_var(ty.clone()).cast(Interner),
}),
);
let ty1_with_vars = vars.apply(tys.value.0.clone(), Interner);
@@ -111,10 +105,10 @@ pub(crate) fn unify(
// default any type vars that weren't unified back to their original bound vars
// (kind of hacky)
let find_var = |iv| {
- vars.iter(Interner).position(|v| match v.interned() {
- chalk_ir::GenericArgData::Ty(ty) => ty.inference_var(Interner),
- chalk_ir::GenericArgData::Lifetime(lt) => lt.inference_var(Interner),
- chalk_ir::GenericArgData::Const(c) => c.inference_var(Interner),
+ vars.iter(Interner).position(|v| match v.data(Interner) {
+ GenericArgData::Ty(ty) => ty.inference_var(Interner),
+ GenericArgData::Lifetime(lt) => lt.inference_var(Interner),
+ GenericArgData::Const(c) => c.inference_var(Interner),
} == Some(iv))
};
let fallback = |iv, kind, default, binder| match kind {
@@ -149,6 +143,9 @@ pub(crate) struct InferenceTable<'a> {
var_unification_table: ChalkInferenceTable,
type_variable_table: Vec<TypeVariableFlags>,
pending_obligations: Vec<Canonicalized<InEnvironment<Goal>>>,
+ /// Double buffer used in [`Self::resolve_obligations_as_possible`] to cut down on
+ /// temporary allocations.
+ resolve_obligations_buffer: Vec<Canonicalized<InEnvironment<Goal>>>,
}
pub(crate) struct InferenceTableSnapshot {
@@ -165,6 +162,7 @@ impl<'a> InferenceTable<'a> {
var_unification_table: ChalkInferenceTable::new(),
type_variable_table: Vec::new(),
pending_obligations: Vec::new(),
+ resolve_obligations_buffer: Vec::new(),
}
}
@@ -516,10 +514,10 @@ impl<'a> InferenceTable<'a> {
pub(crate) fn resolve_obligations_as_possible(&mut self) {
let _span = profile::span("resolve_obligations_as_possible");
let mut changed = true;
- let mut obligations = Vec::new();
- while changed {
- changed = false;
+ let mut obligations = mem::take(&mut self.resolve_obligations_buffer);
+ while mem::take(&mut changed) {
mem::swap(&mut self.pending_obligations, &mut obligations);
+
for canonicalized in obligations.drain(..) {
if !self.check_changed(&canonicalized) {
self.pending_obligations.push(canonicalized);
@@ -534,6 +532,8 @@ impl<'a> InferenceTable<'a> {
self.register_obligation_in_env(uncanonical);
}
}
+ self.resolve_obligations_buffer = obligations;
+ self.resolve_obligations_buffer.clear();
}
pub(crate) fn fudge_inference<T: TypeFoldable<Interner>>(
@@ -611,9 +611,9 @@ impl<'a> InferenceTable<'a> {
fn check_changed(&mut self, canonicalized: &Canonicalized<InEnvironment<Goal>>) -> bool {
canonicalized.free_vars.iter().any(|var| {
let iv = match var.data(Interner) {
- chalk_ir::GenericArgData::Ty(ty) => ty.inference_var(Interner),
- chalk_ir::GenericArgData::Lifetime(lt) => lt.inference_var(Interner),
- chalk_ir::GenericArgData::Const(c) => c.inference_var(Interner),
+ GenericArgData::Ty(ty) => ty.inference_var(Interner),
+ GenericArgData::Lifetime(lt) => lt.inference_var(Interner),
+ GenericArgData::Const(c) => c.inference_var(Interner),
}
.expect("free var is not inference var");
if self.var_unification_table.probe_var(iv).is_some() {
@@ -690,14 +690,10 @@ impl<'a> InferenceTable<'a> {
.fill(|it| {
let arg = match it {
ParamKind::Type => self.new_type_var(),
- ParamKind::Const(ty) => {
- never!("Tuple with const parameter");
- return GenericArgData::Const(self.new_const_var(ty.clone()))
- .intern(Interner);
- }
+ ParamKind::Const(_) => unreachable!("Tuple with const parameter"),
};
arg_tys.push(arg.clone());
- GenericArgData::Ty(arg).intern(Interner)
+ arg.cast(Interner)
})
.build();
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 b15339d44..1a6106c02 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
@@ -24,7 +24,7 @@ pub use self::{
macro_rules! user_error {
($it: expr) => {
- return Err(LayoutError::UserError(format!($it)))
+ return Err(LayoutError::UserError(format!($it).into()))
};
}
@@ -50,7 +50,7 @@ pub type Variants = hir_def::layout::Variants<RustcEnumVariantIdx>;
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum LayoutError {
- UserError(String),
+ UserError(Box<str>),
SizeOverflow,
TargetLayoutNotAvailable,
HasPlaceholder,
@@ -109,7 +109,8 @@ fn layout_of_simd_ty(
// * the homogeneous field type and the number of fields.
let (e_ty, e_len, is_array) = if let TyKind::Array(e_ty, _) = f0_ty.kind(Interner) {
// 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 {
+ let FieldsShape::Array { count, .. } = db.layout_of_ty(f0_ty.clone(), env.clone())?.fields
+ else {
user_error!("Array with non array layout");
};
@@ -233,9 +234,9 @@ pub fn layout_of_ty_query(
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(
- "unevaluated or mistyped const generic parameter".to_string(),
- ))? as u64;
+ let count = try_const_usize(db, &count).ok_or(LayoutError::UserError(Box::from(
+ "unevaluated or mistyped const generic parameter",
+ )))? 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)?;
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 1c92e80f3..85ef649b8 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
@@ -163,7 +163,7 @@ fn repr_discr(
return Err(LayoutError::UserError(
"Integer::repr_discr: `#[repr]` hint too small for \
discriminant range of enum "
- .to_string(),
+ .into(),
));
}
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 333ad473a..ffdbb9de9 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
@@ -212,14 +212,14 @@ fn recursive() {
}
check_fail(
r#"struct Goal(Goal);"#,
- LayoutError::UserError("infinite sized recursive type".to_string()),
+ LayoutError::UserError("infinite sized recursive type".into()),
);
check_fail(
r#"
struct Foo<T>(Foo<T>);
struct Goal(Foo<i32>);
"#,
- LayoutError::UserError("infinite sized recursive type".to_string()),
+ LayoutError::UserError("infinite sized recursive type".into()),
);
}
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 576e7f3fc..bbe855a14 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
@@ -255,3 +255,17 @@ fn ellipsis_pattern() {
}
}
}
+
+#[test]
+fn regression_15623() {
+ size_and_align_expr! {
+ let a = 2;
+ let b = 3;
+ let c = 5;
+ move || {
+ let 0 = a else { return b; };
+ let y = c;
+ y
+ }
+ }
+}
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 b3ca2a222..405bb001b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
@@ -52,12 +52,14 @@ use hir_expand::name;
use la_arena::{Arena, Idx};
use mir::{MirEvalError, VTableMap};
use rustc_hash::FxHashSet;
+use syntax::ast::{make, ConstArg};
use traits::FnTrait;
use triomphe::Arc;
use utils::Generics;
use crate::{
- consteval::unknown_const, db::HirDatabase, infer::unify::InferenceTable, utils::generics,
+ consteval::unknown_const, db::HirDatabase, display::HirDisplay, infer::unify::InferenceTable,
+ utils::generics,
};
pub use autoderef::autoderef;
@@ -719,3 +721,16 @@ where
value.visit_with(&mut collector, DebruijnIndex::INNERMOST);
collector.placeholders.into_iter().collect()
}
+
+pub fn known_const_to_ast(konst: &Const, db: &dyn HirDatabase) -> Option<ConstArg> {
+ if let ConstValue::Concrete(c) = &konst.interned().value {
+ match c.interned {
+ ConstScalar::UnevaluatedConst(GeneralConstId::InTypeConstId(cid), _) => {
+ return Some(cid.source(db.upcast()));
+ }
+ ConstScalar::Unknown => return None,
+ _ => (),
+ }
+ }
+ Some(make::expr_const_value(konst.display(db).to_string().as_str()))
+}
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 2837f400b..9a61f1535 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -58,10 +58,9 @@ use crate::{
InTypeConstIdMetadata,
},
AliasEq, AliasTy, Binders, BoundVar, CallableSig, Const, ConstScalar, DebruijnIndex, DynTy,
- FnPointer, FnSig, FnSubst, GenericArgData, ImplTraitId, Interner, ParamKind, PolyFnSig,
- ProjectionTy, QuantifiedWhereClause, QuantifiedWhereClauses, ReturnTypeImplTrait,
- ReturnTypeImplTraits, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder,
- TyKind, WhereClause,
+ FnPointer, FnSig, FnSubst, ImplTraitId, Interner, ParamKind, PolyFnSig, ProjectionTy,
+ QuantifiedWhereClause, QuantifiedWhereClauses, ReturnTypeImplTrait, ReturnTypeImplTraits,
+ Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, WhereClause,
};
#[derive(Debug)]
@@ -213,6 +212,19 @@ impl<'a> TyLoweringContext<'a> {
self.lower_ty_ext(type_ref).0
}
+ pub fn lower_const(&self, const_ref: &ConstRef, const_type: Ty) -> Const {
+ const_or_path_to_chalk(
+ self.db,
+ self.resolver,
+ self.owner,
+ const_type,
+ const_ref,
+ self.type_param_mode,
+ || self.generics(),
+ self.in_binders,
+ )
+ }
+
fn generics(&self) -> Generics {
generics(
self.db.upcast(),
@@ -242,17 +254,7 @@ impl<'a> TyLoweringContext<'a> {
}
TypeRef::Array(inner, len) => {
let inner_ty = self.lower_ty(inner);
- let const_len = const_or_path_to_chalk(
- self.db,
- self.resolver,
- self.owner,
- TyBuilder::usize(),
- len,
- self.type_param_mode,
- || self.generics(),
- self.in_binders,
- );
-
+ let const_len = self.lower_const(len, TyBuilder::usize());
TyKind::Array(inner_ty, const_len).intern(Interner)
}
TypeRef::Slice(inner) => {
@@ -391,11 +393,9 @@ impl<'a> TyLoweringContext<'a> {
let ty = {
let macro_call = macro_call.to_node(self.db.upcast());
let resolver = |path| {
- self.resolver.resolve_path_as_macro(
- self.db.upcast(),
- &path,
- Some(MacroSubNs::Bang),
- )
+ self.resolver
+ .resolve_path_as_macro(self.db.upcast(), &path, Some(MacroSubNs::Bang))
+ .map(|(it, _)| it)
};
match expander.enter_expand::<ast::Type>(self.db.upcast(), macro_call, resolver)
{
@@ -447,7 +447,7 @@ impl<'a> TyLoweringContext<'a> {
return None;
}
let resolution = match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path) {
- Some((it, None)) => it,
+ Some((it, None, _)) => it,
_ => return None,
};
match resolution {
@@ -627,7 +627,7 @@ impl<'a> TyLoweringContext<'a> {
return self.lower_ty_relative_path(ty, res, path.segments());
}
- let (resolution, remaining_index) =
+ let (resolution, remaining_index, _) =
match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path) {
Some(it) => it,
None => return (TyKind::Error.intern(Interner), None),
@@ -847,18 +847,7 @@ impl<'a> TyLoweringContext<'a> {
arg,
&mut (),
|_, type_ref| self.lower_ty(type_ref),
- |_, c, ty| {
- const_or_path_to_chalk(
- self.db,
- self.resolver,
- self.owner,
- ty,
- c,
- self.type_param_mode,
- || self.generics(),
- self.in_binders,
- )
- },
+ |_, const_ref, ty| self.lower_const(const_ref, ty),
) {
had_explicit_args = true;
substs.push(x);
@@ -1604,24 +1593,35 @@ pub(crate) fn generic_defaults_query(
.iter()
.enumerate()
.map(|(idx, (id, p))| {
- let p = match p {
- TypeOrConstParamData::TypeParamData(p) => p,
- TypeOrConstParamData::ConstParamData(_) => {
- // FIXME: implement const generic defaults
- let val = unknown_const_as_generic(
- db.const_param_ty(ConstParamId::from_unchecked(id)),
+ 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)
+ },
);
- return make_binders(db, &generic_params, val);
+ // 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)
}
- };
- 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))
+ }
})
// FIXME: use `Arc::from_iter` when it becomes available
.collect::<Vec<_>>(),
@@ -1643,9 +1643,7 @@ pub(crate) fn generic_defaults_recover(
.iter_id()
.map(|id| {
let val = match id {
- Either::Left(_) => {
- GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner)
- }
+ 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)
@@ -1991,16 +1989,9 @@ pub(crate) fn generic_arg_to_chalk<'a, T>(
}
};
Some(match (arg, kind) {
- (GenericArg::Type(type_ref), ParamKind::Type) => {
- let ty = for_type(this, type_ref);
- GenericArgData::Ty(ty).intern(Interner)
- }
- (GenericArg::Const(c), ParamKind::Const(c_ty)) => {
- GenericArgData::Const(for_const(this, c, c_ty)).intern(Interner)
- }
- (GenericArg::Const(_), ParamKind::Type) => {
- GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner)
- }
+ (GenericArg::Type(type_ref), ParamKind::Type) => for_type(this, type_ref).cast(Interner),
+ (GenericArg::Const(c), ParamKind::Const(c_ty)) => for_const(this, c, c_ty).cast(Interner),
+ (GenericArg::Const(_), ParamKind::Type) => TyKind::Error.intern(Interner).cast(Interner),
(GenericArg::Type(t), ParamKind::Const(c_ty)) => {
// We want to recover simple idents, which parser detects them
// as types. Maybe here is not the best place to do it, but
@@ -2010,9 +2001,7 @@ pub(crate) fn generic_arg_to_chalk<'a, T>(
if p.kind == PathKind::Plain {
if let [n] = p.segments() {
let c = ConstRef::Path(n.clone());
- return Some(
- GenericArgData::Const(for_const(this, &c, c_ty)).intern(Interner),
- );
+ return Some(for_const(this, &c, c_ty).cast(Interner));
}
}
}
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 4723c25ed..e953058cc 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
@@ -1,6 +1,6 @@
//! MIR definitions and implementation
-use std::{fmt::Display, iter};
+use std::{collections::hash_map::Entry, fmt::Display, iter};
use crate::{
consteval::usize_const,
@@ -37,6 +37,7 @@ pub use monomorphization::{
monomorphize_mir_body_bad, monomorphized_mir_body_for_closure_query,
monomorphized_mir_body_query, monomorphized_mir_body_recover,
};
+use rustc_hash::FxHashMap;
use smallvec::{smallvec, SmallVec};
use stdx::{impl_from, never};
use triomphe::Arc;
@@ -165,8 +166,8 @@ impl<V, T> ProjectionElem<V, T> {
TyKind::Adt(_, subst) => {
db.field_types(f.parent)[f.local_id].clone().substitute(Interner, subst)
}
- _ => {
- never!("Only adt has field");
+ ty => {
+ never!("Only adt has field, found {:?}", ty);
return TyKind::Error.intern(Interner);
}
},
@@ -223,35 +224,93 @@ impl<V, T> ProjectionElem<V, T> {
type PlaceElem = ProjectionElem<LocalId, Ty>;
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct ProjectionId(u32);
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct ProjectionStore {
+ id_to_proj: FxHashMap<ProjectionId, Box<[PlaceElem]>>,
+ proj_to_id: FxHashMap<Box<[PlaceElem]>, ProjectionId>,
+}
+
+impl Default for ProjectionStore {
+ fn default() -> Self {
+ let mut this = Self { id_to_proj: Default::default(), proj_to_id: Default::default() };
+ // Ensure that [] will get the id 0 which is used in `ProjectionId::Empty`
+ this.intern(Box::new([]));
+ this
+ }
+}
+
+impl ProjectionStore {
+ 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> {
+ self.proj_to_id.get(projection).copied()
+ }
+
+ 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(),
+ Entry::Vacant(e) => {
+ let key_clone = e.key().clone();
+ e.insert(new_id);
+ self.id_to_proj.insert(new_id, key_clone);
+ new_id
+ }
+ }
+ }
+}
+
+impl ProjectionId {
+ const EMPTY: ProjectionId = ProjectionId(0);
+
+ fn lookup(self, store: &ProjectionStore) -> &[PlaceElem] {
+ store.id_to_proj.get(&self).unwrap()
+ }
+
+ 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)]
pub struct Place {
pub local: LocalId,
- pub projection: Box<[PlaceElem]>,
+ pub projection: ProjectionId,
}
impl Place {
- fn is_parent(&self, child: &Place) -> bool {
- self.local == child.local && child.projection.starts_with(&self.projection)
+ fn is_parent(&self, child: &Place, store: &ProjectionStore) -> bool {
+ self.local == child.local
+ && child.projection.lookup(store).starts_with(&self.projection.lookup(store))
}
/// The place itself is not included
- fn iterate_over_parents(&self) -> impl Iterator<Item = Place> + '_ {
- (0..self.projection.len())
- .map(|x| &self.projection[0..x])
- .map(|x| Place { local: self.local, projection: x.to_vec().into() })
+ fn iterate_over_parents<'a>(
+ &'a self,
+ store: &'a ProjectionStore,
+ ) -> impl Iterator<Item = Place> + 'a {
+ let projection = self.projection.lookup(store);
+ (0..projection.len()).map(|x| &projection[0..x]).filter_map(move |x| {
+ Some(Place { local: self.local, projection: store.intern_if_exist(x)? })
+ })
}
- fn project(&self, projection: PlaceElem) -> Place {
- Place {
- local: self.local,
- projection: self.projection.iter().cloned().chain([projection]).collect(),
- }
+ fn project(&self, projection: PlaceElem, store: &mut ProjectionStore) -> Place {
+ Place { local: self.local, projection: self.projection.project(projection, store) }
}
}
impl From<LocalId> for Place {
fn from(local: LocalId) -> Self {
- Self { local, projection: vec![].into() }
+ Self { local, projection: ProjectionId::EMPTY }
}
}
@@ -368,7 +427,7 @@ pub enum TerminatorKind {
///
/// Only permitted in cleanup blocks. `Resume` is not permitted with `-C unwind=abort` after
/// deaggregation runs.
- Resume,
+ UnwindResume,
/// Indicates that the landing pad is finished and that the process should abort.
///
@@ -997,6 +1056,7 @@ pub struct BasicBlock {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MirBody {
+ pub projection_store: ProjectionStore,
pub basic_blocks: Arena<BasicBlock>,
pub locals: Arena<Local>,
pub start_block: BasicBlockId,
@@ -1009,11 +1069,15 @@ pub struct MirBody {
}
impl MirBody {
- fn walk_places(&mut self, mut f: impl FnMut(&mut Place)) {
- fn for_operand(op: &mut Operand, f: &mut impl FnMut(&mut Place)) {
+ fn walk_places(&mut self, mut f: impl FnMut(&mut Place, &mut ProjectionStore)) {
+ fn for_operand(
+ op: &mut Operand,
+ f: &mut impl FnMut(&mut Place, &mut ProjectionStore),
+ store: &mut ProjectionStore,
+ ) {
match op {
Operand::Copy(p) | Operand::Move(p) => {
- f(p);
+ f(p, store);
}
Operand::Constant(_) | Operand::Static(_) => (),
}
@@ -1022,30 +1086,30 @@ impl MirBody {
for statement in &mut block.statements {
match &mut statement.kind {
StatementKind::Assign(p, r) => {
- f(p);
+ f(p, &mut self.projection_store);
match r {
Rvalue::ShallowInitBoxWithAlloc(_) => (),
Rvalue::ShallowInitBox(o, _)
| Rvalue::UnaryOp(_, o)
| Rvalue::Cast(_, o, _)
| Rvalue::Repeat(o, _)
- | Rvalue::Use(o) => for_operand(o, &mut f),
+ | Rvalue::Use(o) => for_operand(o, &mut f, &mut self.projection_store),
Rvalue::CopyForDeref(p)
| Rvalue::Discriminant(p)
| Rvalue::Len(p)
- | Rvalue::Ref(_, p) => f(p),
+ | Rvalue::Ref(_, p) => f(p, &mut self.projection_store),
Rvalue::CheckedBinaryOp(_, o1, o2) => {
- for_operand(o1, &mut f);
- for_operand(o2, &mut f);
+ for_operand(o1, &mut f, &mut self.projection_store);
+ for_operand(o2, &mut f, &mut self.projection_store);
}
Rvalue::Aggregate(_, ops) => {
for op in ops.iter_mut() {
- for_operand(op, &mut f);
+ for_operand(op, &mut f, &mut self.projection_store);
}
}
}
}
- StatementKind::Deinit(p) => f(p),
+ StatementKind::Deinit(p) => f(p, &mut self.projection_store),
StatementKind::StorageLive(_)
| StatementKind::StorageDead(_)
| StatementKind::Nop => (),
@@ -1053,33 +1117,36 @@ impl MirBody {
}
match &mut block.terminator {
Some(x) => match &mut x.kind {
- TerminatorKind::SwitchInt { discr, .. } => for_operand(discr, &mut f),
+ TerminatorKind::SwitchInt { discr, .. } => {
+ for_operand(discr, &mut f, &mut self.projection_store)
+ }
TerminatorKind::FalseEdge { .. }
| TerminatorKind::FalseUnwind { .. }
| TerminatorKind::Goto { .. }
- | TerminatorKind::Resume
+ | TerminatorKind::UnwindResume
| TerminatorKind::GeneratorDrop
| TerminatorKind::Abort
| TerminatorKind::Return
| TerminatorKind::Unreachable => (),
TerminatorKind::Drop { place, .. } => {
- f(place);
+ f(place, &mut self.projection_store);
}
TerminatorKind::DropAndReplace { place, value, .. } => {
- f(place);
- for_operand(value, &mut f);
+ f(place, &mut self.projection_store);
+ for_operand(value, &mut f, &mut self.projection_store);
}
TerminatorKind::Call { func, args, destination, .. } => {
- for_operand(func, &mut f);
- args.iter_mut().for_each(|x| for_operand(x, &mut f));
- f(destination);
+ for_operand(func, &mut f, &mut self.projection_store);
+ args.iter_mut()
+ .for_each(|x| for_operand(x, &mut f, &mut self.projection_store));
+ f(destination, &mut self.projection_store);
}
TerminatorKind::Assert { cond, .. } => {
- for_operand(cond, &mut f);
+ for_operand(cond, &mut f, &mut self.projection_store);
}
TerminatorKind::Yield { value, resume_arg, .. } => {
- for_operand(value, &mut f);
- f(resume_arg);
+ for_operand(value, &mut f, &mut self.projection_store);
+ f(resume_arg, &mut self.projection_store);
}
},
None => (),
@@ -1096,7 +1163,9 @@ impl MirBody {
binding_locals,
param_locals,
closures,
+ projection_store,
} = self;
+ projection_store.shrink_to_fit();
basic_blocks.shrink_to_fit();
locals.shrink_to_fit();
binding_locals.shrink_to_fit();
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 ad98e8fa1..41fb12965 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
@@ -42,30 +42,27 @@ pub struct BorrowckResult {
fn all_mir_bodies(
db: &dyn HirDatabase,
def: DefWithBodyId,
-) -> Box<dyn Iterator<Item = Result<Arc<MirBody>, MirLowerError>> + '_> {
+ mut cb: impl FnMut(Arc<MirBody>),
+) -> Result<(), MirLowerError> {
fn for_closure(
db: &dyn HirDatabase,
c: ClosureId,
- ) -> Box<dyn Iterator<Item = Result<Arc<MirBody>, MirLowerError>> + '_> {
+ cb: &mut impl FnMut(Arc<MirBody>),
+ ) -> Result<(), MirLowerError> {
match db.mir_body_for_closure(c) {
Ok(body) => {
- let closures = body.closures.clone();
- Box::new(
- iter::once(Ok(body))
- .chain(closures.into_iter().flat_map(|it| for_closure(db, it))),
- )
+ cb(body.clone());
+ body.closures.iter().map(|&it| for_closure(db, it, cb)).collect()
}
- Err(e) => Box::new(iter::once(Err(e))),
+ Err(e) => Err(e),
}
}
match db.mir_body(def) {
Ok(body) => {
- let closures = body.closures.clone();
- Box::new(
- iter::once(Ok(body)).chain(closures.into_iter().flat_map(|it| for_closure(db, it))),
- )
+ cb(body.clone());
+ body.closures.iter().map(|&it| for_closure(db, it, &mut cb)).collect()
}
- Err(e) => Box::new(iter::once(Err(e))),
+ Err(e) => Err(e),
}
}
@@ -74,17 +71,15 @@ pub fn borrowck_query(
def: DefWithBodyId,
) -> Result<Arc<[BorrowckResult]>, MirLowerError> {
let _p = profile::span("borrowck_query");
- let r = all_mir_bodies(db, def)
- .map(|body| {
- let body = body?;
- Ok(BorrowckResult {
- mutability_of_locals: mutability_of_locals(db, &body),
- moved_out_of_ref: moved_out_of_ref(db, &body),
- mir_body: body,
- })
- })
- .collect::<Result<Vec<_>, MirLowerError>>()?;
- Ok(r.into())
+ let mut res = vec![];
+ all_mir_bodies(db, def, |body| {
+ res.push(BorrowckResult {
+ mutability_of_locals: mutability_of_locals(db, &body),
+ moved_out_of_ref: moved_out_of_ref(db, &body),
+ mir_body: body,
+ });
+ })?;
+ Ok(res.into())
}
fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef> {
@@ -93,7 +88,7 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef>
Operand::Copy(p) | Operand::Move(p) => {
let mut ty: Ty = body.locals[p.local].ty.clone();
let mut is_dereference_of_ref = false;
- for proj in &*p.projection {
+ for proj in p.projection.lookup(&body.projection_store) {
if *proj == ProjectionElem::Deref && ty.as_reference().is_some() {
is_dereference_of_ref = true;
}
@@ -125,6 +120,7 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef>
Operand::Constant(_) | Operand::Static(_) => (),
};
for (_, block) in body.basic_blocks.iter() {
+ db.unwind_if_cancelled();
for statement in &block.statements {
match &statement.kind {
StatementKind::Assign(_, r) => match r {
@@ -160,7 +156,7 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef>
TerminatorKind::FalseEdge { .. }
| TerminatorKind::FalseUnwind { .. }
| TerminatorKind::Goto { .. }
- | TerminatorKind::Resume
+ | TerminatorKind::UnwindResume
| TerminatorKind::GeneratorDrop
| TerminatorKind::Abort
| TerminatorKind::Return
@@ -183,6 +179,7 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef>
None => (),
}
}
+ result.shrink_to_fit();
result
}
@@ -199,7 +196,7 @@ enum ProjectionCase {
fn place_case(db: &dyn HirDatabase, body: &MirBody, lvalue: &Place) -> ProjectionCase {
let mut is_part_of = false;
let mut ty = body.locals[lvalue.local].ty.clone();
- for proj in lvalue.projection.iter() {
+ for proj in lvalue.projection.lookup(&body.projection_store).iter() {
match proj {
ProjectionElem::Deref if ty.as_adt().is_none() => return ProjectionCase::Indirect, // It's indirect in case of reference and raw
ProjectionElem::Deref // It's direct in case of `Box<T>`
@@ -258,7 +255,7 @@ fn ever_initialized_map(
for statement in &block.statements {
match &statement.kind {
StatementKind::Assign(p, _) => {
- if p.projection.len() == 0 && p.local == l {
+ if p.projection.lookup(&body.projection_store).len() == 0 && p.local == l {
is_ever_initialized = true;
}
}
@@ -277,21 +274,37 @@ fn ever_initialized_map(
);
return;
};
- let targets = match &terminator.kind {
- TerminatorKind::Goto { target } => vec![*target],
- TerminatorKind::SwitchInt { targets, .. } => targets.all_targets().to_vec(),
- TerminatorKind::Resume
+ let mut process = |target, is_ever_initialized| {
+ if !result[target].contains_idx(l) || !result[target][l] && is_ever_initialized {
+ result[target].insert(l, is_ever_initialized);
+ dfs(db, body, target, l, result);
+ }
+ };
+ match &terminator.kind {
+ TerminatorKind::Goto { target } => process(*target, is_ever_initialized),
+ TerminatorKind::SwitchInt { targets, .. } => {
+ targets.all_targets().iter().for_each(|&it| process(it, is_ever_initialized));
+ }
+ TerminatorKind::UnwindResume
| TerminatorKind::Abort
| TerminatorKind::Return
- | TerminatorKind::Unreachable => vec![],
+ | TerminatorKind::Unreachable => (),
TerminatorKind::Call { target, cleanup, destination, .. } => {
- if destination.projection.len() == 0 && destination.local == l {
+ if destination.projection.lookup(&body.projection_store).len() == 0
+ && destination.local == l
+ {
is_ever_initialized = true;
}
- target.into_iter().chain(cleanup.into_iter()).copied().collect()
+ target
+ .into_iter()
+ .chain(cleanup.into_iter())
+ .for_each(|&it| process(it, is_ever_initialized));
}
TerminatorKind::Drop { target, unwind, place: _ } => {
- Some(target).into_iter().chain(unwind.into_iter()).copied().collect()
+ iter::once(target)
+ .into_iter()
+ .chain(unwind.into_iter())
+ .for_each(|&it| process(it, is_ever_initialized));
}
TerminatorKind::DropAndReplace { .. }
| TerminatorKind::Assert { .. }
@@ -300,13 +313,7 @@ fn ever_initialized_map(
| TerminatorKind::FalseEdge { .. }
| TerminatorKind::FalseUnwind { .. } => {
never!("We don't emit these MIR terminators yet");
- vec![]
- }
- };
- for target in targets {
- if !result[target].contains_idx(l) || !result[target][l] && is_ever_initialized {
- result[target].insert(l, is_ever_initialized);
- dfs(db, body, target, l, result);
+ ()
}
}
}
@@ -315,6 +322,7 @@ fn ever_initialized_map(
dfs(db, body, body.start_block, l, &mut result);
}
for l in body.locals.iter().map(|it| it.0) {
+ db.unwind_if_cancelled();
if !result[body.start_block].contains_idx(l) {
result[body.start_block].insert(l, false);
dfs(db, body, body.start_block, l, &mut result);
@@ -371,7 +379,7 @@ fn mutability_of_locals(
};
match &terminator.kind {
TerminatorKind::Goto { .. }
- | TerminatorKind::Resume
+ | TerminatorKind::UnwindResume
| TerminatorKind::Abort
| TerminatorKind::Return
| TerminatorKind::Unreachable
@@ -384,7 +392,7 @@ fn mutability_of_locals(
| TerminatorKind::Assert { .. }
| TerminatorKind::Yield { .. } => (),
TerminatorKind::Call { destination, .. } => {
- if destination.projection.len() == 0 {
+ 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);
} else {
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 9e30eed56..4364e0d32 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
@@ -10,7 +10,7 @@ use std::{
};
use base_db::{CrateId, FileId};
-use chalk_ir::Mutability;
+use chalk_ir::{cast::Cast, Mutability};
use either::Either;
use hir_def::{
builtin_type::BuiltinType,
@@ -40,14 +40,14 @@ use crate::{
name, static_lifetime,
traits::FnTrait,
utils::{detect_variant_from_bytes, ClosureSubst},
- CallableDefId, ClosureId, Const, ConstScalar, FnDefId, GenericArgData, Interner, MemoryMap,
- Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind,
+ CallableDefId, ClosureId, Const, ConstScalar, FnDefId, Interner, MemoryMap, Substitution,
+ TraitEnvironment, Ty, TyBuilder, TyExt, TyKind,
};
use super::{
return_slot, AggregateKind, BasicBlockId, BinOp, CastKind, LocalId, MirBody, MirLowerError,
- MirSpan, Operand, Place, PlaceElem, ProjectionElem, Rvalue, StatementKind, TerminatorKind,
- UnOp,
+ MirSpan, Operand, Place, PlaceElem, ProjectionElem, ProjectionStore, Rvalue, StatementKind,
+ TerminatorKind, UnOp,
};
mod shim;
@@ -215,9 +215,7 @@ impl Interval {
}
fn write_from_interval(&self, memory: &mut Evaluator<'_>, interval: Interval) -> Result<()> {
- // FIXME: this could be more efficient
- let bytes = &interval.get(memory)?.to_vec();
- memory.write_memory(self.addr, bytes)
+ memory.copy_from_interval(self.addr, interval)
}
fn slice(self, range: Range<usize>) -> Interval {
@@ -341,7 +339,7 @@ pub enum MirEvalError {
InvalidVTableId(usize),
CoerceUnsizedError(Ty),
LangItemNotFound(LangItem),
- BrokenLayout(Layout),
+ BrokenLayout(Box<Layout>),
}
impl MirEvalError {
@@ -410,7 +408,7 @@ impl MirEvalError {
err.pretty_print(f, db, span_formatter)?;
}
MirEvalError::ConstEvalError(name, err) => {
- MirLowerError::ConstEvalError(name.clone(), err.clone()).pretty_print(
+ MirLowerError::ConstEvalError((**name).into(), err.clone()).pretty_print(
f,
db,
span_formatter,
@@ -485,17 +483,18 @@ struct DropFlags {
}
impl DropFlags {
- fn add_place(&mut self, p: Place) {
- if p.iterate_over_parents().any(|it| self.need_drop.contains(&it)) {
+ fn add_place(&mut self, p: Place, store: &ProjectionStore) {
+ if p.iterate_over_parents(store).any(|it| self.need_drop.contains(&it)) {
return;
}
- self.need_drop.retain(|it| !p.is_parent(it));
+ self.need_drop.retain(|it| !p.is_parent(it, store));
self.need_drop.insert(p);
}
- fn remove_place(&mut self, p: &Place) -> bool {
+ fn remove_place(&mut self, p: &Place, store: &ProjectionStore) -> bool {
// FIXME: replace parents with parts
- if let Some(parent) = p.iterate_over_parents().find(|it| self.need_drop.contains(&it)) {
+ if let Some(parent) = p.iterate_over_parents(store).find(|it| self.need_drop.contains(&it))
+ {
self.need_drop.remove(&parent);
return true;
}
@@ -656,7 +655,7 @@ impl Evaluator<'_> {
let mut addr = locals.ptr[p.local].addr;
let mut ty: Ty = locals.body.locals[p.local].ty.clone();
let mut metadata: Option<IntervalOrOwned> = None; // locals are always sized
- for proj in &*p.projection {
+ for proj in p.projection.lookup(&locals.body.projection_store) {
let prev_ty = ty.clone();
ty = self.projected_ty(ty, proj.clone());
match proj {
@@ -837,7 +836,9 @@ impl Evaluator<'_> {
let addr = self.place_addr(l, &locals)?;
let result = self.eval_rvalue(r, &mut locals)?.to_vec(&self)?;
self.write_memory(addr, &result)?;
- locals.drop_flags.add_place(l.clone());
+ locals
+ .drop_flags
+ .add_place(l.clone(), &locals.body.projection_store);
}
StatementKind::Deinit(_) => not_supported!("de-init statement"),
StatementKind::StorageLive(_)
@@ -889,7 +890,9 @@ impl Evaluator<'_> {
)?,
it => not_supported!("unknown function type {it:?}"),
};
- locals.drop_flags.add_place(destination.clone());
+ locals
+ .drop_flags
+ .add_place(destination.clone(), &locals.body.projection_store);
if let Some(stack_frame) = stack_frame {
self.code_stack.push(my_stack_frame);
current_block_idx = stack_frame.locals.body.start_block;
@@ -970,7 +973,7 @@ impl Evaluator<'_> {
) -> Result<()> {
let mut remain_args = body.param_locals.len();
for ((l, interval), value) in locals.ptr.iter().skip(1).zip(args) {
- locals.drop_flags.add_place(l.into());
+ locals.drop_flags.add_place(l.into(), &locals.body.projection_store);
match value {
IntervalOrOwned::Owned(value) => interval.write_from_bytes(self, &value)?,
IntervalOrOwned::Borrowed(value) => interval.write_from_interval(self, value)?,
@@ -1629,7 +1632,7 @@ impl Evaluator<'_> {
if let Some((offset, size, value)) = tag {
match result.get_mut(offset..offset + size) {
Some(it) => it.copy_from_slice(&value.to_le_bytes()[0..size]),
- None => return Err(MirEvalError::BrokenLayout(variant_layout.clone())),
+ None => return Err(MirEvalError::BrokenLayout(Box::new(variant_layout.clone()))),
}
}
for (i, op) in values.enumerate() {
@@ -1637,7 +1640,7 @@ impl Evaluator<'_> {
let op = op.get(&self)?;
match result.get_mut(offset..offset + op.len()) {
Some(it) => it.copy_from_slice(op),
- None => return Err(MirEvalError::BrokenLayout(variant_layout.clone())),
+ None => return Err(MirEvalError::BrokenLayout(Box::new(variant_layout.clone()))),
}
}
Ok(result)
@@ -1646,7 +1649,7 @@ impl Evaluator<'_> {
fn eval_operand(&mut self, it: &Operand, locals: &mut Locals) -> Result<Interval> {
Ok(match it {
Operand::Copy(p) | Operand::Move(p) => {
- locals.drop_flags.remove_place(p);
+ locals.drop_flags.remove_place(p, &locals.body.projection_store);
self.eval_place(p, locals)?
}
Operand::Static(st) => {
@@ -1760,6 +1763,48 @@ impl Evaluator<'_> {
Ok(())
}
+ fn copy_from_interval(&mut self, addr: Address, r: Interval) -> Result<()> {
+ if r.size == 0 {
+ return Ok(());
+ }
+
+ let oob = || MirEvalError::UndefinedBehavior("out of bounds memory write".to_string());
+
+ match (addr, r.addr) {
+ (Stack(dst), Stack(src)) => {
+ if self.stack.len() < src + r.size || self.stack.len() < dst + r.size {
+ return Err(oob());
+ }
+ self.stack.copy_within(src..src + r.size, dst)
+ }
+ (Heap(dst), Heap(src)) => {
+ if self.stack.len() < src + r.size || self.stack.len() < dst + r.size {
+ return Err(oob());
+ }
+ self.heap.copy_within(src..src + r.size, dst)
+ }
+ (Stack(dst), Heap(src)) => {
+ self.stack
+ .get_mut(dst..dst + r.size)
+ .ok_or_else(oob)?
+ .copy_from_slice(self.heap.get(src..src + r.size).ok_or_else(oob)?);
+ }
+ (Heap(dst), Stack(src)) => {
+ self.heap
+ .get_mut(dst..dst + r.size)
+ .ok_or_else(oob)?
+ .copy_from_slice(self.stack.get(src..src + r.size).ok_or_else(oob)?);
+ }
+ _ => {
+ return Err(MirEvalError::UndefinedBehavior(format!(
+ "invalid memory write at address {addr:?}"
+ )))
+ }
+ }
+
+ Ok(())
+ }
+
fn size_align_of(&self, ty: &Ty, locals: &Locals) -> Result<Option<(usize, usize)>> {
if let Some(layout) = self.layout_cache.borrow().get(ty) {
return Ok(layout
@@ -2007,7 +2052,28 @@ impl Evaluator<'_> {
}
}
AdtId::UnionId(_) => (),
- AdtId::EnumId(_) => (),
+ AdtId::EnumId(e) => {
+ if let Some((variant, layout)) = detect_variant_from_bytes(
+ &layout,
+ self.db,
+ self.trait_env.clone(),
+ self.read_memory(addr, layout.size.bytes_usize())?,
+ e,
+ ) {
+ let ev = EnumVariantId { parent: e, local_id: variant };
+ for (i, (_, ty)) in self.db.field_types(ev.into()).iter().enumerate() {
+ let offset = layout.fields.offset(i).bytes_usize();
+ let ty = ty.clone().substitute(Interner, subst);
+ self.patch_addresses(
+ patch_map,
+ old_vtable,
+ addr.offset(offset),
+ &ty,
+ locals,
+ )?;
+ }
+ }
+ }
},
TyKind::Tuple(_, subst) => {
for (id, ty) in subst.iter(Interner).enumerate() {
@@ -2248,7 +2314,7 @@ impl Evaluator<'_> {
interval: args_for_target[0].interval.slice(0..self.ptr_size()),
ty: ty.clone(),
};
- let ty = GenericArgData::Ty(ty.clone()).intern(Interner);
+ let ty = ty.clone().cast(Interner);
let generics_for_target = Substitution::from_iter(
Interner,
generic_args.iter(Interner).enumerate().map(|(i, it)| {
@@ -2447,7 +2513,7 @@ impl Evaluator<'_> {
fn drop_place(&mut self, place: &Place, locals: &mut Locals, span: MirSpan) -> Result<()> {
let (addr, ty, metadata) = self.place_addr_and_ty_and_metadata(place, locals)?;
- if !locals.drop_flags.remove_place(place) {
+ if !locals.drop_flags.remove_place(place, &locals.body.projection_store) {
return Ok(());
}
let metadata = match metadata {
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 b2e29fd34..803ef631f 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
@@ -4,7 +4,10 @@
use std::cmp;
use chalk_ir::TyKind;
-use hir_def::resolver::HasResolver;
+use hir_def::{
+ builtin_type::{BuiltinInt, BuiltinUint},
+ resolver::HasResolver,
+};
use hir_expand::mod_path::ModPath;
use super::*;
@@ -136,7 +139,10 @@ impl Evaluator<'_> {
not_supported!("wrong generic arg kind for clone");
};
// Clone has special impls for tuples and function pointers
- if matches!(self_ty.kind(Interner), TyKind::Function(_) | TyKind::Tuple(..)) {
+ if matches!(
+ self_ty.kind(Interner),
+ TyKind::Function(_) | TyKind::Tuple(..) | TyKind::Closure(..)
+ ) {
self.exec_clone(def, args, self_ty.clone(), locals, destination, span)?;
return Ok(true);
}
@@ -167,32 +173,26 @@ impl Evaluator<'_> {
return destination
.write_from_interval(self, Interval { addr, size: destination.size });
}
+ TyKind::Closure(id, subst) => {
+ let [arg] = args else {
+ not_supported!("wrong arg count for clone");
+ };
+ let addr = Address::from_bytes(arg.get(self)?)?;
+ let (closure_owner, _) = self.db.lookup_intern_closure((*id).into());
+ let infer = self.db.infer(closure_owner);
+ let (captures, _) = infer.closure_info(id);
+ let layout = self.layout(&self_ty)?;
+ let ty_iter = captures.iter().map(|c| c.ty(subst));
+ self.exec_clone_for_fields(ty_iter, layout, addr, def, locals, destination, span)?;
+ }
TyKind::Tuple(_, subst) => {
let [arg] = args else {
not_supported!("wrong arg count for clone");
};
let addr = Address::from_bytes(arg.get(self)?)?;
let layout = self.layout(&self_ty)?;
- for (i, ty) in subst.iter(Interner).enumerate() {
- let ty = ty.assert_ty_ref(Interner);
- let size = self.layout(ty)?.size.bytes_usize();
- let tmp = self.heap_allocate(self.ptr_size(), self.ptr_size())?;
- let arg = IntervalAndTy {
- interval: Interval { addr: tmp, size: self.ptr_size() },
- ty: TyKind::Ref(Mutability::Not, static_lifetime(), ty.clone())
- .intern(Interner),
- };
- let offset = layout.fields.offset(i).bytes_usize();
- self.write_memory(tmp, &addr.offset(offset).to_bytes())?;
- self.exec_clone(
- def,
- &[arg],
- ty.clone(),
- locals,
- destination.slice(offset..offset + size),
- span,
- )?;
- }
+ let ty_iter = subst.iter(Interner).map(|ga| ga.assert_ty_ref(Interner).clone());
+ self.exec_clone_for_fields(ty_iter, layout, addr, def, locals, destination, span)?;
}
_ => {
self.exec_fn_with_args(
@@ -209,6 +209,37 @@ impl Evaluator<'_> {
Ok(())
}
+ fn exec_clone_for_fields(
+ &mut self,
+ ty_iter: impl Iterator<Item = Ty>,
+ layout: Arc<Layout>,
+ addr: Address,
+ def: FunctionId,
+ locals: &Locals,
+ destination: Interval,
+ span: MirSpan,
+ ) -> Result<()> {
+ for (i, ty) in ty_iter.enumerate() {
+ let size = self.layout(&ty)?.size.bytes_usize();
+ let tmp = self.heap_allocate(self.ptr_size(), self.ptr_size())?;
+ let arg = IntervalAndTy {
+ interval: Interval { addr: tmp, size: self.ptr_size() },
+ ty: TyKind::Ref(Mutability::Not, static_lifetime(), ty.clone()).intern(Interner),
+ };
+ let offset = layout.fields.offset(i).bytes_usize();
+ self.write_memory(tmp, &addr.offset(offset).to_bytes())?;
+ self.exec_clone(
+ def,
+ &[arg],
+ ty,
+ locals,
+ destination.slice(offset..offset + size),
+ span,
+ )?;
+ }
+ Ok(())
+ }
+
fn exec_alloc_fn(
&mut self,
alloc_fn: &str,
@@ -272,21 +303,36 @@ impl Evaluator<'_> {
BeginPanic => Err(MirEvalError::Panic("<unknown-panic-payload>".to_string())),
PanicFmt => {
let message = (|| {
- let resolver = self.db.crate_def_map(self.crate_id).crate_root().resolver(self.db.upcast());
+ let resolver = self
+ .db
+ .crate_def_map(self.crate_id)
+ .crate_root()
+ .resolver(self.db.upcast());
let Some(format_fn) = resolver.resolve_path_in_value_ns_fully(
self.db.upcast(),
- &hir_def::path::Path::from_known_path_with_no_generic(ModPath::from_segments(
- hir_expand::mod_path::PathKind::Abs,
- [name![std], name![fmt], name![format]].into_iter(),
- )),
+ &hir_def::path::Path::from_known_path_with_no_generic(
+ ModPath::from_segments(
+ hir_expand::mod_path::PathKind::Abs,
+ [name![std], name![fmt], name![format]].into_iter(),
+ ),
+ ),
) else {
not_supported!("std::fmt::format not found");
};
- let hir_def::resolver::ValueNs::FunctionId(format_fn) = format_fn else { not_supported!("std::fmt::format is not a function") };
- let message_string = self.interpret_mir(self.db.mir_body(format_fn.into()).map_err(|e| MirEvalError::MirLowerError(format_fn, e))?, args.map(|x| IntervalOrOwned::Owned(x.clone())))?;
- let addr = Address::from_bytes(&message_string[self.ptr_size()..2 * self.ptr_size()])?;
+ let hir_def::resolver::ValueNs::FunctionId(format_fn) = format_fn else {
+ not_supported!("std::fmt::format is not a function")
+ };
+ let message_string = self.interpret_mir(
+ self.db
+ .mir_body(format_fn.into())
+ .map_err(|e| MirEvalError::MirLowerError(format_fn, e))?,
+ args.map(|x| IntervalOrOwned::Owned(x.clone())),
+ )?;
+ let addr =
+ Address::from_bytes(&message_string[self.ptr_size()..2 * self.ptr_size()])?;
let size = from_bytes!(usize, message_string[2 * self.ptr_size()..]);
- Ok(std::string::String::from_utf8_lossy(self.read_memory(addr, size)?).into_owned())
+ Ok(std::string::String::from_utf8_lossy(self.read_memory(addr, size)?)
+ .into_owned())
})()
.unwrap_or_else(|e| format!("Failed to render panic format args: {e:?}"));
Err(MirEvalError::Panic(message))
@@ -455,9 +501,7 @@ impl Evaluator<'_> {
}
"syscall" => {
let Some((id, rest)) = args.split_first() else {
- return Err(MirEvalError::TypeError(
- "syscall arg1 is not provided",
- ));
+ return Err(MirEvalError::TypeError("syscall arg1 is not provided"));
};
let id = from_bytes!(i64, id.get(self)?);
self.exec_syscall(id, rest, destination, locals, span)
@@ -473,6 +517,38 @@ impl Evaluator<'_> {
self.write_memory_using_ref(destination.addr, destination.size)?.fill(0);
Ok(())
}
+ "getenv" => {
+ let [name] = args else {
+ return Err(MirEvalError::TypeError("libc::write args are not provided"));
+ };
+ let mut name_buf = vec![];
+ let name = {
+ let mut index = Address::from_bytes(name.get(self)?)?;
+ loop {
+ let byte = self.read_memory(index, 1)?[0];
+ index = index.offset(1);
+ if byte == 0 {
+ break;
+ }
+ name_buf.push(byte);
+ }
+ String::from_utf8_lossy(&name_buf)
+ };
+ let value = self.db.crate_graph()[self.crate_id].env.get(&name);
+ match value {
+ None => {
+ // Write null as fail
+ self.write_memory_using_ref(destination.addr, destination.size)?.fill(0);
+ }
+ Some(mut value) => {
+ value.push('\0');
+ let addr = self.heap_allocate(value.len(), 1)?;
+ self.write_memory(addr, value.as_bytes())?;
+ self.write_memory(destination.addr, &addr.to_bytes())?;
+ }
+ }
+ Ok(())
+ }
_ => not_supported!("unknown external function {as_str}"),
}
}
@@ -650,7 +726,8 @@ impl Evaluator<'_> {
}
match name {
"size_of" => {
- let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
+ let Some(ty) =
+ generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
else {
return Err(MirEvalError::TypeError("size_of generic arg is not provided"));
};
@@ -658,14 +735,17 @@ impl Evaluator<'_> {
destination.write_from_bytes(self, &size.to_le_bytes()[0..destination.size])
}
"min_align_of" | "pref_align_of" => {
- let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) else {
+ let Some(ty) =
+ generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
+ else {
return Err(MirEvalError::TypeError("align_of generic arg is not provided"));
};
let align = self.layout(ty)?.align.abi.bytes();
destination.write_from_bytes(self, &align.to_le_bytes()[0..destination.size])
}
"size_of_val" => {
- let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
+ let Some(ty) =
+ generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
else {
return Err(MirEvalError::TypeError("size_of_val generic arg is not provided"));
};
@@ -681,8 +761,12 @@ impl Evaluator<'_> {
}
}
"min_align_of_val" => {
- let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) else {
- return Err(MirEvalError::TypeError("min_align_of_val generic arg is not provided"));
+ let Some(ty) =
+ generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
+ else {
+ return Err(MirEvalError::TypeError(
+ "min_align_of_val generic arg is not provided",
+ ));
};
let [arg] = args else {
return Err(MirEvalError::TypeError("min_align_of_val args are not provided"));
@@ -696,7 +780,8 @@ impl Evaluator<'_> {
}
}
"type_name" => {
- let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
+ let Some(ty) =
+ generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
else {
return Err(MirEvalError::TypeError("type_name generic arg is not provided"));
};
@@ -719,7 +804,8 @@ impl Evaluator<'_> {
.write_from_bytes(self, &len.to_le_bytes())
}
"needs_drop" => {
- let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
+ let Some(ty) =
+ generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
else {
return Err(MirEvalError::TypeError("size_of generic arg is not provided"));
};
@@ -771,9 +857,12 @@ impl Evaluator<'_> {
let lhs = i128::from_le_bytes(pad16(lhs.get(self)?, false));
let rhs = i128::from_le_bytes(pad16(rhs.get(self)?, false));
let ans = lhs.wrapping_sub(rhs);
- let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
+ let Some(ty) =
+ generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
else {
- return Err(MirEvalError::TypeError("ptr_offset_from generic arg is not provided"));
+ return Err(MirEvalError::TypeError(
+ "ptr_offset_from generic arg is not provided",
+ ));
};
let size = self.size_of_sized(ty, locals, "ptr_offset_from arg")? as i128;
let ans = ans / size;
@@ -880,7 +969,8 @@ impl Evaluator<'_> {
"copy_nonoverlapping args are not provided",
));
};
- let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
+ let Some(ty) =
+ generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
else {
return Err(MirEvalError::TypeError(
"copy_nonoverlapping generic arg is not provided",
@@ -899,9 +989,45 @@ impl Evaluator<'_> {
let [ptr, offset] = args else {
return Err(MirEvalError::TypeError("offset args are not provided"));
};
- let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
- else {
- return Err(MirEvalError::TypeError("offset generic arg is not provided"));
+ let ty = if name == "offset" {
+ let Some(ty0) =
+ generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
+ else {
+ return Err(MirEvalError::TypeError("offset generic arg is not provided"));
+ };
+ let Some(ty1) =
+ generic_args.as_slice(Interner).get(1).and_then(|it| it.ty(Interner))
+ else {
+ return Err(MirEvalError::TypeError("offset generic arg is not provided"));
+ };
+ if !matches!(
+ ty1.as_builtin(),
+ Some(
+ BuiltinType::Int(BuiltinInt::Isize)
+ | BuiltinType::Uint(BuiltinUint::Usize)
+ )
+ ) {
+ return Err(MirEvalError::TypeError(
+ "offset generic arg is not usize or isize",
+ ));
+ }
+ match ty0.as_raw_ptr() {
+ Some((ty, _)) => ty,
+ None => {
+ return Err(MirEvalError::TypeError(
+ "offset generic arg is not a raw pointer",
+ ));
+ }
+ }
+ } else {
+ let Some(ty) =
+ generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
+ else {
+ return Err(MirEvalError::TypeError(
+ "arith_offset generic arg is not provided",
+ ));
+ };
+ ty
};
let ptr = u128::from_le_bytes(pad16(ptr.get(self)?, false));
let offset = u128::from_le_bytes(pad16(offset.get(self)?, false));
@@ -1019,7 +1145,8 @@ impl Evaluator<'_> {
let [arg] = args else {
return Err(MirEvalError::TypeError("discriminant_value arg is not provided"));
};
- let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
+ let Some(ty) =
+ generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
else {
return Err(MirEvalError::TypeError(
"discriminant_value generic arg is not provided",
@@ -1073,17 +1200,32 @@ impl Evaluator<'_> {
let addr = Address::from_bytes(arg.interval.get(self)?)?;
destination.write_from_interval(self, Interval { addr, size: destination.size })
}
+ "write_via_move" => {
+ let [ptr, val] = args else {
+ return Err(MirEvalError::TypeError("write_via_move args are not provided"));
+ };
+ let dst = Address::from_bytes(ptr.get(self)?)?;
+ let Some(ty) =
+ generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
+ else {
+ return Err(MirEvalError::TypeError(
+ "write_via_copy generic arg is not provided",
+ ));
+ };
+ let size = self.size_of_sized(ty, locals, "write_via_move ptr type")?;
+ Interval { addr: dst, size }.write_from_interval(self, val.interval)?;
+ Ok(())
+ }
"write_bytes" => {
let [dst, val, count] = args else {
return Err(MirEvalError::TypeError("write_bytes args are not provided"));
};
let count = from_bytes!(usize, count.get(self)?);
let val = from_bytes!(u8, val.get(self)?);
- let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
+ let Some(ty) =
+ generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
else {
- return Err(MirEvalError::TypeError(
- "write_bytes generic arg is not provided",
- ));
+ return Err(MirEvalError::TypeError("write_bytes generic arg is not provided"));
};
let dst = Address::from_bytes(dst.get(self)?)?;
let size = self.size_of_sized(ty, locals, "copy_nonoverlapping ptr type")?;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs
index ec7463104..519006624 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs
@@ -45,7 +45,9 @@ impl Evaluator<'_> {
};
match try_const_usize(self.db, len) {
Some(len) => {
- let Some(ty) = subst.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) else {
+ let Some(ty) =
+ subst.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
+ else {
return Err(MirEvalError::TypeError("simd type with no ty param"));
};
Ok((len as usize, ty.clone()))
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs
index 46165cf3d..ff30dc6da 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs
@@ -730,6 +730,48 @@ fn main() {
}
#[test]
+fn posix_getenv() {
+ check_pass(
+ r#"
+//- /main.rs env:foo=bar
+
+type c_char = u8;
+
+extern "C" {
+ pub fn getenv(s: *const c_char) -> *mut c_char;
+}
+
+fn should_not_reach() {
+ _ // FIXME: replace this function with panic when that works
+}
+
+fn main() {
+ let result = getenv(b"foo\0" as *const _);
+ if *result != b'b' {
+ should_not_reach();
+ }
+ let result = (result as usize + 1) as *const c_char;
+ if *result != b'a' {
+ should_not_reach();
+ }
+ let result = (result as usize + 1) as *const c_char;
+ if *result != b'r' {
+ should_not_reach();
+ }
+ let result = (result as usize + 1) as *const c_char;
+ if *result != 0 {
+ should_not_reach();
+ }
+ let result = getenv(b"not found\0" as *const _);
+ if result as usize != 0 {
+ should_not_reach();
+ }
+}
+"#,
+ );
+}
+
+#[test]
fn posix_tls() {
check_pass(
r#"
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 718df8331..dd2dba717 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
@@ -15,7 +15,7 @@ use hir_def::{
path::Path,
resolver::{resolver_for_expr, HasResolver, ResolveValueResult, ValueNs},
AdtId, DefWithBodyId, EnumVariantId, GeneralConstId, HasModule, ItemContainerId, LocalFieldId,
- TraitId, TypeOrConstParamId,
+ Lookup, TraitId, TypeOrConstParamId,
};
use hir_expand::name::Name;
use la_arena::ArenaMap;
@@ -71,7 +71,7 @@ struct MirLowerCtx<'a> {
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MirLowerError {
- ConstEvalError(String, Box<ConstEvalError>),
+ ConstEvalError(Box<str>, Box<ConstEvalError>),
LayoutError(LayoutError),
IncompleteExpr,
IncompletePattern,
@@ -84,7 +84,7 @@ pub enum MirLowerError {
UnsizedTemporary(Ty),
MissingFunctionDefinition(DefWithBodyId, ExprId),
TypeMismatch(TypeMismatch),
- /// This should be never happen. Type mismatch should catch everything.
+ /// This should never happen. Type mismatch should catch everything.
TypeError(&'static str),
NotSupported(String),
ContinueWithoutLoop,
@@ -244,6 +244,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
let locals = Arena::new();
let binding_locals: ArenaMap<BindingId, LocalId> = ArenaMap::new();
let mir = MirBody {
+ projection_store: ProjectionStore::default(),
basic_blocks,
locals,
start_block,
@@ -370,9 +371,15 @@ impl<'ctx> MirLowerCtx<'ctx> {
mut current: BasicBlockId,
) -> Result<Option<BasicBlockId>> {
match &self.body.exprs[expr_id] {
+ Expr::OffsetOf(_) => {
+ not_supported!("builtin#offset_of")
+ }
+ Expr::InlineAsm(_) => {
+ not_supported!("builtin#asm")
+ }
Expr::Missing => {
if let DefWithBodyId::FunctionId(f) = self.owner {
- let assoc = self.db.lookup_intern_function(f);
+ let assoc = f.lookup(self.db.upcast());
if let ItemContainerId::TraitId(t) = assoc.container {
let name = &self.db.function_data(f).name;
return Err(MirLowerError::TraitFunctionDefinition(t, name.clone()));
@@ -803,36 +810,34 @@ impl<'ctx> MirLowerCtx<'ctx> {
current = c;
operands[u32::from(field_id.into_raw()) as usize] = Some(op);
}
- self.push_assignment(
- current,
- place,
- Rvalue::Aggregate(
- AggregateKind::Adt(variant_id, subst),
- match spread_place {
- Some(sp) => operands
- .into_iter()
- .enumerate()
- .map(|(i, it)| match it {
- Some(it) => it,
- None => {
- let p =
- sp.project(ProjectionElem::Field(FieldId {
- parent: variant_id,
- local_id: LocalFieldId::from_raw(
- RawIdx::from(i as u32),
- ),
- }));
- Operand::Copy(p)
- }
- })
- .collect(),
- None => operands.into_iter().collect::<Option<_>>().ok_or(
- MirLowerError::TypeError("missing field in record literal"),
- )?,
- },
- ),
- expr_id.into(),
+ let rvalue = Rvalue::Aggregate(
+ AggregateKind::Adt(variant_id, subst),
+ match spread_place {
+ Some(sp) => operands
+ .into_iter()
+ .enumerate()
+ .map(|(i, it)| match it {
+ Some(it) => it,
+ None => {
+ let p = sp.project(
+ ProjectionElem::Field(FieldId {
+ parent: variant_id,
+ local_id: LocalFieldId::from_raw(RawIdx::from(
+ i as u32,
+ )),
+ }),
+ &mut self.result.projection_store,
+ );
+ Operand::Copy(p)
+ }
+ })
+ .collect(),
+ None => operands.into_iter().collect::<Option<_>>().ok_or(
+ MirLowerError::TypeError("missing field in record literal"),
+ )?,
+ },
);
+ self.push_assignment(current, place, rvalue, expr_id.into());
Ok(Some(current))
}
VariantId::UnionId(union_id) => {
@@ -841,10 +846,10 @@ impl<'ctx> MirLowerCtx<'ctx> {
};
let local_id =
variant_data.field(name).ok_or(MirLowerError::UnresolvedField)?;
- let place = place.project(PlaceElem::Field(FieldId {
- parent: union_id.into(),
- local_id,
- }));
+ let place = place.project(
+ PlaceElem::Field(FieldId { parent: union_id.into(), local_id }),
+ &mut self.result.projection_store,
+ );
self.lower_expr_to_place(*expr, place, current)
}
}
@@ -898,7 +903,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
else {
return Ok(None);
};
- let p = place.project(ProjectionElem::Deref);
+ let p = place.project(ProjectionElem::Deref, &mut self.result.projection_store);
self.push_assignment(current, p, operand.into(), expr_id.into());
Ok(Some(current))
}
@@ -1120,27 +1125,31 @@ impl<'ctx> MirLowerCtx<'ctx> {
for capture in captures.iter() {
let p = Place {
local: self.binding_local(capture.place.local)?,
- projection: capture
- .place
- .projections
- .clone()
- .into_iter()
- .map(|it| match it {
- ProjectionElem::Deref => ProjectionElem::Deref,
- ProjectionElem::Field(it) => ProjectionElem::Field(it),
- ProjectionElem::TupleOrClosureField(it) => {
- ProjectionElem::TupleOrClosureField(it)
- }
- ProjectionElem::ConstantIndex { offset, from_end } => {
- ProjectionElem::ConstantIndex { offset, from_end }
- }
- ProjectionElem::Subslice { from, to } => {
- ProjectionElem::Subslice { from, to }
- }
- ProjectionElem::OpaqueCast(it) => ProjectionElem::OpaqueCast(it),
- ProjectionElem::Index(it) => match it {},
- })
- .collect(),
+ projection: self.result.projection_store.intern(
+ capture
+ .place
+ .projections
+ .clone()
+ .into_iter()
+ .map(|it| match it {
+ ProjectionElem::Deref => ProjectionElem::Deref,
+ ProjectionElem::Field(it) => ProjectionElem::Field(it),
+ ProjectionElem::TupleOrClosureField(it) => {
+ ProjectionElem::TupleOrClosureField(it)
+ }
+ ProjectionElem::ConstantIndex { offset, from_end } => {
+ ProjectionElem::ConstantIndex { offset, from_end }
+ }
+ ProjectionElem::Subslice { from, to } => {
+ ProjectionElem::Subslice { from, to }
+ }
+ ProjectionElem::OpaqueCast(it) => {
+ ProjectionElem::OpaqueCast(it)
+ }
+ ProjectionElem::Index(it) => match it {},
+ })
+ .collect(),
+ ),
};
match &capture.kind {
CaptureKind::ByRef(bk) => {
@@ -1201,7 +1210,8 @@ impl<'ctx> MirLowerCtx<'ctx> {
let Some(values) = elements
.iter()
.map(|it| {
- let Some((o, c)) = self.lower_expr_to_some_operand(*it, current)? else {
+ let Some((o, c)) = self.lower_expr_to_some_operand(*it, current)?
+ else {
return Ok(None);
};
current = c;
@@ -1244,6 +1254,40 @@ impl<'ctx> MirLowerCtx<'ctx> {
}
}
+ fn lower_destructing_assignment(
+ &mut self,
+ mut current: BasicBlockId,
+ lhs: ExprId,
+ rhs: Place,
+ span: MirSpan,
+ ) -> Result<Option<BasicBlockId>> {
+ match &self.body.exprs[lhs] {
+ Expr::Tuple { exprs, is_assignee_expr: _ } => {
+ for (i, expr) in exprs.iter().enumerate() {
+ let rhs = rhs.project(
+ ProjectionElem::TupleOrClosureField(i),
+ &mut self.result.projection_store,
+ );
+ let Some(c) = self.lower_destructing_assignment(current, *expr, rhs, span)?
+ else {
+ return Ok(None);
+ };
+ current = c;
+ }
+ Ok(Some(current))
+ }
+ Expr::Underscore => Ok(Some(current)),
+ _ => {
+ let Some((lhs_place, current)) = self.lower_expr_as_place(current, lhs, false)?
+ else {
+ return Ok(None);
+ };
+ self.push_assignment(current, lhs_place, Operand::Copy(rhs).into(), span);
+ Ok(Some(current))
+ }
+ }
+ }
+
fn lower_assignment(
&mut self,
current: BasicBlockId,
@@ -1251,17 +1295,22 @@ impl<'ctx> MirLowerCtx<'ctx> {
rhs: ExprId,
span: MirSpan,
) -> Result<Option<BasicBlockId>> {
- let Some((rhs_op, current)) =
- self.lower_expr_to_some_operand(rhs, current)?
- else {
+ let Some((rhs_op, current)) = self.lower_expr_to_some_operand(rhs, current)? else {
return Ok(None);
};
if matches!(&self.body.exprs[lhs], Expr::Underscore) {
return Ok(Some(current));
}
- let Some((lhs_place, current)) =
- self.lower_expr_as_place(current, lhs, false)?
- else {
+ if matches!(
+ &self.body.exprs[lhs],
+ Expr::Tuple { .. } | Expr::RecordLit { .. } | Expr::Call { .. }
+ ) {
+ let temp = self.temp(self.expr_ty_after_adjustments(rhs), current, rhs.into())?;
+ let temp = Place::from(temp);
+ self.push_assignment(current, temp.clone(), rhs_op.into(), span);
+ return self.lower_destructing_assignment(current, lhs, temp, span);
+ }
+ let Some((lhs_place, current)) = self.lower_expr_as_place(current, lhs, false)? else {
return Ok(None);
};
self.push_assignment(current, lhs_place, rhs_op.into(), span);
@@ -1276,17 +1325,21 @@ impl<'ctx> MirLowerCtx<'ctx> {
placeholder_subst
}
- fn push_field_projection(&self, place: &mut Place, expr_id: ExprId) -> Result<()> {
+ fn push_field_projection(&mut self, place: &mut Place, expr_id: ExprId) -> Result<()> {
if let Expr::Field { expr, name } = &self.body[expr_id] {
if let TyKind::Tuple(..) = self.expr_ty_after_adjustments(*expr).kind(Interner) {
let index = name
.as_tuple_index()
.ok_or(MirLowerError::TypeError("named field on tuple"))?;
- *place = place.project(ProjectionElem::TupleOrClosureField(index))
+ *place = place.project(
+ ProjectionElem::TupleOrClosureField(index),
+ &mut self.result.projection_store,
+ )
} else {
let field =
self.infer.field_resolution(expr_id).ok_or(MirLowerError::UnresolvedField)?;
- *place = place.project(ProjectionElem::Field(field));
+ *place =
+ place.project(ProjectionElem::Field(field), &mut self.result.projection_store);
}
} else {
not_supported!("")
@@ -1308,14 +1361,14 @@ impl<'ctx> MirLowerCtx<'ctx> {
.resolve_path_in_value_ns(self.db.upcast(), c)
.ok_or_else(unresolved_name)?;
match pr {
- ResolveValueResult::ValueNs(v) => {
+ ResolveValueResult::ValueNs(v, _) => {
if let ValueNs::ConstId(c) = v {
self.lower_const_to_operand(Substitution::empty(Interner), c.into(), ty)
} else {
not_supported!("bad path in range pattern");
}
}
- ResolveValueResult::Partial(_, _) => {
+ ResolveValueResult::Partial(_, _, _) => {
not_supported!("associated constants in range pattern")
}
}
@@ -1403,7 +1456,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
let name = const_id.name(self.db.upcast());
self.db
.const_eval(const_id.into(), subst, None)
- .map_err(|e| MirLowerError::ConstEvalError(name, Box::new(e)))?
+ .map_err(|e| MirLowerError::ConstEvalError(name.into(), Box::new(e)))?
};
Ok(Operand::Constant(c))
}
@@ -1800,7 +1853,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
data.name.display(self.db.upcast()),
data.variants[variant.local_id].name.display(self.db.upcast())
);
- Err(MirLowerError::ConstEvalError(name, Box::new(e)))
+ Err(MirLowerError::ConstEvalError(name.into(), Box::new(e)))
}
}
}
@@ -1948,13 +2001,14 @@ pub fn mir_body_for_closure_query(
FnTrait::FnOnce => vec![],
FnTrait::FnMut | FnTrait::Fn => vec![ProjectionElem::Deref],
};
- ctx.result.walk_places(|p| {
+ ctx.result.walk_places(|p, store| {
if let Some(it) = upvar_map.get(&p.local) {
let r = it.iter().find(|it| {
- if p.projection.len() < it.0.place.projections.len() {
+ if p.projection.lookup(&store).len() < it.0.place.projections.len() {
return false;
}
- for (it, y) in p.projection.iter().zip(it.0.place.projections.iter()) {
+ for (it, y) in p.projection.lookup(&store).iter().zip(it.0.place.projections.iter())
+ {
match (it, y) {
(ProjectionElem::Deref, ProjectionElem::Deref) => (),
(ProjectionElem::Field(it), ProjectionElem::Field(y)) if it == y => (),
@@ -1972,13 +2026,18 @@ pub fn mir_body_for_closure_query(
p.local = closure_local;
let mut next_projs = closure_projection.clone();
next_projs.push(PlaceElem::TupleOrClosureField(it.1));
- let prev_projs = mem::take(&mut p.projection);
+ let prev_projs = p.projection;
if it.0.kind != CaptureKind::ByValue {
next_projs.push(ProjectionElem::Deref);
}
- next_projs
- .extend(prev_projs.iter().cloned().skip(it.0.place.projections.len()));
- p.projection = next_projs.into();
+ next_projs.extend(
+ prev_projs
+ .lookup(&store)
+ .iter()
+ .cloned()
+ .skip(it.0.place.projections.len()),
+ );
+ p.projection = store.intern(next_projs.into());
}
None => err = Some(p.clone()),
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs
index 213f151ab..8c078eb4a 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs
@@ -70,7 +70,7 @@ impl MirLowerCtx<'_> {
else {
return Ok(None);
};
- it.0 = it.0.project(ProjectionElem::Deref);
+ it.0 = it.0.project(ProjectionElem::Deref, &mut self.result.projection_store);
Ok(Some(it))
}
Adjust::Deref(Some(od)) => {
@@ -152,7 +152,10 @@ impl MirLowerCtx<'_> {
Operand::Static(s).into(),
expr_id.into(),
);
- Ok(Some((temp.project(ProjectionElem::Deref), current)))
+ Ok(Some((
+ temp.project(ProjectionElem::Deref, &mut self.result.projection_store),
+ current,
+ )))
}
_ => try_rvalue(self),
}
@@ -203,7 +206,7 @@ impl MirLowerCtx<'_> {
else {
return Ok(None);
};
- r = r.project(ProjectionElem::Deref);
+ r = r.project(ProjectionElem::Deref, &mut self.result.projection_store);
Ok(Some((r, current)))
}
_ => try_rvalue(self),
@@ -267,7 +270,8 @@ impl MirLowerCtx<'_> {
else {
return Ok(None);
};
- p_base = p_base.project(ProjectionElem::Index(l_index));
+ p_base = p_base
+ .project(ProjectionElem::Index(l_index), &mut self.result.projection_store);
Ok(Some((p_base, current)))
}
_ => try_rvalue(self),
@@ -308,7 +312,7 @@ impl MirLowerCtx<'_> {
else {
return Ok(None);
};
- result = result.project(ProjectionElem::Deref);
+ result = result.project(ProjectionElem::Deref, &mut self.result.projection_store);
Ok(Some((result, current)))
}
@@ -363,7 +367,7 @@ impl MirLowerCtx<'_> {
else {
return Ok(None);
};
- result = result.project(ProjectionElem::Deref);
+ result = result.project(ProjectionElem::Deref, &mut self.result.projection_store);
Ok(Some((result, current)))
}
}
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 3354cbd76..270f75ad9 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
@@ -81,13 +81,16 @@ impl MirLowerCtx<'_> {
mode: MatchingMode,
) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
let cnt = self.infer.pat_adjustments.get(&pattern).map(|x| x.len()).unwrap_or_default();
- cond_place.projection = cond_place
- .projection
- .iter()
- .cloned()
- .chain((0..cnt).map(|_| ProjectionElem::Deref))
- .collect::<Vec<_>>()
- .into();
+ cond_place.projection = self.result.projection_store.intern(
+ cond_place
+ .projection
+ .lookup(&self.result.projection_store)
+ .iter()
+ .cloned()
+ .chain((0..cnt).map(|_| ProjectionElem::Deref))
+ .collect::<Vec<_>>()
+ .into(),
+ );
Ok(match &self.body.pats[pattern] {
Pat::Missing => return Err(MirLowerError::IncompletePattern),
Pat::Wild => (current, current_else),
@@ -262,20 +265,23 @@ impl MirLowerCtx<'_> {
}
}
for (i, &pat) in prefix.iter().enumerate() {
- let next_place = (&mut cond_place).project(ProjectionElem::ConstantIndex {
- offset: i as u64,
- from_end: false,
- });
+ let next_place = (&mut cond_place).project(
+ ProjectionElem::ConstantIndex { offset: i as u64, from_end: false },
+ &mut self.result.projection_store,
+ );
(current, current_else) =
self.pattern_match_inner(current, current_else, next_place, pat, mode)?;
}
if let Some(slice) = slice {
if mode == MatchingMode::Bind {
if let Pat::Bind { id, subpat: _ } = self.body[*slice] {
- let next_place = (&mut cond_place).project(ProjectionElem::Subslice {
- from: prefix.len() as u64,
- to: suffix.len() as u64,
- });
+ let next_place = (&mut cond_place).project(
+ ProjectionElem::Subslice {
+ from: prefix.len() as u64,
+ to: suffix.len() as u64,
+ },
+ &mut self.result.projection_store,
+ );
(current, current_else) = self.pattern_match_binding(
id,
next_place,
@@ -287,10 +293,10 @@ impl MirLowerCtx<'_> {
}
}
for (i, &pat) in suffix.iter().enumerate() {
- let next_place = (&mut cond_place).project(ProjectionElem::ConstantIndex {
- offset: i as u64,
- from_end: true,
- });
+ let next_place = (&mut cond_place).project(
+ ProjectionElem::ConstantIndex { offset: i as u64, from_end: true },
+ &mut self.result.projection_store,
+ );
(current, current_else) =
self.pattern_match_inner(current, current_else, next_place, pat, mode)?;
}
@@ -323,7 +329,7 @@ impl MirLowerCtx<'_> {
break 'b (c, x.1);
}
}
- if let ResolveValueResult::ValueNs(v) = pr {
+ if let ResolveValueResult::ValueNs(v, _) = pr {
if let ValueNs::ConstId(c) = v {
break 'b (c, Substitution::empty(Interner));
}
@@ -412,13 +418,11 @@ impl MirLowerCtx<'_> {
mode,
)?
}
- Pat::Ref { pat, mutability: _ } => self.pattern_match_inner(
- current,
- current_else,
- cond_place.project(ProjectionElem::Deref),
- *pat,
- mode,
- )?,
+ Pat::Ref { pat, mutability: _ } => {
+ let cond_place =
+ cond_place.project(ProjectionElem::Deref, &mut self.result.projection_store);
+ self.pattern_match_inner(current, current_else, cond_place, *pat, mode)?
+ }
Pat::Box { .. } => not_supported!("box pattern"),
Pat::ConstBlock(_) => not_supported!("const block pattern"),
})
@@ -594,7 +598,7 @@ impl MirLowerCtx<'_> {
mode: MatchingMode,
) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
for (proj, arg) in args {
- let cond_place = cond_place.project(proj);
+ let cond_place = cond_place.project(proj, &mut self.result.projection_store);
(current, current_else) =
self.pattern_match_inner(current, current_else, cond_place, arg, mode)?;
}
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 c565228d9..df16d0d82 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
@@ -265,7 +265,7 @@ impl Filler<'_> {
self.fill_operand(discr)?;
}
TerminatorKind::Goto { .. }
- | TerminatorKind::Resume
+ | TerminatorKind::UnwindResume
| TerminatorKind::Abort
| TerminatorKind::Return
| TerminatorKind::Unreachable
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 781ffaeca..0108859ff 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
@@ -329,7 +329,7 @@ impl<'a> MirPrettyCtx<'a> {
}
}
}
- f(self, p.local, &p.projection);
+ f(self, p.local, &p.projection.lookup(&self.body.projection_store));
}
fn operand(&mut self, r: &Operand) {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
index 2ad7946c8..8140c4107 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
@@ -3,55 +3,6 @@ use expect_test::expect;
use super::{check, check_infer, check_no_mismatches, check_types};
#[test]
-fn infer_box() {
- check_types(
- r#"
-//- /main.rs crate:main deps:std
-fn test() {
- let x = box 1;
- let t = (x, box x, box &1, box [1]);
- t;
-} //^ (Box<i32>, Box<Box<i32>>, Box<&i32>, Box<[i32; 1]>)
-
-//- /std.rs crate:std
-#[prelude_import] use prelude::*;
-mod prelude {}
-
-mod boxed {
- #[lang = "owned_box"]
- pub struct Box<T: ?Sized> {
- inner: *mut T,
- }
-}
-"#,
- );
-}
-
-#[test]
-fn infer_box_with_allocator() {
- check_types(
- r#"
-//- /main.rs crate:main deps:std
-fn test() {
- let x = box 1;
- let t = (x, box x, box &1, box [1]);
- t;
-} //^ (Box<i32, {unknown}>, Box<Box<i32, {unknown}>, {unknown}>, Box<&i32, {unknown}>, Box<[i32; 1], {unknown}>)
-
-//- /std.rs crate:std
-#[prelude_import] use prelude::*;
-mod boxed {
- #[lang = "owned_box"]
- pub struct Box<T: ?Sized, A: Allocator> {
- inner: *mut T,
- allocator: A,
- }
-}
-"#,
- );
-}
-
-#[test]
fn infer_adt_self() {
check_types(
r#"
@@ -2763,8 +2714,8 @@ impl<T> [T] {
}
fn test() {
- let vec = <[_]>::into_vec(box [1i32]);
- let v: Vec<Box<dyn B>> = <[_]> :: into_vec(box [box Astruct]);
+ let vec = <[_]>::into_vec(#[rustc_box] Box::new([1i32]));
+ let v: Vec<Box<dyn B>> = <[_]> :: into_vec(#[rustc_box] Box::new([#[rustc_box] Box::new(Astruct)]));
}
trait B{}
@@ -2774,20 +2725,20 @@ impl B for Astruct {}
expect![[r#"
604..608 'self': Box<[T], A>
637..669 '{ ... }': Vec<T, A>
- 683..796 '{ ...t]); }': ()
+ 683..853 '{ ...])); }': ()
693..696 'vec': Vec<i32, Global>
699..714 '<[_]>::into_vec': fn into_vec<i32, Global>(Box<[i32], Global>) -> Vec<i32, Global>
- 699..726 '<[_]>:...1i32])': Vec<i32, Global>
- 715..725 'box [1i32]': Box<[i32; 1], Global>
- 719..725 '[1i32]': [i32; 1]
- 720..724 '1i32': i32
- 736..737 'v': Vec<Box<dyn B, Global>, Global>
- 757..774 '<[_]> ...to_vec': fn into_vec<Box<dyn B, Global>, Global>(Box<[Box<dyn B, Global>], Global>) -> Vec<Box<dyn B, Global>, Global>
- 757..793 '<[_]> ...ruct])': Vec<Box<dyn B, Global>, Global>
- 775..792 'box [b...truct]': Box<[Box<dyn B, Global>; 1], Global>
- 779..792 '[box Astruct]': [Box<dyn B, Global>; 1]
- 780..791 'box Astruct': Box<Astruct, Global>
- 784..791 'Astruct': Astruct
+ 699..745 '<[_]>:...i32]))': Vec<i32, Global>
+ 715..744 '#[rust...1i32])': Box<[i32; 1], Global>
+ 737..743 '[1i32]': [i32; 1]
+ 738..742 '1i32': i32
+ 755..756 'v': Vec<Box<dyn B, Global>, Global>
+ 776..793 '<[_]> ...to_vec': fn into_vec<Box<dyn B, Global>, Global>(Box<[Box<dyn B, Global>], Global>) -> Vec<Box<dyn B, Global>, Global>
+ 776..850 '<[_]> ...ct)]))': Vec<Box<dyn B, Global>, Global>
+ 794..849 '#[rust...uct)])': Box<[Box<dyn B, Global>; 1], Global>
+ 816..848 '[#[rus...ruct)]': [Box<dyn B, Global>; 1]
+ 817..847 '#[rust...truct)': Box<Astruct, Global>
+ 839..846 'Astruct': Astruct
"#]],
)
}
@@ -3649,3 +3600,30 @@ fn main() {
"#,
);
}
+
+#[test]
+fn offset_of() {
+ check_types(
+ r#"
+fn main() {
+ builtin#offset_of((,), 0);
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^ usize
+}
+"#,
+ );
+}
+
+#[test]
+fn builtin_format_args() {
+ check(
+ r#"
+//- minicore: fmt
+fn main() {
+ let are = "are";
+ let count = 10;
+ builtin#format_args("hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", last = "!");
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type: Arguments<'_>
+}
+"#,
+ );
+}
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 542df8b34..d36b885ec 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
@@ -162,16 +162,16 @@ unsafe impl Allocator for Global {}
#[lang = "owned_box"]
#[fundamental]
-pub struct Box<T: ?Sized, A: Allocator = Global>;
+pub struct Box<T: ?Sized, A: Allocator = Global>(T);
impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Box<U, A>> for Box<T, A> {}
fn send() -> Box<dyn Future<Output = ()> + Send + 'static>{
- box async move {}
+ Box(async move {})
}
fn not_send() -> Box<dyn Future<Output = ()> + 'static> {
- box async move {}
+ Box(async move {})
}
"#,
);
@@ -3057,7 +3057,7 @@ impl<T: ?Sized> core::ops::Deref for Box<T> {
fn foo() {
let s = None;
- let f: Box<dyn FnOnce(&Option<i32>)> = box (|ps| {});
+ let f: Box<dyn FnOnce(&Option<i32>)> = Box { inner: &mut (|ps| {}) };
f(&s);
}"#,
expect![[r#"
@@ -3068,19 +3068,19 @@ fn foo() {
186..197 '*self.inner': T
187..191 'self': &Box<T>
187..197 'self.inner': *mut T
- 218..308 '{ ...&s); }': ()
+ 218..324 '{ ...&s); }': ()
228..229 's': Option<i32>
232..236 'None': Option<i32>
246..247 'f': Box<dyn FnOnce(&Option<i32>)>
- 281..294 'box (|ps| {})': Box<impl Fn(&Option<i32>)>
- 286..293 '|ps| {}': impl Fn(&Option<i32>)
- 287..289 'ps': &Option<i32>
- 291..293 '{}': ()
- 300..301 'f': Box<dyn FnOnce(&Option<i32>)>
- 300..305 'f(&s)': ()
- 302..304 '&s': &Option<i32>
- 303..304 's': Option<i32>
- 281..294: expected Box<dyn FnOnce(&Option<i32>)>, got Box<impl Fn(&Option<i32>)>
+ 281..310 'Box { ... {}) }': Box<dyn FnOnce(&Option<i32>)>
+ 294..308 '&mut (|ps| {})': &mut impl Fn(&Option<i32>)
+ 300..307 '|ps| {}': impl Fn(&Option<i32>)
+ 301..303 'ps': &Option<i32>
+ 305..307 '{}': ()
+ 316..317 'f': Box<dyn FnOnce(&Option<i32>)>
+ 316..321 'f(&s)': ()
+ 318..320 '&s': &Option<i32>
+ 319..320 's': Option<i32>
"#]],
);
}