diff options
Diffstat (limited to 'src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs')
-rw-r--r-- | src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs | 115 |
1 files changed, 105 insertions, 10 deletions
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 53838cf41..067bdc960 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 @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use base_db::fixture::WithFixture; use chalk_ir::{AdtId, TyKind}; use hir_def::{ @@ -5,20 +7,16 @@ use hir_def::{ layout::{Layout, LayoutError}, }; -use crate::{test_db::TestDB, Interner, Substitution}; +use crate::{db::HirDatabase, test_db::TestDB, Interner, Substitution}; use super::layout_of_ty; -fn eval_goal(ra_fixture: &str, minicore: &str) -> Result<Layout, LayoutError> { - // using unstable cargo features failed, fall back to using plain rustc - let mut cmd = std::process::Command::new("rustc"); - cmd.args(["-Z", "unstable-options", "--print", "target-spec-json"]).env("RUSTC_BOOTSTRAP", "1"); - let output = cmd.output().unwrap(); - assert!(output.status.success(), "{}", output.status); - let stdout = String::from_utf8(output.stdout).unwrap(); - let target_data_layout = - stdout.split_once(r#""data-layout": ""#).unwrap().1.split_once('"').unwrap().0.to_owned(); +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> { + 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}", ); @@ -45,6 +43,42 @@ fn eval_goal(ra_fixture: &str, minicore: &str) -> Result<Layout, LayoutError> { layout_of_ty(&db, &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> { + 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}}};}}", + ); + + 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::FunctionId(x) => { + let name = db.function_data(x).name.to_smol_str(); + (name == "main").then_some(x) + } + _ => None, + }) + .unwrap(); + let hir_body = db.body(adt_id.into()); + let pat = hir_body + .pats + .iter() + .find(|x| match x.1 { + hir_def::expr::Pat::Bind { name, .. } => name.to_smol_str() == "goal", + _ => false, + }) + .unwrap() + .0; + let infer = db.infer(adt_id.into()); + let goal_ty = infer.type_of_pat[pat].clone(); + layout_of_ty(&db, &goal_ty, module_id.krate()) +} + #[track_caller] fn check_size_and_align(ra_fixture: &str, minicore: &str, size: u64, align: u64) { let l = eval_goal(ra_fixture, minicore).unwrap(); @@ -53,6 +87,13 @@ 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); +} + +#[track_caller] fn check_fail(ra_fixture: &str, e: LayoutError) { let r = eval_goal(ra_fixture, ""); assert_eq!(r, Err(e)); @@ -85,11 +126,31 @@ macro_rules! size_and_align { }; } +macro_rules! size_and_align_expr { + ($($t:tt)*) => { + { + #[allow(dead_code)] + { + let val = { $($t)* }; + check_size_and_align_expr( + stringify!($($t)*), + "", + ::std::mem::size_of_val(&val) as u64, + ::std::mem::align_of_val(&val) as u64, + ); + } + } + }; +} + #[test] fn hello_world() { size_and_align! { struct Goal(i32); } + size_and_align_expr! { + 2i32 + } } #[test] @@ -144,6 +205,40 @@ fn generic() { } #[test] +fn return_position_impl_trait() { + size_and_align_expr! { + trait T {} + impl T for i32 {} + impl T for i64 {} + fn foo() -> impl T { 2i64 } + foo() + } + size_and_align_expr! { + trait T {} + impl T for i32 {} + impl T for i64 {} + fn foo() -> (impl T, impl T, impl T) { (2i64, 5i32, 7i32) } + foo() + } + size_and_align_expr! { + struct Foo<T>(T, T, (T, T)); + trait T {} + impl T for Foo<i32> {} + impl T for Foo<i64> {} + + fn foo() -> Foo<impl T> { Foo( + Foo(1i64, 2, (3, 4)), + Foo(5, 6, (7, 8)), + ( + Foo(1i64, 2, (3, 4)), + Foo(5, 6, (7, 8)), + ), + ) } + foo() + } +} + +#[test] fn enums() { size_and_align! { enum Goal { |