mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-27 10:17:15 +00:00
Merge commit 'baee6b338b' into sync-from-ra
This commit is contained in:
parent
0155385b57
commit
aa55ce9567
139 changed files with 4248 additions and 1042 deletions
|
|
@ -36,6 +36,9 @@ impl Evaluator<'_> {
|
|||
destination: Interval,
|
||||
span: MirSpan,
|
||||
) -> Result<bool> {
|
||||
if self.not_special_fn_cache.borrow().contains(&def) {
|
||||
return Ok(false);
|
||||
}
|
||||
let function_data = self.db.function_data(def);
|
||||
let is_intrinsic = match &function_data.abi {
|
||||
Some(abi) => *abi == Interned::new_str("rust-intrinsic"),
|
||||
|
|
@ -124,9 +127,88 @@ impl Evaluator<'_> {
|
|||
destination.write_from_bytes(self, &result)?;
|
||||
return Ok(true);
|
||||
}
|
||||
if let ItemContainerId::TraitId(t) = def.lookup(self.db.upcast()).container {
|
||||
if self.db.lang_attr(t.into()) == Some(LangItem::Clone) {
|
||||
let [self_ty] = generic_args.as_slice(Interner) else {
|
||||
not_supported!("wrong generic arg count for clone");
|
||||
};
|
||||
let Some(self_ty) = self_ty.ty(Interner) else {
|
||||
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(..)) {
|
||||
self.exec_clone(def, args, self_ty.clone(), locals, destination, span)?;
|
||||
return Ok(true);
|
||||
}
|
||||
// Return early to prevent caching clone as non special fn.
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
self.not_special_fn_cache.borrow_mut().insert(def);
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
/// Clone has special impls for tuples and function pointers
|
||||
fn exec_clone(
|
||||
&mut self,
|
||||
def: FunctionId,
|
||||
args: &[IntervalAndTy],
|
||||
self_ty: Ty,
|
||||
locals: &Locals,
|
||||
destination: Interval,
|
||||
span: MirSpan,
|
||||
) -> Result<()> {
|
||||
match self_ty.kind(Interner) {
|
||||
TyKind::Function(_) => {
|
||||
let [arg] = args else {
|
||||
not_supported!("wrong arg count for clone");
|
||||
};
|
||||
let addr = Address::from_bytes(arg.get(self)?)?;
|
||||
return destination
|
||||
.write_from_interval(self, Interval { addr, size: destination.size });
|
||||
}
|
||||
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,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
self.exec_fn_with_args(
|
||||
def,
|
||||
args,
|
||||
Substitution::from1(Interner, self_ty),
|
||||
locals,
|
||||
destination,
|
||||
None,
|
||||
span,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn exec_alloc_fn(
|
||||
&mut self,
|
||||
alloc_fn: &str,
|
||||
|
|
@ -618,12 +700,15 @@ impl Evaluator<'_> {
|
|||
else {
|
||||
return Err(MirEvalError::TypeError("type_name generic arg is not provided"));
|
||||
};
|
||||
let Ok(ty_name) = ty.display_source_code(
|
||||
let ty_name = match ty.display_source_code(
|
||||
self.db,
|
||||
locals.body.owner.module(self.db.upcast()),
|
||||
true,
|
||||
) else {
|
||||
not_supported!("fail in generating type_name using source code display");
|
||||
) {
|
||||
Ok(ty_name) => ty_name,
|
||||
// Fallback to human readable display in case of `Err`. Ideally we want to use `display_source_code` to
|
||||
// render full paths.
|
||||
Err(_) => ty.display(self.db).to_string(),
|
||||
};
|
||||
let len = ty_name.len();
|
||||
let addr = self.heap_allocate(len, 1)?;
|
||||
|
|
@ -679,7 +764,22 @@ impl Evaluator<'_> {
|
|||
let ans = lhs.wrapping_add(rhs);
|
||||
destination.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size])
|
||||
}
|
||||
"wrapping_sub" | "unchecked_sub" | "ptr_offset_from_unsigned" | "ptr_offset_from" => {
|
||||
"ptr_offset_from_unsigned" | "ptr_offset_from" => {
|
||||
let [lhs, rhs] = args else {
|
||||
return Err(MirEvalError::TypeError("wrapping_sub args are not provided"));
|
||||
};
|
||||
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))
|
||||
else {
|
||||
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;
|
||||
destination.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size])
|
||||
}
|
||||
"wrapping_sub" | "unchecked_sub" => {
|
||||
let [lhs, rhs] = args else {
|
||||
return Err(MirEvalError::TypeError("wrapping_sub args are not provided"));
|
||||
};
|
||||
|
|
@ -1057,7 +1157,14 @@ impl Evaluator<'_> {
|
|||
_span: MirSpan,
|
||||
) -> Result<()> {
|
||||
// We are a single threaded runtime with no UB checking and no optimization, so
|
||||
// we can implement these as normal functions.
|
||||
// we can implement atomic intrinsics as normal functions.
|
||||
|
||||
if name.starts_with("singlethreadfence_") || name.starts_with("fence_") {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// The rest of atomic intrinsics have exactly one generic arg
|
||||
|
||||
let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) else {
|
||||
return Err(MirEvalError::TypeError("atomic intrinsic generic arg is not provided"));
|
||||
};
|
||||
|
|
|
|||
|
|
@ -182,6 +182,50 @@ fn main() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drop_struct_field() {
|
||||
check_pass(
|
||||
r#"
|
||||
//- minicore: drop, add, option, cell, builtin_impls
|
||||
|
||||
use core::cell::Cell;
|
||||
|
||||
fn should_not_reach() {
|
||||
_ // FIXME: replace this function with panic when that works
|
||||
}
|
||||
|
||||
struct X<'a>(&'a Cell<i32>);
|
||||
impl<'a> Drop for X<'a> {
|
||||
fn drop(&mut self) {
|
||||
self.0.set(self.0.get() + 1)
|
||||
}
|
||||
}
|
||||
|
||||
struct Tuple<'a>(X<'a>, X<'a>, X<'a>);
|
||||
|
||||
fn main() {
|
||||
let s = Cell::new(0);
|
||||
{
|
||||
let x0 = X(&s);
|
||||
let xt = Tuple(x0, X(&s), X(&s));
|
||||
let x1 = xt.1;
|
||||
if s.get() != 0 {
|
||||
should_not_reach();
|
||||
}
|
||||
drop(xt.0);
|
||||
if s.get() != 1 {
|
||||
should_not_reach();
|
||||
}
|
||||
}
|
||||
// FIXME: this should be 3
|
||||
if s.get() != 2 {
|
||||
should_not_reach();
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drop_in_place() {
|
||||
check_pass(
|
||||
|
|
@ -613,6 +657,50 @@ fn main() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn self_with_capital_s() {
|
||||
check_pass(
|
||||
r#"
|
||||
//- minicore: fn, add, copy
|
||||
|
||||
struct S1;
|
||||
|
||||
impl S1 {
|
||||
fn f() {
|
||||
Self;
|
||||
}
|
||||
}
|
||||
|
||||
struct S2 {
|
||||
f1: i32,
|
||||
}
|
||||
|
||||
impl S2 {
|
||||
fn f() {
|
||||
Self { f1: 5 };
|
||||
}
|
||||
}
|
||||
|
||||
struct S3(i32);
|
||||
|
||||
impl S3 {
|
||||
fn f() {
|
||||
Self(2);
|
||||
Self;
|
||||
let this = Self;
|
||||
this(2);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
S1::f();
|
||||
S2::f();
|
||||
S3::f();
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn syscalls() {
|
||||
check_pass(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue