mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-30 13:51:31 +00:00
Merge commit 'aa9bc86125
' into sync-from-ra
This commit is contained in:
parent
1570299af4
commit
c48062fe2a
598 changed files with 57696 additions and 17615 deletions
|
@ -1,18 +1,25 @@
|
|||
//! Compute the binary representation of structs, unions and enums
|
||||
|
||||
use std::ops::Bound;
|
||||
use std::{cmp, ops::Bound};
|
||||
|
||||
use base_db::CrateId;
|
||||
use hir_def::{
|
||||
adt::VariantData,
|
||||
layout::{Integer, IntegerExt, Layout, LayoutCalculator, LayoutError, RustcEnumVariantIdx},
|
||||
AdtId, EnumVariantId, HasModule, LocalEnumVariantId, VariantId,
|
||||
data::adt::VariantData,
|
||||
layout::{Integer, LayoutCalculator, ReprOptions, TargetDataLayout},
|
||||
AdtId, EnumVariantId, LocalEnumVariantId, VariantId,
|
||||
};
|
||||
use la_arena::RawIdx;
|
||||
use smallvec::SmallVec;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{db::HirDatabase, lang_items::is_unsafe_cell, layout::field_ty, Substitution};
|
||||
use crate::{
|
||||
db::HirDatabase,
|
||||
lang_items::is_unsafe_cell,
|
||||
layout::{field_ty, Layout, LayoutError, RustcEnumVariantIdx},
|
||||
Substitution,
|
||||
};
|
||||
|
||||
use super::{layout_of_ty, LayoutCx};
|
||||
use super::LayoutCx;
|
||||
|
||||
pub(crate) fn struct_variant_idx() -> RustcEnumVariantIdx {
|
||||
RustcEnumVariantIdx(LocalEnumVariantId::from_raw(RawIdx::from(0)))
|
||||
|
@ -22,29 +29,29 @@ pub fn layout_of_adt_query(
|
|||
db: &dyn HirDatabase,
|
||||
def: AdtId,
|
||||
subst: Substitution,
|
||||
) -> Result<Layout, LayoutError> {
|
||||
let krate = def.module(db.upcast()).krate();
|
||||
krate: CrateId,
|
||||
) -> Result<Arc<Layout>, LayoutError> {
|
||||
let Some(target) = db.target_data_layout(krate) else { return Err(LayoutError::TargetLayoutNotAvailable) };
|
||||
let cx = LayoutCx { krate, target: &target };
|
||||
let dl = cx.current_data_layout();
|
||||
let handle_variant = |def: VariantId, var: &VariantData| {
|
||||
var.fields()
|
||||
.iter()
|
||||
.map(|(fd, _)| layout_of_ty(db, &field_ty(db, def, fd, &subst), cx.krate))
|
||||
.map(|(fd, _)| db.layout_of_ty(field_ty(db, def, fd, &subst), cx.krate))
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
};
|
||||
let (variants, is_enum, is_union, repr) = match def {
|
||||
let (variants, repr) = match def {
|
||||
AdtId::StructId(s) => {
|
||||
let data = db.struct_data(s);
|
||||
let mut r = SmallVec::<[_; 1]>::new();
|
||||
r.push(handle_variant(s.into(), &data.variant_data)?);
|
||||
(r, false, false, data.repr.unwrap_or_default())
|
||||
(r, data.repr.unwrap_or_default())
|
||||
}
|
||||
AdtId::UnionId(id) => {
|
||||
let data = db.union_data(id);
|
||||
let mut r = SmallVec::new();
|
||||
r.push(handle_variant(id.into(), &data.variant_data)?);
|
||||
(r, false, true, data.repr.unwrap_or_default())
|
||||
(r, data.repr.unwrap_or_default())
|
||||
}
|
||||
AdtId::EnumId(e) => {
|
||||
let data = db.enum_data(e);
|
||||
|
@ -58,22 +65,24 @@ pub fn layout_of_adt_query(
|
|||
)
|
||||
})
|
||||
.collect::<Result<SmallVec<_>, _>>()?;
|
||||
(r, true, false, data.repr.unwrap_or_default())
|
||||
(r, data.repr.unwrap_or_default())
|
||||
}
|
||||
};
|
||||
let variants =
|
||||
variants.iter().map(|x| x.iter().collect::<Vec<_>>()).collect::<SmallVec<[_; 1]>>();
|
||||
let variants = variants
|
||||
.iter()
|
||||
.map(|x| x.iter().map(|x| &**x).collect::<Vec<_>>())
|
||||
.collect::<SmallVec<[_; 1]>>();
|
||||
let variants = variants.iter().map(|x| x.iter().collect()).collect();
|
||||
if is_union {
|
||||
cx.layout_of_union(&repr, &variants).ok_or(LayoutError::Unknown)
|
||||
let result = if matches!(def, AdtId::UnionId(..)) {
|
||||
cx.layout_of_union(&repr, &variants).ok_or(LayoutError::Unknown)?
|
||||
} else {
|
||||
cx.layout_of_struct_or_enum(
|
||||
&repr,
|
||||
&variants,
|
||||
is_enum,
|
||||
is_unsafe_cell(def, db),
|
||||
matches!(def, AdtId::EnumId(..)),
|
||||
is_unsafe_cell(db, def),
|
||||
layout_scalar_valid_range(db, def),
|
||||
|min, max| Integer::repr_discr(&dl, &repr, min, max).unwrap_or((Integer::I8, false)),
|
||||
|min, max| repr_discr(&dl, &repr, min, max).unwrap_or((Integer::I8, false)),
|
||||
variants.iter_enumerated().filter_map(|(id, _)| {
|
||||
let AdtId::EnumId(e) = def else { return None };
|
||||
let d =
|
||||
|
@ -90,15 +99,16 @@ pub fn layout_of_adt_query(
|
|||
// .iter_enumerated()
|
||||
// .any(|(i, v)| v.discr != ty::VariantDiscr::Relative(i.as_u32()))
|
||||
repr.inhibit_enum_layout_opt(),
|
||||
!is_enum
|
||||
!matches!(def, AdtId::EnumId(..))
|
||||
&& variants
|
||||
.iter()
|
||||
.next()
|
||||
.and_then(|x| x.last().map(|x| x.is_unsized()))
|
||||
.unwrap_or(true),
|
||||
)
|
||||
.ok_or(LayoutError::SizeOverflow)
|
||||
}
|
||||
.ok_or(LayoutError::SizeOverflow)?
|
||||
};
|
||||
Ok(Arc::new(result))
|
||||
}
|
||||
|
||||
fn layout_scalar_valid_range(db: &dyn HirDatabase, def: AdtId) -> (Bound<u128>, Bound<u128>) {
|
||||
|
@ -122,6 +132,54 @@ pub fn layout_of_adt_recover(
|
|||
_: &[String],
|
||||
_: &AdtId,
|
||||
_: &Substitution,
|
||||
) -> Result<Layout, LayoutError> {
|
||||
_: &CrateId,
|
||||
) -> Result<Arc<Layout>, LayoutError> {
|
||||
user_error!("infinite sized recursive type");
|
||||
}
|
||||
|
||||
/// Finds the appropriate Integer type and signedness for the given
|
||||
/// signed discriminant range and `#[repr]` attribute.
|
||||
/// N.B.: `u128` values above `i128::MAX` will be treated as signed, but
|
||||
/// that shouldn't affect anything, other than maybe debuginfo.
|
||||
fn repr_discr(
|
||||
dl: &TargetDataLayout,
|
||||
repr: &ReprOptions,
|
||||
min: i128,
|
||||
max: i128,
|
||||
) -> Result<(Integer, bool), LayoutError> {
|
||||
// Theoretically, negative values could be larger in unsigned representation
|
||||
// than the unsigned representation of the signed minimum. However, if there
|
||||
// are any negative values, the only valid unsigned representation is u128
|
||||
// which can fit all i128 values, so the result remains unaffected.
|
||||
let unsigned_fit = Integer::fit_unsigned(cmp::max(min as u128, max as u128));
|
||||
let signed_fit = cmp::max(Integer::fit_signed(min), Integer::fit_signed(max));
|
||||
|
||||
if let Some(ity) = repr.int {
|
||||
let discr = Integer::from_attr(dl, ity);
|
||||
let fit = if ity.is_signed() { signed_fit } else { unsigned_fit };
|
||||
if discr < fit {
|
||||
return Err(LayoutError::UserError(
|
||||
"Integer::repr_discr: `#[repr]` hint too small for \
|
||||
discriminant range of enum "
|
||||
.to_string(),
|
||||
));
|
||||
}
|
||||
return Ok((discr, ity.is_signed()));
|
||||
}
|
||||
|
||||
let at_least = if repr.c() {
|
||||
// This is usually I32, however it can be different on some platforms,
|
||||
// notably hexagon and arm-none/thumb-none
|
||||
dl.c_enum_min_size
|
||||
} else {
|
||||
// repr(Rust) enums try to be as small as possible
|
||||
Integer::I8
|
||||
};
|
||||
|
||||
// If there are no negative values, we can use the unsigned fit.
|
||||
Ok(if min >= 0 {
|
||||
(cmp::max(unsigned_fit, at_least), false)
|
||||
} else {
|
||||
(cmp::max(signed_fit, at_least), true)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
//! Target dependent parameters needed for layouts
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use base_db::CrateId;
|
||||
use hir_def::layout::TargetDataLayout;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::db::HirDatabase;
|
||||
|
||||
|
|
|
@ -2,49 +2,55 @@ use std::collections::HashMap;
|
|||
|
||||
use base_db::fixture::WithFixture;
|
||||
use chalk_ir::{AdtId, TyKind};
|
||||
use hir_def::{
|
||||
db::DefDatabase,
|
||||
use hir_def::db::DefDatabase;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
db::HirDatabase,
|
||||
layout::{Layout, LayoutError},
|
||||
test_db::TestDB,
|
||||
Interner, Substitution,
|
||||
};
|
||||
|
||||
use crate::{db::HirDatabase, test_db::TestDB, Interner, Substitution};
|
||||
|
||||
use super::layout_of_ty;
|
||||
mod closure;
|
||||
|
||||
fn current_machine_data_layout() -> String {
|
||||
project_model::target_data_layout::get(None, None, &HashMap::default()).unwrap()
|
||||
}
|
||||
|
||||
fn eval_goal(ra_fixture: &str, minicore: &str) -> Result<Layout, LayoutError> {
|
||||
fn eval_goal(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutError> {
|
||||
let target_data_layout = current_machine_data_layout();
|
||||
let ra_fixture = format!(
|
||||
"{minicore}//- /main.rs crate:test target_data_layout:{target_data_layout}\n{ra_fixture}",
|
||||
);
|
||||
|
||||
let (db, file_id) = TestDB::with_single_file(&ra_fixture);
|
||||
let module_id = db.module_for_file(file_id);
|
||||
let def_map = module_id.def_map(&db);
|
||||
let scope = &def_map[module_id.local_id].scope;
|
||||
let adt_id = scope
|
||||
.declarations()
|
||||
.find_map(|x| match x {
|
||||
hir_def::ModuleDefId::AdtId(x) => {
|
||||
let name = match x {
|
||||
hir_def::AdtId::StructId(x) => db.struct_data(x).name.to_smol_str(),
|
||||
hir_def::AdtId::UnionId(x) => db.union_data(x).name.to_smol_str(),
|
||||
hir_def::AdtId::EnumId(x) => db.enum_data(x).name.to_smol_str(),
|
||||
};
|
||||
(name == "Goal").then_some(x)
|
||||
}
|
||||
_ => None,
|
||||
let (db, file_ids) = TestDB::with_many_files(&ra_fixture);
|
||||
let (adt_id, module_id) = file_ids
|
||||
.into_iter()
|
||||
.find_map(|file_id| {
|
||||
let module_id = db.module_for_file(file_id);
|
||||
let def_map = module_id.def_map(&db);
|
||||
let scope = &def_map[module_id.local_id].scope;
|
||||
let adt_id = scope.declarations().find_map(|x| match x {
|
||||
hir_def::ModuleDefId::AdtId(x) => {
|
||||
let name = match x {
|
||||
hir_def::AdtId::StructId(x) => db.struct_data(x).name.to_smol_str(),
|
||||
hir_def::AdtId::UnionId(x) => db.union_data(x).name.to_smol_str(),
|
||||
hir_def::AdtId::EnumId(x) => db.enum_data(x).name.to_smol_str(),
|
||||
};
|
||||
(name == "Goal").then_some(x)
|
||||
}
|
||||
_ => None,
|
||||
})?;
|
||||
Some((adt_id, module_id))
|
||||
})
|
||||
.unwrap();
|
||||
let goal_ty = TyKind::Adt(AdtId(adt_id), Substitution::empty(Interner)).intern(Interner);
|
||||
layout_of_ty(&db, &goal_ty, module_id.krate())
|
||||
db.layout_of_ty(goal_ty, module_id.krate())
|
||||
}
|
||||
|
||||
/// A version of `eval_goal` for types that can not be expressed in ADTs, like closures and `impl Trait`
|
||||
fn eval_expr(ra_fixture: &str, minicore: &str) -> Result<Layout, LayoutError> {
|
||||
fn eval_expr(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutError> {
|
||||
let target_data_layout = current_machine_data_layout();
|
||||
let ra_fixture = format!(
|
||||
"{minicore}//- /main.rs crate:test target_data_layout:{target_data_layout}\nfn main(){{let goal = {{{ra_fixture}}};}}",
|
||||
|
@ -68,7 +74,7 @@ fn eval_expr(ra_fixture: &str, minicore: &str) -> Result<Layout, LayoutError> {
|
|||
let b = hir_body.bindings.iter().find(|x| x.1.name.to_smol_str() == "goal").unwrap().0;
|
||||
let infer = db.infer(adt_id.into());
|
||||
let goal_ty = infer.type_of_binding[b].clone();
|
||||
layout_of_ty(&db, &goal_ty, module_id.krate())
|
||||
db.layout_of_ty(goal_ty, module_id.krate())
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
|
@ -81,8 +87,8 @@ fn check_size_and_align(ra_fixture: &str, minicore: &str, size: u64, align: u64)
|
|||
#[track_caller]
|
||||
fn check_size_and_align_expr(ra_fixture: &str, minicore: &str, size: u64, align: u64) {
|
||||
let l = eval_expr(ra_fixture, minicore).unwrap();
|
||||
assert_eq!(l.size.bytes(), size);
|
||||
assert_eq!(l.align.abi.bytes(), align);
|
||||
assert_eq!(l.size.bytes(), size, "size mismatch");
|
||||
assert_eq!(l.align.abi.bytes(), align, "align mismatch");
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
|
@ -118,13 +124,31 @@ macro_rules! size_and_align {
|
|||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! size_and_align_expr {
|
||||
(minicore: $($x:tt),*; stmts: [$($s:tt)*] $($t:tt)*) => {
|
||||
{
|
||||
#[allow(dead_code)]
|
||||
#[allow(unused_must_use)]
|
||||
#[allow(path_statements)]
|
||||
{
|
||||
$($s)*
|
||||
let val = { $($t)* };
|
||||
$crate::layout::tests::check_size_and_align_expr(
|
||||
&format!("{{ {} let val = {{ {} }}; val }}", stringify!($($s)*), stringify!($($t)*)),
|
||||
&format!("//- minicore: {}\n", stringify!($($x),*)),
|
||||
::std::mem::size_of_val(&val) as u64,
|
||||
::std::mem::align_of_val(&val) as u64,
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
($($t:tt)*) => {
|
||||
{
|
||||
#[allow(dead_code)]
|
||||
{
|
||||
let val = { $($t)* };
|
||||
check_size_and_align_expr(
|
||||
$crate::layout::tests::check_size_and_align_expr(
|
||||
stringify!($($t)*),
|
||||
"",
|
||||
::std::mem::size_of_val(&val) as u64,
|
||||
|
@ -196,6 +220,44 @@ fn generic() {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn associated_types() {
|
||||
size_and_align! {
|
||||
trait Tr {
|
||||
type Ty;
|
||||
}
|
||||
|
||||
impl Tr for i32 {
|
||||
type Ty = i64;
|
||||
}
|
||||
|
||||
struct Foo<A: Tr>(<A as Tr>::Ty);
|
||||
struct Bar<A: Tr>(A::Ty);
|
||||
struct Goal(Foo<i32>, Bar<i32>, <i32 as Tr>::Ty);
|
||||
}
|
||||
check_size_and_align(
|
||||
r#"
|
||||
//- /b/mod.rs crate:b
|
||||
pub trait Tr {
|
||||
type Ty;
|
||||
}
|
||||
pub struct Foo<A: Tr>(<A as Tr>::Ty);
|
||||
|
||||
//- /a/mod.rs crate:a deps:b
|
||||
use b::{Tr, Foo};
|
||||
|
||||
struct S;
|
||||
impl Tr for S {
|
||||
type Ty = i64;
|
||||
}
|
||||
struct Goal(Foo<S>);
|
||||
"#,
|
||||
"",
|
||||
8,
|
||||
8,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn return_position_impl_trait() {
|
||||
size_and_align_expr! {
|
||||
|
@ -212,6 +274,45 @@ fn return_position_impl_trait() {
|
|||
fn foo() -> (impl T, impl T, impl T) { (2i64, 5i32, 7i32) }
|
||||
foo()
|
||||
}
|
||||
size_and_align_expr! {
|
||||
minicore: iterators;
|
||||
stmts: []
|
||||
trait Tr {}
|
||||
impl Tr for i32 {}
|
||||
fn foo() -> impl Iterator<Item = impl Tr> {
|
||||
[1, 2, 3].into_iter()
|
||||
}
|
||||
let mut iter = foo();
|
||||
let item = iter.next();
|
||||
(iter, item)
|
||||
}
|
||||
size_and_align_expr! {
|
||||
minicore: future;
|
||||
stmts: []
|
||||
use core::{future::Future, task::{Poll, Context}, pin::pin};
|
||||
use std::{task::Wake, sync::Arc};
|
||||
trait Tr {}
|
||||
impl Tr for i32 {}
|
||||
async fn f() -> impl Tr {
|
||||
2
|
||||
}
|
||||
fn unwrap_fut<T>(inp: impl Future<Output = T>) -> Poll<T> {
|
||||
// In a normal test we could use `loop {}` or `panic!()` here,
|
||||
// but rustc actually runs this code.
|
||||
let pinned = pin!(inp);
|
||||
struct EmptyWaker;
|
||||
impl Wake for EmptyWaker {
|
||||
fn wake(self: Arc<Self>) {
|
||||
}
|
||||
}
|
||||
let waker = Arc::new(EmptyWaker).into();
|
||||
let mut context = Context::from_waker(&waker);
|
||||
let x = pinned.poll(&mut context);
|
||||
x
|
||||
}
|
||||
let x = unwrap_fut(f());
|
||||
x
|
||||
}
|
||||
size_and_align_expr! {
|
||||
struct Foo<T>(T, T, (T, T));
|
||||
trait T {}
|
||||
|
@ -276,6 +377,14 @@ fn niche_optimization() {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn const_eval() {
|
||||
size_and_align! {
|
||||
const X: usize = 5;
|
||||
struct Goal([i32; X]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enums_with_discriminants() {
|
||||
size_and_align! {
|
||||
|
|
257
crates/hir-ty/src/layout/tests/closure.rs
Normal file
257
crates/hir-ty/src/layout/tests/closure.rs
Normal file
|
@ -0,0 +1,257 @@
|
|||
use crate::size_and_align_expr;
|
||||
|
||||
#[test]
|
||||
fn zero_capture_simple() {
|
||||
size_and_align_expr! {
|
||||
|x: i32| x + 2
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn move_simple() {
|
||||
size_and_align_expr! {
|
||||
minicore: copy;
|
||||
stmts: []
|
||||
let y: i32 = 5;
|
||||
move |x: i32| {
|
||||
x + y
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ref_simple() {
|
||||
size_and_align_expr! {
|
||||
minicore: copy;
|
||||
stmts: [
|
||||
let y: i32 = 5;
|
||||
]
|
||||
|x: i32| {
|
||||
x + y
|
||||
}
|
||||
}
|
||||
size_and_align_expr! {
|
||||
minicore: copy;
|
||||
stmts: [
|
||||
let mut y: i32 = 5;
|
||||
]
|
||||
|x: i32| {
|
||||
y = y + x;
|
||||
y
|
||||
}
|
||||
}
|
||||
size_and_align_expr! {
|
||||
minicore: copy, deref_mut;
|
||||
stmts: [
|
||||
let y: &mut i32 = &mut 5;
|
||||
]
|
||||
|x: i32| {
|
||||
*y += x;
|
||||
}
|
||||
}
|
||||
size_and_align_expr! {
|
||||
minicore: copy;
|
||||
stmts: [
|
||||
struct X(i32, i64);
|
||||
let x: X = X(2, 6);
|
||||
]
|
||||
|| {
|
||||
x
|
||||
}
|
||||
}
|
||||
size_and_align_expr! {
|
||||
minicore: copy, deref_mut;
|
||||
stmts: [
|
||||
struct X(i32, i64);
|
||||
let x: &mut X = &mut X(2, 6);
|
||||
]
|
||||
|| {
|
||||
(*x).0 as i64 + x.1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ref_then_mut_then_move() {
|
||||
size_and_align_expr! {
|
||||
minicore: copy;
|
||||
stmts: [
|
||||
struct X(i32, i64);
|
||||
let mut x: X = X(2, 6);
|
||||
]
|
||||
|| {
|
||||
&x;
|
||||
&mut x;
|
||||
x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nested_closures() {
|
||||
size_and_align_expr! {
|
||||
|| {
|
||||
|| {
|
||||
|| {
|
||||
let x = 2;
|
||||
move || {
|
||||
move || {
|
||||
x
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn capture_specific_fields2() {
|
||||
size_and_align_expr! {
|
||||
minicore: copy;
|
||||
stmts: [
|
||||
let x = &mut 2;
|
||||
]
|
||||
|| {
|
||||
*x = 5;
|
||||
&x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn capture_specific_fields() {
|
||||
size_and_align_expr! {
|
||||
struct X(i64, i32, (u8, i128));
|
||||
let y: X = X(2, 5, (7, 3));
|
||||
move |x: i64| {
|
||||
y.0 + x + (y.2 .0 as i64)
|
||||
}
|
||||
}
|
||||
size_and_align_expr! {
|
||||
struct X(i64, i32, (u8, i128));
|
||||
let y: X = X(2, 5, (7, 3));
|
||||
move |x: i64| {
|
||||
let _ = &y;
|
||||
y.0 + x + (y.2 .0 as i64)
|
||||
}
|
||||
}
|
||||
size_and_align_expr! {
|
||||
minicore: copy;
|
||||
stmts: [
|
||||
struct X(i64, i32, (u8, i128));
|
||||
let y: X = X(2, 5, (7, 3));
|
||||
]
|
||||
let y = &y;
|
||||
move |x: i64| {
|
||||
y.0 + x + (y.2 .0 as i64)
|
||||
}
|
||||
}
|
||||
size_and_align_expr! {
|
||||
struct X(i64, i32, (u8, i128));
|
||||
let y: X = X(2, 5, (7, 3));
|
||||
move |x: i64| {
|
||||
let X(a, _, (b, _)) = y;
|
||||
a + x + (b as i64)
|
||||
}
|
||||
}
|
||||
size_and_align_expr! {
|
||||
struct X(i64, i32, (u8, i128));
|
||||
let y = &&X(2, 5, (7, 3));
|
||||
move |x: i64| {
|
||||
let X(a, _, (b, _)) = y;
|
||||
*a + x + (*b as i64)
|
||||
}
|
||||
}
|
||||
size_and_align_expr! {
|
||||
struct X(i64, i32, (u8, i128));
|
||||
let y: X = X(2, 5, (7, 3));
|
||||
move |x: i64| {
|
||||
match y {
|
||||
X(a, _, (b, _)) => a + x + (b as i64),
|
||||
}
|
||||
}
|
||||
}
|
||||
size_and_align_expr! {
|
||||
struct X(i64, i32, (u8, i128));
|
||||
let y: X = X(2, 5, (7, 3));
|
||||
move |x: i64| {
|
||||
let X(a @ 2, _, (b, _)) = y else { return 5 };
|
||||
a + x + (b as i64)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn match_pattern() {
|
||||
size_and_align_expr! {
|
||||
struct X(i64, i32, (u8, i128));
|
||||
let y: X = X(2, 5, (7, 3));
|
||||
move |x: i64| {
|
||||
match y {
|
||||
_ => x,
|
||||
}
|
||||
}
|
||||
}
|
||||
size_and_align_expr! {
|
||||
minicore: copy;
|
||||
stmts: [
|
||||
struct X(i64, i32, (u8, i128));
|
||||
let y: X = X(2, 5, (7, 3));
|
||||
]
|
||||
|x: i64| {
|
||||
match y {
|
||||
X(_a, _, _c) => x,
|
||||
}
|
||||
}
|
||||
}
|
||||
size_and_align_expr! {
|
||||
minicore: copy;
|
||||
stmts: [
|
||||
struct X(i64, i32, (u8, i128));
|
||||
let y: X = X(2, 5, (7, 3));
|
||||
]
|
||||
|x: i64| {
|
||||
match y {
|
||||
_y => x,
|
||||
}
|
||||
}
|
||||
}
|
||||
size_and_align_expr! {
|
||||
minicore: copy;
|
||||
stmts: [
|
||||
struct X(i64, i32, (u8, i128));
|
||||
let y: X = X(2, 5, (7, 3));
|
||||
]
|
||||
|x: i64| {
|
||||
match y {
|
||||
ref _y => x,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ellipsis_pattern() {
|
||||
size_and_align_expr! {
|
||||
struct X(i8, u16, i32, u64, i128, u8);
|
||||
let y: X = X(1, 2, 3, 4, 5, 6);
|
||||
move |_: i64| {
|
||||
let X(_a, .., _b, _c) = y;
|
||||
}
|
||||
}
|
||||
size_and_align_expr! {
|
||||
struct X { a: i32, b: u8, c: i128}
|
||||
let y: X = X { a: 1, b: 2, c: 3 };
|
||||
move |_: i64| {
|
||||
let X { a, b, .. } = y;
|
||||
_ = (a, b);
|
||||
}
|
||||
}
|
||||
size_and_align_expr! {
|
||||
let y: (&&&(i8, u16, i32, u64, i128, u8), u16, i32, u64, i128, u8) = (&&&(1, 2, 3, 4, 5, 6), 2, 3, 4, 5, 6);
|
||||
move |_: i64| {
|
||||
let ((_a, .., _b, _c), .., _e, _f) = y;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue