From 679bb21633d6bbbf04b4cba5cb70f73cc5f5de19 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 19 Jun 2021 18:17:57 +0200 Subject: Add coverage mark for block local impls --- crates/hir_ty/src/chalk_db.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/hir_ty/src/chalk_db.rs b/crates/hir_ty/src/chalk_db.rs index a4c09c742..a55b99de0 100644 --- a/crates/hir_ty/src/chalk_db.rs +++ b/crates/hir_ty/src/chalk_db.rs @@ -2,6 +2,7 @@ //! about the code that Chalk needs. use std::sync::Arc; +use cov_mark::hit; use log::debug; use chalk_ir::{cast::Cast, fold::shift::Shift, CanonicalVarKinds}; @@ -106,7 +107,9 @@ impl<'a> chalk_solve::RustIrDatabase for ChalkContext<'a> { }; fn local_impls(db: &dyn HirDatabase, module: ModuleId) -> Option> { - db.trait_impls_in_block(module.containing_block()?) + let block = module.containing_block()?; + hit!(block_local_impls); + db.trait_impls_in_block(block) } // Note: Since we're using impls_for_trait, only impls where the trait -- cgit v1.2.3 From 04fbdce426ac8e618ac8b5d136c58cf3427bdd6c Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 20 Jun 2021 16:37:50 +0200 Subject: Unify check_mismatches and check_types --- crates/hir_ty/src/test_db.rs | 10 +- crates/hir_ty/src/tests.rs | 151 ++++++++++----- crates/hir_ty/src/tests/coercion.rs | 4 +- crates/hir_ty/src/tests/macros.rs | 27 +-- crates/hir_ty/src/tests/method_resolution.rs | 264 ++++++++++++--------------- crates/hir_ty/src/tests/patterns.rs | 4 +- crates/hir_ty/src/tests/regression.rs | 11 +- crates/hir_ty/src/tests/simple.rs | 18 +- crates/hir_ty/src/tests/traits.rs | 244 +++++++++---------------- 9 files changed, 353 insertions(+), 380 deletions(-) diff --git a/crates/hir_ty/src/test_db.rs b/crates/hir_ty/src/test_db.rs index 4640ea821..b99a03492 100644 --- a/crates/hir_ty/src/test_db.rs +++ b/crates/hir_ty/src/test_db.rs @@ -86,16 +86,20 @@ impl FileLoader for TestDB { } impl TestDB { - pub(crate) fn module_for_file(&self, file_id: FileId) -> ModuleId { + pub(crate) fn module_for_file_opt(&self, file_id: FileId) -> Option { for &krate in self.relevant_crates(file_id).iter() { let crate_def_map = self.crate_def_map(krate); for (local_id, data) in crate_def_map.modules() { if data.origin.file_id() == Some(file_id) { - return crate_def_map.module_id(local_id); + return Some(crate_def_map.module_id(local_id)); } } } - panic!("Can't find module for file") + None + } + + pub(crate) fn module_for_file(&self, file_id: FileId) -> ModuleId { + self.module_for_file_opt(file_id).unwrap() } pub(crate) fn extract_annotations(&self) -> FxHashMap> { diff --git a/crates/hir_ty/src/tests.rs b/crates/hir_ty/src/tests.rs index b873585c4..c4f981b44 100644 --- a/crates/hir_ty/src/tests.rs +++ b/crates/hir_ty/src/tests.rs @@ -59,14 +59,16 @@ fn setup_tracing() -> Option { } fn check_types(ra_fixture: &str) { - check_types_impl(ra_fixture, false) + check_impl(ra_fixture, false, true) } fn check_types_source_code(ra_fixture: &str) { + // TODO check_types_impl(ra_fixture, true) } fn check_types_impl(ra_fixture: &str, display_source: bool) { + // TODO let _tracing = setup_tracing(); let db = TestDB::with_files(ra_fixture); let mut checked_one = false; @@ -88,22 +90,47 @@ fn check_types_impl(ra_fixture: &str, display_source: bool) { } fn check_no_mismatches(ra_fixture: &str) { - check_mismatches_impl(ra_fixture, true) + check_impl(ra_fixture, true, false) } -#[allow(unused)] -fn check_mismatches(ra_fixture: &str) { - check_mismatches_impl(ra_fixture, false) +fn check(ra_fixture: &str) { + check_impl(ra_fixture, false, false) } -fn check_mismatches_impl(ra_fixture: &str, allow_none: bool) { +fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool) { let _tracing = setup_tracing(); - let (db, file_id) = TestDB::with_single_file(ra_fixture); - let module = db.module_for_file(file_id); - let def_map = module.def_map(&db); + let (db, files) = TestDB::with_many_files(ra_fixture); + + let mut had_annotations = false; + let mut mismatches = HashMap::new(); + let mut types = HashMap::new(); + for (file_id, annotations) in db.extract_annotations() { + for (range, expected) in annotations { + let file_range = FileRange { file_id, range }; + if only_types { + types.insert(file_range, expected); + } else if expected.starts_with("type: ") { + types.insert(file_range, expected.trim_start_matches("type: ").to_string()); + } else if expected.starts_with("expected") { + mismatches.insert(file_range, expected); + } else { + panic!("unexpected annotation: {}", expected); + } + had_annotations = true; + } + } + assert!(had_annotations || allow_none, "no `//^` annotations found"); let mut defs: Vec = Vec::new(); - visit_module(&db, &def_map, module.local_id, &mut |it| defs.push(it)); + for file_id in files { + let module = db.module_for_file_opt(file_id); + let module = match module { + Some(m) => m, + None => continue, + }; + let def_map = module.def_map(&db); + visit_module(&db, &def_map, module.local_id, &mut |it| defs.push(it)); + } defs.sort_by_key(|def| match def { DefWithBodyId::FunctionId(it) => { let loc = it.lookup(&db); @@ -118,25 +145,46 @@ fn check_mismatches_impl(ra_fixture: &str, allow_none: bool) { loc.source(&db).value.syntax().text_range().start() } }); - let mut mismatches = HashMap::new(); - let mut push_mismatch = |src_ptr: InFile, mismatch: TypeMismatch| { - let range = src_ptr.value.text_range(); - if src_ptr.file_id.call_node(&db).is_some() { - panic!("type mismatch in macro expansion"); - } - let file_range = FileRange { file_id: src_ptr.file_id.original_file(&db), range }; - let actual = format!( - "expected {}, got {}", - mismatch.expected.display_test(&db), - mismatch.actual.display_test(&db) - ); - mismatches.insert(file_range, actual); - }; + let mut unexpected_type_mismatches = String::new(); for def in defs { let (_body, body_source_map) = db.body_with_source_map(def); let inference_result = db.infer(def); + + for (pat, ty) in inference_result.type_of_pat.iter() { + let node = match body_source_map.pat_syntax(pat) { + Ok(sp) => { + let root = db.parse_or_expand(sp.file_id).unwrap(); + sp.map(|ptr| { + ptr.either( + |it| it.to_node(&root).syntax().clone(), + |it| it.to_node(&root).syntax().clone(), + ) + }) + } + Err(SyntheticSyntax) => continue, + }; + let range = node.as_ref().original_file_range(&db); + if let Some(annotation) = types.remove(&range) { + assert_eq!(ty.display_test(&db).to_string(), annotation); + } + } + + for (expr, ty) in inference_result.type_of_expr.iter() { + let node = match body_source_map.expr_syntax(expr) { + Ok(sp) => { + let root = db.parse_or_expand(sp.file_id).unwrap(); + sp.map(|ptr| ptr.to_node(&root).syntax().clone()) + } + Err(SyntheticSyntax) => continue, + }; + let range = node.as_ref().original_file_range(&db); + if let Some(annotation) = types.remove(&range) { + assert_eq!(ty.display_test(&db).to_string(), annotation); + } + } + for (pat, mismatch) in inference_result.pat_type_mismatches() { - let syntax_ptr = match body_source_map.pat_syntax(pat) { + let node = match body_source_map.pat_syntax(pat) { Ok(sp) => { let root = db.parse_or_expand(sp.file_id).unwrap(); sp.map(|ptr| { @@ -148,7 +196,17 @@ fn check_mismatches_impl(ra_fixture: &str, allow_none: bool) { } Err(SyntheticSyntax) => continue, }; - push_mismatch(syntax_ptr, mismatch.clone()); + let range = node.as_ref().original_file_range(&db); + let actual = format!( + "expected {}, got {}", + mismatch.expected.display_test(&db), + mismatch.actual.display_test(&db) + ); + if let Some(annotation) = mismatches.remove(&range) { + assert_eq!(actual, annotation); + } else { + format_to!(unexpected_type_mismatches, "{:?}: {}\n", range.range, actual); + } } for (expr, mismatch) in inference_result.expr_type_mismatches() { let node = match body_source_map.expr_syntax(expr) { @@ -158,28 +216,37 @@ fn check_mismatches_impl(ra_fixture: &str, allow_none: bool) { } Err(SyntheticSyntax) => continue, }; - push_mismatch(node, mismatch.clone()); - } - } - let mut checked_one = false; - for (file_id, annotations) in db.extract_annotations() { - for (range, expected) in annotations { - let file_range = FileRange { file_id, range }; - if let Some(mismatch) = mismatches.remove(&file_range) { - assert_eq!(mismatch, expected); + let range = node.as_ref().original_file_range(&db); + let actual = format!( + "expected {}, got {}", + mismatch.expected.display_test(&db), + mismatch.actual.display_test(&db) + ); + if let Some(annotation) = mismatches.remove(&range) { + assert_eq!(actual, annotation); } else { - assert!(false, "Expected mismatch not encountered: {}\n", expected); + format_to!(unexpected_type_mismatches, "{:?}: {}\n", range.range, actual); } - checked_one = true; } } + let mut buf = String::new(); - for (range, mismatch) in mismatches { - format_to!(buf, "{:?}: {}\n", range.range, mismatch,); + if !unexpected_type_mismatches.is_empty() { + format_to!(buf, "Unexpected type mismatches:\n{}", unexpected_type_mismatches); } - assert!(buf.is_empty(), "Unexpected type mismatches:\n{}", buf); - - assert!(checked_one || allow_none, "no `//^` annotations found"); + if !mismatches.is_empty() { + format_to!(buf, "Unchecked mismatch annotations:\n"); + for m in mismatches { + format_to!(buf, "{:?}: {}\n", m.0.range, m.1); + } + } + if !types.is_empty() { + format_to!(buf, "Unchecked type annotations:\n"); + for t in types { + format_to!(buf, "{:?}: type {}\n", t.0.range, t.1); + } + } + assert!(buf.is_empty(), "{}", buf); } fn type_at_range(db: &TestDB, pos: FileRange) -> Ty { diff --git a/crates/hir_ty/src/tests/coercion.rs b/crates/hir_ty/src/tests/coercion.rs index 713b74165..24ce5bcca 100644 --- a/crates/hir_ty/src/tests/coercion.rs +++ b/crates/hir_ty/src/tests/coercion.rs @@ -842,9 +842,9 @@ fn infer_two_closures_lub() { fn foo(c: i32) { let add = |a: i32, b: i32| a + b; let sub = |a, b| a - b; - //^ |i32, i32| -> i32 + //^^^^^^^^^^^^ |i32, i32| -> i32 if c > 42 { add } else { sub }; - //^ fn(i32, i32) -> i32 + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ fn(i32, i32) -> i32 } "#, ) diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs index d14103aab..6c3d46caf 100644 --- a/crates/hir_ty/src/tests/macros.rs +++ b/crates/hir_ty/src/tests/macros.rs @@ -435,11 +435,11 @@ fn processes_impls_generated_by_macros() { macro_rules! m { ($ident:ident) => (impl Trait for $ident {}) } -trait Trait { fn foo(self) -> u128 {} } +trait Trait { fn foo(self) -> u128 { 0 } } struct S; m!(S); fn test() { S.foo(); } - //^ u128 + //^^^^^^^ u128 "#, ); } @@ -457,7 +457,7 @@ impl S { } fn test() { S.foo(); } - //^ u128 + //^^^^^^^ u128 "#, ); } @@ -479,7 +479,7 @@ impl S { } fn test() { S.foo(); } - //^ u128 + //^^^^^^^ u128 "#, ); } @@ -743,7 +743,7 @@ include!("foo.rs"); fn main() { bar(); -} //^ u32 +} //^^^^^ u32 //- /foo.rs fn bar() -> u32 {0} @@ -781,7 +781,7 @@ include!("f/foo.rs"); fn main() { bar::bar(); -} //^ u32 +} //^^^^^^^^^^ u32 //- /f/foo.rs pub mod bar; @@ -879,7 +879,7 @@ include!(concat!("f", "oo.rs")); fn main() { bar(); -} //^ u32 +} //^^^^^ u32 //- /foo.rs fn bar() -> u32 {0} @@ -905,7 +905,7 @@ include!(concat!(env!("OUT_DIR"), "/foo.rs")); fn main() { bar(); -} //^ {unknown} +} //^^^^^ {unknown} //- /foo.rs fn bar() -> u32 {0} @@ -923,7 +923,7 @@ macro_rules! include {() => {}} include!("main.rs"); fn main() { - 0 + 0; } //^ i32 "#, ); @@ -979,7 +979,7 @@ fn infer_derive_clone_simple() { struct S; fn test() { S.clone(); -} //^ S +} //^^^^^^^^^ S //- /lib.rs crate:core pub mod prelude { @@ -1028,7 +1028,7 @@ pub struct S; use core::S; fn test() { S.clone(); -} //^ S +} //^^^^^^^^^ S "#, ); } @@ -1044,7 +1044,8 @@ struct S; struct Wrapper(T); struct NonClone; fn test() { - (Wrapper(S).clone(), Wrapper(NonClone).clone()); + let x = (Wrapper(S).clone(), Wrapper(NonClone).clone()); + x; //^ (Wrapper, {unknown}) } @@ -1079,7 +1080,7 @@ struct S{} fn test() { S{}; -} //^ S +} //^^^ S "#, ); } diff --git a/crates/hir_ty/src/tests/method_resolution.rs b/crates/hir_ty/src/tests/method_resolution.rs index d9b5ee9cf..3f7a37295 100644 --- a/crates/hir_ty/src/tests/method_resolution.rs +++ b/crates/hir_ty/src/tests/method_resolution.rs @@ -257,7 +257,7 @@ fn test() { mod foo { struct S; impl S { - fn thing() -> i128 {} + fn thing() -> i128 { 0 } } } "#, @@ -267,164 +267,128 @@ mod foo { #[test] fn infer_trait_method_simple() { // the trait implementation is intentionally incomplete -- it shouldn't matter - check_infer( + check_types( r#" - trait Trait1 { - fn method(&self) -> u32; - } - struct S1; - impl Trait1 for S1 {} - trait Trait2 { - fn method(&self) -> i128; - } - struct S2; - impl Trait2 for S2 {} - fn test() { - S1.method(); // -> u32 - S2.method(); // -> i128 - } +trait Trait1 { + fn method(&self) -> u32; +} +struct S1; +impl Trait1 for S1 {} +trait Trait2 { + fn method(&self) -> i128; +} +struct S2; +impl Trait2 for S2 {} +fn test() { + S1.method(); + //^^^^^^^^^^^ u32 + S2.method(); // -> i128 + //^^^^^^^^^^^ i128 +} "#, - expect![[r#" - 30..34 'self': &Self - 109..113 'self': &Self - 169..227 '{ ...i128 }': () - 175..177 'S1': S1 - 175..186 'S1.method()': u32 - 202..204 'S2': S2 - 202..213 'S2.method()': i128 - "#]], ); } #[test] fn infer_trait_method_scoped() { // the trait implementation is intentionally incomplete -- it shouldn't matter - check_infer( + check_types( r#" - struct S; - mod foo { - pub trait Trait1 { - fn method(&self) -> u32; - } - impl Trait1 for super::S {} - } - mod bar { - pub trait Trait2 { - fn method(&self) -> i128; - } - impl Trait2 for super::S {} - } +struct S; +mod foo { + pub trait Trait1 { + fn method(&self) -> u32; + } + impl Trait1 for super::S {} +} +mod bar { + pub trait Trait2 { + fn method(&self) -> i128; + } + impl Trait2 for super::S {} +} - mod foo_test { - use super::S; - use super::foo::Trait1; - fn test() { - S.method(); // -> u32 - } - } +mod foo_test { + use super::S; + use super::foo::Trait1; + fn test() { + S.method(); + //^^^^^^^^^^ u32 + } +} - mod bar_test { - use super::S; - use super::bar::Trait2; - fn test() { - S.method(); // -> i128 - } - } +mod bar_test { + use super::S; + use super::bar::Trait2; + fn test() { + S.method(); + //^^^^^^^^^^ i128 + } +} "#, - expect![[r#" - 62..66 'self': &Self - 168..172 'self': &Self - 299..336 '{ ... }': () - 309..310 'S': S - 309..319 'S.method()': u32 - 415..453 '{ ... }': () - 425..426 'S': S - 425..435 'S.method()': i128 - "#]], ); } #[test] fn infer_trait_method_generic_1() { // the trait implementation is intentionally incomplete -- it shouldn't matter - check_infer( + check_types( r#" - trait Trait { - fn method(&self) -> T; - } - struct S; - impl Trait for S {} - fn test() { - S.method(); - } +trait Trait { + fn method(&self) -> T; +} +struct S; +impl Trait for S {} +fn test() { + S.method(); + //^^^^^^^^^^ u32 +} "#, - expect![[r#" - 32..36 'self': &Self - 91..110 '{ ...d(); }': () - 97..98 'S': S - 97..107 'S.method()': u32 - "#]], ); } #[test] fn infer_trait_method_generic_more_params() { // the trait implementation is intentionally incomplete -- it shouldn't matter - check_infer( + check_types( r#" - trait Trait { - fn method1(&self) -> (T1, T2, T3); - fn method2(&self) -> (T3, T2, T1); - } - struct S1; - impl Trait for S1 {} - struct S2; - impl Trait for S2 {} - fn test() { - S1.method1(); // u8, u16, u32 - S1.method2(); // u32, u16, u8 - S2.method1(); // i8, i16, {unknown} - S2.method2(); // {unknown}, i16, i8 - } +trait Trait { + fn method1(&self) -> (T1, T2, T3); + fn method2(&self) -> (T3, T2, T1); +} +struct S1; +impl Trait for S1 {} +struct S2; +impl Trait for S2 {} +fn test() { + S1.method1(); + //^^^^^^^^^^^^ (u8, u16, u32) + S1.method2(); + //^^^^^^^^^^^^ (u32, u16, u8) + S2.method1(); + //^^^^^^^^^^^^ (i8, i16, {unknown}) + S2.method2(); + //^^^^^^^^^^^^ ({unknown}, i16, i8) +} "#, - expect![[r#" - 42..46 'self': &Self - 81..85 'self': &Self - 209..360 '{ ..., i8 }': () - 215..217 'S1': S1 - 215..227 'S1.method1()': (u8, u16, u32) - 249..251 'S1': S1 - 249..261 'S1.method2()': (u32, u16, u8) - 283..285 'S2': S2 - 283..295 'S2.method1()': (i8, i16, {unknown}) - 323..325 'S2': S2 - 323..335 'S2.method2()': ({unknown}, i16, i8) - "#]], ); } #[test] fn infer_trait_method_generic_2() { // the trait implementation is intentionally incomplete -- it shouldn't matter - check_infer( + check_types( r#" - trait Trait { - fn method(&self) -> T; - } - struct S(T); - impl Trait for S {} - fn test() { - S(1u32).method(); - } +trait Trait { + fn method(&self) -> T; +} +struct S(T); +impl Trait for S {} +fn test() { + S(1u32).method(); + //^^^^^^^^^^^^^^^^ u32 +} "#, - expect![[r#" - 32..36 'self': &Self - 101..126 '{ ...d(); }': () - 107..108 'S': S(u32) -> S - 107..114 'S(1u32)': S - 107..123 'S(1u32...thod()': u32 - 109..113 '1u32': u32 - "#]], ); } @@ -685,10 +649,10 @@ fn method_resolution_unify_impl_self_type() { check_types( r#" struct S; -impl S { fn foo(&self) -> u8 {} } -impl S { fn foo(&self) -> i8 {} } +impl S { fn foo(&self) -> u8 { 0 } } +impl S { fn foo(&self) -> i8 { 0 } } fn test() { (S::.foo(), S::.foo()); } - //^ (u8, i8) + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (u8, i8) "#, ); } @@ -702,7 +666,7 @@ struct S; impl S { fn foo(&self) -> i8 { 0 } } impl Trait for S { fn foo(self) -> u128 { 0 } } fn test() { S.foo(); } - //^ u128 + //^^^^^^^ u128 "#, ); } @@ -716,7 +680,7 @@ struct S; impl Clone for S {} impl Clone for &S {} fn test() { (S.clone(), (&S).clone(), (&&S).clone()); } - //^ (S, S, &S) + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (S, S, &S) "#, ); } @@ -730,7 +694,7 @@ struct S; impl S { fn foo(self) -> i8 { 0 } } impl Trait for &S { fn foo(self) -> u128 { 0 } } fn test() { (&S).foo(); } - //^ u128 + //^^^^^^^^^^ u128 "#, ); } @@ -744,7 +708,7 @@ struct S; impl S { fn foo(self) -> i8 { 0 } } impl Trait for S { fn foo(self) -> u128 { 0 } } fn test() { S.foo(); } - //^ i8 + //^^^^^^^ i8 "#, ); } @@ -758,7 +722,7 @@ struct S; impl S { fn foo(&self) -> i8 { 0 } } impl Trait for &S { fn foo(self) -> u128 { 0 } } fn test() { S.foo(); } - //^ i8 + //^^^^^^^ i8 "#, ); } @@ -771,7 +735,7 @@ trait Trait { fn foo(self) -> u128; } struct S; impl Trait for S { fn foo(self) -> u128 { 0 } } fn test() { (&S).foo(); } - //^ u128 + //^^^^^^^^^^ u128 "#, ); } @@ -784,7 +748,7 @@ fn method_resolution_unsize_array() { fn test() { let a = [1, 2, 3]; a.len(); -} //^ usize +} //^^^^^^^ usize "#, ); } @@ -799,7 +763,7 @@ impl Clone for S {} fn test() { S.clone(); - //^ S + //^^^^^^^^^ S } //- /lib.rs crate:core @@ -823,7 +787,7 @@ trait Trait { fn foo(self) -> u128; } struct S; impl Trait for T where T: UnknownTrait {} fn test() { (&S).foo(); } - //^ u128 + //^^^^^^^^^^ u128 "#, ); } @@ -841,7 +805,7 @@ trait Trait { fn foo(self) -> u128; } struct S; impl Trait for T where T: Clone {} fn test() { (&S).foo(); } - //^ {unknown} + //^^^^^^^^^^ {unknown} "#, ); } @@ -856,7 +820,7 @@ trait Trait { fn foo(self) -> u128; } struct S; impl Trait for T {} fn test() { (&S).foo(); } - //^ {unknown} + //^^^^^^^^^^ {unknown} "#, ); } @@ -871,7 +835,7 @@ struct S; impl Clone for S {} impl Trait for T where T: Clone {} fn test() { S.foo(); } - //^ u128 + //^^^^^^^ u128 "#, ); } @@ -887,7 +851,7 @@ struct S2; impl From for S1 {} impl Into for T where U: From {} fn test() { S2.into(); } - //^ {unknown} + //^^^^^^^^^ {unknown} "#, ); } @@ -903,7 +867,7 @@ struct S2; impl From for S1 {} impl> Into for T {} fn test() { S2.into(); } - //^ {unknown} + //^^^^^^^^^ {unknown} "#, ); } @@ -933,7 +897,7 @@ fn main() { let a = Wrapper::>::new(1.0); let b = Wrapper::>::new(1.0); (a, b); - //^ (Wrapper>, Wrapper>) + //^^^^^^ (Wrapper>, Wrapper>) } "#, ); @@ -947,7 +911,7 @@ fn method_resolution_encountering_fn_type() { fn foo() {} trait FnOnce { fn call(self); } fn test() { foo.call(); } - //^ {unknown} + //^^^^^^^^^^ {unknown} "#, ); } @@ -1013,7 +977,7 @@ where Wrapper: a::Foo, { t.foo(); -} //^ {unknown} +} //^^^^^^^ {unknown} "#, ); } @@ -1030,7 +994,7 @@ impl A { fn main() { A::from(3); -} //^ A +} //^^^^^^^^^^ A "#, ); } @@ -1058,7 +1022,7 @@ trait FnX {} impl Trait for S where C: FnX, B: SendX {} fn test() { (S {}).method(); } - //^ () + //^^^^^^^^^^^^^^^ () "#, ); } @@ -1143,8 +1107,8 @@ impl Slice { fn main() { let foo: Slice; - (foo.into_vec()); // we don't actually support arbitrary self types, but we shouldn't crash at least -} //^ {unknown} + foo.into_vec(); // we shouldn't crash on this at least +} //^^^^^^^^^^^^^^ {unknown} "#, ); } @@ -1165,7 +1129,7 @@ impl dyn Foo + '_ { fn main() { let f = &42u32 as &dyn Foo; f.dyn_foo(); - // ^u32 + // ^^^^^^^^^^^ u32 } "#, ); @@ -1376,11 +1340,11 @@ pub trait IntoIterator { impl IntoIterator for [T; 1] { type Out = T; - fn into_iter(self) -> Self::Out {} + fn into_iter(self) -> Self::Out { loop {} } } impl<'a, T> IntoIterator for &'a [T] { type Out = &'a T; - fn into_iter(self) -> Self::Out {} + fn into_iter(self) -> Self::Out { loop {} } } "#, ); diff --git a/crates/hir_ty/src/tests/patterns.rs b/crates/hir_ty/src/tests/patterns.rs index 5adbe9c45..47aa30d2e 100644 --- a/crates/hir_ty/src/tests/patterns.rs +++ b/crates/hir_ty/src/tests/patterns.rs @@ -1,6 +1,6 @@ use expect_test::expect; -use super::{check_infer, check_infer_with_mismatches, check_mismatches, check_types}; +use super::{check, check_infer, check_infer_with_mismatches, check_types}; #[test] fn infer_pattern() { @@ -518,7 +518,7 @@ fn infer_generics_in_patterns() { #[test] fn infer_const_pattern() { - check_mismatches( + check( r#" enum Option { None } use Option::None; diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs index 0f418ea49..8c5e8954c 100644 --- a/crates/hir_ty/src/tests/regression.rs +++ b/crates/hir_ty/src/tests/regression.rs @@ -1,6 +1,6 @@ use expect_test::expect; -use super::{check_infer, check_types}; +use super::{check_infer, check_no_mismatches, check_types}; #[test] fn bug_484() { @@ -422,20 +422,20 @@ fn issue_2683_chars_impl() { pub struct Chars<'a> {} impl<'a> Iterator for Chars<'a> { type Item = char; - fn next(&mut self) -> Option {} + fn next(&mut self) -> Option { loop {} } } fn test() { let chars: Chars<'_>; (chars.next(), chars.nth(1)); -} //^ (Option, Option) +} //^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (Option, Option) "#, ); } #[test] fn issue_3642_bad_macro_stackover() { - check_types( + check_no_mismatches( r#" #[macro_export] macro_rules! match_ast { @@ -452,7 +452,6 @@ macro_rules! match_ast { fn main() { let anchor = match_ast! { - //^ () match parent { as => {}, _ => return None @@ -956,7 +955,7 @@ trait IterTrait<'a, T: 'a>: Iterator { fn clone_iter(s: Iter) { s.inner.clone_box(); - //^^^^^^^^^^^^^^^^^^^ () + //^^^^^^^^^^^^^^^^^^^ () } "#, ) diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs index 108ff3179..b4bcc6d95 100644 --- a/crates/hir_ty/src/tests/simple.rs +++ b/crates/hir_ty/src/tests/simple.rs @@ -60,7 +60,7 @@ enum Nat { Succ(Self), Demo(Nat), Zero } fn test() { let foo: Nat = Nat::Zero; if let Nat::Succ(x) = foo { - x + x; } //^ Nat } "#, @@ -138,7 +138,7 @@ enum Option { Some(T), None } fn test() { let foo: Option = None; while let Option::Some(x) = foo { - x + x; } //^ f32 } "#, @@ -1745,7 +1745,7 @@ impl i32 { fn foo(&self) -> Foo { Foo } } fn main() { let x: i32 = i32; x.foo(); - //^ Foo + //^^^^^^^ Foo }"#, ); } @@ -1763,7 +1763,7 @@ fn main() { fn inner() {} let x: i32 = i32; x.foo(); - //^ Foo + //^^^^^^^ Foo }"#, ); } @@ -1781,7 +1781,7 @@ fn foo() -> &'static str { "" } fn main() { foo(); - //^ &str + //^^^^^ &str }"#, ); } @@ -1799,7 +1799,7 @@ fn foo() -> &'static str { "" } fn main() { str::foo(); - //^ u32 + //^^^^^^^^^^ u32 }"#, ); } @@ -1825,9 +1825,9 @@ mod d { fn main() { d::foo(); - //^ u8 + //^^^^^^^^ u8 d::foo{a:0}; - //^ u8 + //^^^^^^^^^^^ foo }"#, ); } @@ -2677,7 +2677,7 @@ fn prelude_2015() { //- /main.rs edition:2015 crate:main deps:core fn f() { Rust; - //^ Rust + //^^^^ Rust } //- /core.rs crate:core diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs index 279a1354a..a0ddad570 100644 --- a/crates/hir_ty/src/tests/traits.rs +++ b/crates/hir_ty/src/tests/traits.rs @@ -1,6 +1,7 @@ +use cov_mark::check; use expect_test::expect; -use super::{check_infer, check_infer_with_mismatches, check_types}; +use super::{check, check_infer, check_infer_with_mismatches, check_types}; #[test] fn infer_await() { @@ -285,7 +286,7 @@ mod ops { #[test] fn infer_from_bound_1() { - check_infer( + check_types( r#" trait Trait {} struct S(T); @@ -293,99 +294,62 @@ impl Trait for S {} fn foo>(t: T) {} fn test() { let s = S(unknown); + // ^^^^^^^ u32 foo(s); }"#, - expect![[r#" - 85..86 't': T - 91..93 '{}': () - 104..143 '{ ...(s); }': () - 114..115 's': S - 118..119 'S': S(u32) -> S - 118..128 'S(unknown)': S - 120..127 'unknown': u32 - 134..137 'foo': fn foo>(S) - 134..140 'foo(s)': () - 138..139 's': S - "#]], ); } #[test] fn infer_from_bound_2() { - check_infer( + check_types( r#" trait Trait {} struct S(T); impl Trait for S {} -fn foo>(t: T) -> U {} +fn foo>(t: T) -> U { loop {} } fn test() { let s = S(unknown); + // ^^^^^^^ u32 let x: u32 = foo(s); }"#, - expect![[r#" - 86..87 't': T - 97..99 '{}': () - 110..162 '{ ...(s); }': () - 120..121 's': S - 124..125 'S': S(u32) -> S - 124..134 'S(unknown)': S - 126..133 'unknown': u32 - 144..145 'x': u32 - 153..156 'foo': fn foo>(S) -> u32 - 153..159 'foo(s)': u32 - 157..158 's': S - "#]], ); } #[test] fn trait_default_method_self_bound_implements_trait() { cov_mark::check!(trait_self_implements_self); - check_infer( + check( r#" trait Trait { fn foo(&self) -> i64; - fn bar(&self) -> { - let x = self.foo(); + fn bar(&self) -> () { + self.foo(); + // ^^^^^^^^^^ type: i64 } }"#, - expect![[r#" - 26..30 'self': &Self - 52..56 'self': &Self - 61..96 '{ ... }': () - 75..76 'x': i64 - 79..83 'self': &Self - 79..89 'self.foo()': i64 - "#]], ); } #[test] fn trait_default_method_self_bound_implements_super_trait() { - check_infer( + check( r#" trait SuperTrait { fn foo(&self) -> i64; } trait Trait: SuperTrait { - fn bar(&self) -> { - let x = self.foo(); + fn bar(&self) -> () { + self.foo(); + // ^^^^^^^^^^ type: i64 } }"#, - expect![[r#" - 31..35 'self': &Self - 85..89 'self': &Self - 94..129 '{ ... }': () - 108..109 'x': i64 - 112..116 'self': &Self - 112..122 'self.foo()': i64 - "#]], ); } #[test] fn infer_project_associated_type() { - check_infer( + check_types( r#" trait Iterable { type Item; @@ -394,89 +358,62 @@ struct S; impl Iterable for S { type Item = u32; } fn test() { let x: ::Item = 1; - let y: ::Item = no_matter; - let z: T::Item = no_matter; - let a: ::Item = no_matter; + // ^ u32 + let y: ::Item = u; + // ^ Iterable::Item + let z: T::Item = u; + // ^ Iterable::Item + let a: ::Item = u; + // ^ Iterable::Item }"#, - expect![[r#" - 108..261 '{ ...ter; }': () - 118..119 'x': u32 - 145..146 '1': u32 - 156..157 'y': Iterable::Item - 183..192 'no_matter': Iterable::Item - 202..203 'z': Iterable::Item - 215..224 'no_matter': Iterable::Item - 234..235 'a': Iterable::Item - 249..258 'no_matter': Iterable::Item - "#]], ); } #[test] fn infer_return_associated_type() { - check_infer( + check_types( r#" trait Iterable { type Item; } struct S; impl Iterable for S { type Item = u32; } -fn foo1(t: T) -> T::Item {} -fn foo2(t: T) -> ::Item {} -fn foo3(t: T) -> ::Item {} +fn foo1(t: T) -> T::Item { loop {} } +fn foo2(t: T) -> ::Item { loop {} } +fn foo3(t: T) -> ::Item { loop {} } fn test() { - let x = foo1(S); - let y = foo2(S); - let z = foo3(S); + foo1(S); + // ^^^^^^^ u32 + foo2(S); + // ^^^^^^^ u32 + foo3(S); + // ^^^^^^^ u32 }"#, - expect![[r#" - 106..107 't': T - 123..125 '{}': () - 147..148 't': T - 178..180 '{}': () - 202..203 't': T - 221..223 '{}': () - 234..300 '{ ...(S); }': () - 244..245 'x': u32 - 248..252 'foo1': fn foo1(S) -> ::Item - 248..255 'foo1(S)': u32 - 253..254 'S': S - 265..266 'y': u32 - 269..273 'foo2': fn foo2(S) -> ::Item - 269..276 'foo2(S)': u32 - 274..275 'S': S - 286..287 'z': u32 - 290..294 'foo3': fn foo3(S) -> ::Item - 290..297 'foo3(S)': u32 - 295..296 'S': S - "#]], ); } #[test] fn infer_associated_type_bound() { - check_infer( + check_types( r#" trait Iterable { type Item; } fn test>() { let y: T::Item = unknown; + // ^^^^^^^ u32 }"#, - expect![[r#" - 67..100 '{ ...own; }': () - 77..78 'y': u32 - 90..97 'unknown': u32 - "#]], ); } #[test] fn infer_const_body() { + // FIXME make check_types work with other bodies check_infer( r#" const A: u32 = 1 + 1; -static B: u64 = { let x = 1; x };"#, +static B: u64 = { let x = 1; x }; +"#, expect![[r#" 15..16 '1': u32 15..20 '1 + 1': u32 @@ -637,12 +574,12 @@ impl core::ops::Deref for Arc { struct S; impl S { - fn foo(&self) -> u128 {} + fn foo(&self) -> u128 { 0 } } fn test(s: Arc) { (*s, s.foo()); -} //^ (S, u128) +} //^^^^^^^^^^^^^ (S, u128) "#, ); } @@ -653,7 +590,7 @@ fn deref_trait_with_inference_var() { r#" //- minicore: deref struct Arc; -fn new_arc() -> Arc {} +fn new_arc() -> Arc { Arc } impl core::ops::Deref for Arc { type Target = T; } @@ -663,8 +600,8 @@ fn foo(a: Arc) {} fn test() { let a = new_arc(); - let b = (*a); - //^ S + let b = *a; + //^^ S foo(a); } "#, @@ -684,7 +621,7 @@ impl core::ops::Deref for S { fn test(s: S) { s.foo(); -} //^ {unknown} +} //^^^^^^^ {unknown} "#, ); } @@ -701,12 +638,12 @@ impl core::ops::Deref for Arc { struct S; impl S { - fn foo(&self) -> u128 {} + fn foo(&self) -> u128 { 0 } } fn test(s: Arc) { (*s, s.foo()); -} //^ (S, u128) +} //^^^^^^^^^^^^^ (S, u128) "#, ); } @@ -720,11 +657,11 @@ struct S; trait Trait {} impl Trait for S {} -fn foo, U>(t: T) -> U {} +fn foo, U>(t: T) -> U { loop {} } fn test(s: S) { - (foo(s)); -} //^ u32 + foo(s); +} //^^^^^^ u32 "#, ); } @@ -741,12 +678,12 @@ impl Trait for S {} struct O; impl O { - fn foo, U>(&self, t: T) -> U {} + fn foo, U>(&self, t: T) -> U { loop {} } } fn test() { O.foo(S); -} //^ isize +} //^^^^^^^^ isize "#, ); } @@ -761,12 +698,12 @@ trait Trait {} impl Trait for S {} impl S { - fn foo(&self) -> U where Self: Trait {} + fn foo(&self) -> U where Self: Trait { loop {} } } fn test() { S.foo(); -} //^ i64 +} //^^^^^^^ i64 "#, ); } @@ -782,12 +719,12 @@ impl Trait<&str> for S {} struct O; impl> O { - fn foo(&self) -> U {} + fn foo(&self) -> U { loop {} } } fn test(o: O) { o.foo(); -} //^ &str +} //^^^^^^^ &str "#, ); } @@ -802,7 +739,7 @@ struct S; impl Clone for S {} impl Trait for T where T: Clone {} fn test(t: T) { t.foo(); } - //^ u128 + //^^^^^^^ u128 "#, ); } @@ -818,7 +755,7 @@ struct S; impl Clone for S {} impl Trait for T where T: Clone {} fn test(t: T) { t.foo(); } - //^ {unknown} + //^^^^^^^ {unknown} "#, ); } @@ -831,7 +768,7 @@ trait Trait { fn foo(self) -> u128; } struct S; impl Trait for S {} fn test(t: T) { t.foo(); } - //^ u128 + //^^^^^^^ u128 "#, ); } @@ -844,7 +781,7 @@ trait Trait { fn foo(self) -> u128; } struct S; impl Trait for S {} fn test(t: T) { t.foo(); } - //^ {unknown} + //^^^^^^^ {unknown} "#, ); } @@ -858,8 +795,8 @@ trait Trait {} impl core::ops::Deref for T where T: Trait { type Target = i128; } -fn test(t: T) { (*t); } - //^ i128 +fn test(t: T) { *t; } + //^^ i128 "#, ); } @@ -1380,12 +1317,12 @@ fn error_bound_chalk() { check_types( r#" trait Trait { - fn foo(&self) -> u32 {} + fn foo(&self) -> u32 { 0 } } fn test(x: (impl Trait + UnknownTrait)) { x.foo(); -} //^ u32 +} //^^^^^^^ u32 "#, ); } @@ -1476,7 +1413,7 @@ trait Clone { fn api_walkthrough() { for node in foo() { node.clone(); - } //^ {unknown} + } //^^^^^^^^^^^^ {unknown} } "#, ); @@ -1513,13 +1450,13 @@ fn where_clause_trait_in_scope_for_method_resolution() { r#" mod foo { trait Trait { - fn foo(&self) -> u32 {} + fn foo(&self) -> u32 { 0 } } } fn test(x: T) { x.foo(); -} //^ u32 +} //^^^^^^^ u32 "#, ); } @@ -1982,7 +1919,7 @@ fn fn_item_fn_trait() { //- minicore: fn struct S; -fn foo() -> S {} +fn foo() -> S { S } fn takes_closure U>(f: F) -> U { f() } @@ -2009,7 +1946,7 @@ trait Trait2 { fn test() where T::Item: Trait2 { let x: T::Item = no_matter; x.foo(); -} //^ u32 +} //^^^^^^^ u32 "#, ); } @@ -2029,7 +1966,7 @@ trait Trait2 { fn test() where T::Item: Trait2, T: Trait, U: Trait<()> { let x: T::Item = no_matter; x.foo(); -} //^ u32 +} //^^^^^^^ u32 "#, ); } @@ -2092,7 +2029,7 @@ impl Trait for S { fn test() { S.f(); -} //^ u32 +} //^^^^^ u32 "#, ); } @@ -2120,7 +2057,7 @@ where fn foo(interner: &I, t: Ty) { fold(interner, t); -} //^ Ty +} //^^^^^^^^^^^^^^^^^ Ty "#, ); } @@ -2139,7 +2076,7 @@ impl Trait for S {} fn test() { S.foo(); -} //^ () +} //^^^^^^^ () "#, ); } @@ -2158,7 +2095,7 @@ impl Trait for S {} fn test() { S.foo(); -} //^ {unknown} +} //^^^^^^^ {unknown} "#, ); } @@ -2176,7 +2113,7 @@ trait Trait2 {} fn test() where T: Trait2 { let x: T::Item = no_matter; -} //^ {unknown} +} //^^^^^^^^^ {unknown} "#, ); } @@ -2193,7 +2130,7 @@ trait Trait { fn test() where T: Trait, U: Trait { let x: T::Item = no_matter; -} //^ {unknown} +} //^^^^^^^^^ {unknown} "#, ); } @@ -2211,7 +2148,7 @@ trait Trait { fn test() where T: Trait { let x: T::Item = no_matter; -} //^ Trait::Item +} //^^^^^^^^^ Trait::Item "#, ); } @@ -2243,7 +2180,7 @@ fn test(t: T) where T: UnificationStoreMut { t.push(x); let y: Key; (x, y); -} //^ (UnificationStoreBase::Key, UnificationStoreBase::Key) +} //^^^^^^ (UnificationStoreBase::Key, UnificationStoreBase::Key) "#, ); } @@ -2268,7 +2205,7 @@ impl Iterator for S { fn test>>() { let x: as Iterator>::Item; x.foo(); -} //^ u32 +} //^^^^^^^ u32 "#, ); } @@ -2470,7 +2407,7 @@ impl Trait for S { fn test() { let y: as Trait>::Item = no_matter; y.foo(); -} //^ u32 +} //^^^^^^^ u32 "#, ); } @@ -2490,7 +2427,7 @@ trait Trait { fn test(x: Box) { x.foo(); -} //^ () +} //^^^^^^^ () "#, ); } @@ -2509,7 +2446,7 @@ impl ToOwned for str { } fn test() { "foo".to_owned(); -} //^ String +} //^^^^^^^^^^^^^^^^ String "#, ); } @@ -2649,7 +2586,7 @@ impl B for T { fn main() { Bar::foo(); -} //^ Foo +} //^^^^^^^^^^ Foo "#, ); } @@ -3002,7 +2939,7 @@ fn test() { S.get(1); //^^^^^^^^ u128 S.get(1.); - //^^^^^^^^ f32 + //^^^^^^^^^ f32 } "#, ); @@ -3477,14 +3414,12 @@ trait Convert { fn new() -> Self; } impl Convert for u32 { - fn new() -> Self { - 0 - } + fn new() -> Self { 0 } } async fn get_accounts() -> Result { let ret = Fooey.collect(); - // ^ u32 + // ^^^^^^^^^^^^^^^ u32 Ok(ret) } "#, @@ -3493,6 +3428,7 @@ async fn get_accounts() -> Result { #[test] fn local_impl_1() { + check!(block_local_impls); check_types( r#" trait Trait { @@ -3502,7 +3438,7 @@ trait Trait { fn test() { struct S; impl Trait for S { - fn foo(&self) { 0 } + fn foo(&self) -> u32 { 0 } } S.foo(); @@ -3514,6 +3450,7 @@ fn test() { #[test] fn local_impl_2() { + check!(block_local_impls); check_types( r#" struct S; @@ -3523,7 +3460,7 @@ fn test() { fn foo(&self) -> T; } impl Trait for S { - fn foo(&self) { 0 } + fn foo(&self) -> u32 { 0 } } S.foo(); @@ -3535,6 +3472,7 @@ fn test() { #[test] fn local_impl_3() { + check!(block_local_impls); check_types( r#" trait Trait { @@ -3547,7 +3485,7 @@ fn test() { struct S2; impl Trait for S2 { - fn foo(&self) { S1 } + fn foo(&self) -> S1 { S1 } } S2.foo(); -- cgit v1.2.3 From d340f28a815ba53a4d35801242eec7fca3718731 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 20 Jun 2021 18:34:43 +0200 Subject: test_utils: Make overlapping annotations possible --- crates/test_utils/src/lib.rs | 50 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs index d55bae62a..d9c22c180 100644 --- a/crates/test_utils/src/lib.rs +++ b/crates/test_utils/src/lib.rs @@ -11,6 +11,7 @@ mod fixture; mod assert_linear; use std::{ + collections::BTreeMap, convert::{TryFrom, TryInto}, env, fs, path::{Path, PathBuf}, @@ -205,14 +206,25 @@ pub fn add_cursor(text: &str, offset: TextSize) -> String { /// /// // ^^^ first line /// // | second line +/// +/// Annotations point to the last line that actually was long enough for the +/// range, not counting annotations themselves. So overlapping annotations are +/// possible: +/// ```no_run +/// // stuff other stuff +/// // ^^ 'st' +/// // ^^^^^ 'stuff' +/// // ^^^^^^^^^^^ 'other stuff' +/// ``` pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> { let mut res = Vec::new(); - let mut prev_line_start: Option = Some(0.into()); + // map from line length to beginning of last line that had that length + let mut line_start_map = BTreeMap::new(); let mut line_start: TextSize = 0.into(); let mut prev_line_annotations: Vec<(TextSize, usize)> = Vec::new(); for line in text.split_inclusive('\n') { let mut this_line_annotations = Vec::new(); - if let Some(idx) = line.find("//") { + let line_length = if let Some(idx) = line.find("//") { let annotation_offset = TextSize::of(&line[..idx + "//".len()]); for annotation in extract_line_annotations(&line[idx + "//".len()..]) { match annotation { @@ -222,7 +234,9 @@ pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> { let range = if file { TextRange::up_to(TextSize::of(text)) } else { - range + prev_line_start.unwrap() + let line_start = line_start_map.range(range.end()..).next().unwrap(); + + range + line_start.1 }; res.push((range, content)) } @@ -238,9 +252,14 @@ pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> { } } } - } + idx.try_into().unwrap() + } else { + TextSize::of(line) + }; + + line_start_map = line_start_map.split_off(&line_length); + line_start_map.insert(line_length, line_start); - prev_line_start = Some(line_start); line_start += TextSize::of(line); prev_line_annotations = this_line_annotations; @@ -296,7 +315,7 @@ fn extract_line_annotations(mut line: &str) -> Vec { } #[test] -fn test_extract_annotations() { +fn test_extract_annotations_1() { let text = stdx::trim_indent( r#" fn main() { @@ -321,6 +340,25 @@ fn main() { assert_eq!(res[3].0.len(), 115); } +#[test] +fn test_extract_annotations_2() { + let text = stdx::trim_indent( + r#" +fn main() { + (x, y); + //^ a + // ^ b + //^^^^^^^^ c +}"#, + ); + let res = extract_annotations(&text) + .into_iter() + .map(|(range, ann)| (&text[range], ann)) + .collect::>(); + + assert_eq!(res, [("x", "a".into()), ("y", "b".into()), ("(x, y)", "c".into())]); +} + /// Returns `false` if slow tests should not run, otherwise returns `true` and /// also creates a file at `./target/.slow_tests_cookie` which serves as a flag /// that slow tests did run. -- cgit v1.2.3 From 0219b145ea255e215693d0fc324aa78311a41236 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 20 Jun 2021 18:36:59 +0200 Subject: Clean up coercion tests --- crates/hir_ty/src/tests/coercion.rs | 669 +++++++----------------------------- 1 file changed, 117 insertions(+), 552 deletions(-) diff --git a/crates/hir_ty/src/tests/coercion.rs b/crates/hir_ty/src/tests/coercion.rs index 24ce5bcca..87089f09d 100644 --- a/crates/hir_ty/src/tests/coercion.rs +++ b/crates/hir_ty/src/tests/coercion.rs @@ -1,27 +1,22 @@ -use expect_test::expect; - -use super::{check_infer, check_infer_with_mismatches, check_no_mismatches, check_types}; +use super::{check, check_no_mismatches, check_types}; #[test] -fn infer_block_expr_type_mismatch() { - check_infer( +fn block_expr_type_mismatch() { + // FIXME fix double type mismatch + check( r" - fn test() { - let a: i32 = { 1i64 }; - } +fn test() { + let a: i32 = { 1i64 }; + // ^^^^^^^^ expected i32, got i64 + // ^^^^ expected i32, got i64 +} ", - expect![[r" - 10..40 '{ ...4 }; }': () - 20..21 'a': i32 - 29..37 '{ 1i64 }': i64 - 31..35 '1i64': i64 - "]], ); } #[test] fn coerce_places() { - check_infer( + check_no_mismatches( r#" //- minicore: coerce_unsized struct S { a: T } @@ -46,81 +41,25 @@ fn test2() { let g: (&[_], &[_]) = (arr, arr); } "#, - expect![[r#" - 30..31 '_': &[T] - 44..55 '{ loop {} }': T - 46..53 'loop {}': ! - 51..53 '{}': () - 64..65 '_': S<&[T]> - 81..92 '{ loop {} }': T - 83..90 'loop {}': ! - 88..90 '{}': () - 121..132 '{ loop {} }': *mut [T; 2] - 123..130 'loop {}': ! - 128..130 '{}': () - 159..172 '{ gen() }': *mut [U] - 165..168 'gen': fn gen() -> *mut [U; 2] - 165..170 'gen()': *mut [U; 2] - 185..419 '{ ...rr); }': () - 195..198 'arr': &[u8; 1] - 211..215 '&[1]': &[u8; 1] - 212..215 '[1]': [u8; 1] - 213..214 '1': u8 - 226..227 'a': &[u8] - 236..239 'arr': &[u8; 1] - 249..250 'b': u8 - 253..254 'f': fn f(&[u8]) -> u8 - 253..259 'f(arr)': u8 - 255..258 'arr': &[u8; 1] - 269..270 'c': &[u8] - 279..286 '{ arr }': &[u8] - 281..284 'arr': &[u8; 1] - 296..297 'd': u8 - 300..301 'g': fn g(S<&[u8]>) -> u8 - 300..315 'g(S { a: arr })': u8 - 302..314 'S { a: arr }': S<&[u8]> - 309..312 'arr': &[u8; 1] - 325..326 'e': [&[u8]; 1] - 340..345 '[arr]': [&[u8]; 1] - 341..344 'arr': &[u8; 1] - 355..356 'f': [&[u8]; 2] - 370..378 '[arr; 2]': [&[u8]; 2] - 371..374 'arr': &[u8; 1] - 376..377 '2': usize - 388..389 'g': (&[u8], &[u8]) - 406..416 '(arr, arr)': (&[u8], &[u8]) - 407..410 'arr': &[u8; 1] - 412..415 'arr': &[u8; 1] - "#]], ); } #[test] -fn infer_let_stmt_coerce() { - check_infer( +fn let_stmt_coerce() { + check_no_mismatches( r" - fn test() { - let x: &[isize] = &[1]; - let x: *const [isize] = &[1]; - } - ", - expect![[r#" - 10..75 '{ ...[1]; }': () - 20..21 'x': &[isize] - 34..38 '&[1]': &[isize; 1] - 35..38 '[1]': [isize; 1] - 36..37 '1': isize - 48..49 'x': *const [isize] - 68..72 '&[1]': &[isize; 1] - 69..72 '[1]': [isize; 1] - 70..71 '1': isize - "#]], +//- minicore: coerce_unsized +fn test() { + let x: &[isize] = &[1]; + let x: *const [isize] = &[1]; +} +", ); } #[test] -fn infer_custom_coerce_unsized() { - check_infer( +fn custom_coerce_unsized() { + check( r#" //- minicore: coerce_unsized use core::{marker::Unsize, ops::CoerceUnsized}; @@ -138,46 +77,22 @@ fn foo3(x: C<[T]>) -> C<[T]> { x } fn test(a: A<[u8; 2]>, b: B<[u8; 2]>, c: C<[u8; 2]>) { let d = foo1(a); + // ^ expected A<[{unknown}]>, got A<[u8; 2]> let e = foo2(b); + // ^ type: B<[u8]> let f = foo3(c); + // ^ type: C<[u8]> } "#, - expect![[r#" - 306..307 'x': A<[T]> - 327..332 '{ x }': A<[T]> - 329..330 'x': A<[T]> - 344..345 'x': B<[T]> - 365..370 '{ x }': B<[T]> - 367..368 'x': B<[T]> - 382..383 'x': C<[T]> - 403..408 '{ x }': C<[T]> - 405..406 'x': C<[T]> - 418..419 'a': A<[u8; 2]> - 433..434 'b': B<[u8; 2]> - 448..449 'c': C<[u8; 2]> - 463..529 '{ ...(c); }': () - 473..474 'd': A<[{unknown}]> - 477..481 'foo1': fn foo1<{unknown}>(A<[{unknown}]>) -> A<[{unknown}]> - 477..484 'foo1(a)': A<[{unknown}]> - 482..483 'a': A<[u8; 2]> - 494..495 'e': B<[u8]> - 498..502 'foo2': fn foo2(B<[u8]>) -> B<[u8]> - 498..505 'foo2(b)': B<[u8]> - 503..504 'b': B<[u8; 2]> - 515..516 'f': C<[u8]> - 519..523 'foo3': fn foo3(C<[u8]>) -> C<[u8]> - 519..526 'foo3(c)': C<[u8]> - 524..525 'c': C<[u8; 2]> - "#]], ); } #[test] -fn infer_if_coerce() { - check_infer( +fn if_coerce() { + check_no_mismatches( r#" -//- minicore: unsize -fn foo(x: &[T]) -> &[T] { loop {} } +//- minicore: coerce_unsized +fn foo(x: &[T]) -> &[T] { x } fn test() { let x = if true { foo(&[1]) @@ -186,35 +101,15 @@ fn test() { }; } "#, - expect![[r#" - 10..11 'x': &[T] - 27..38 '{ loop {} }': &[T] - 29..36 'loop {}': ! - 34..36 '{}': () - 49..125 '{ ... }; }': () - 59..60 'x': &[i32] - 63..122 'if tru... }': &[i32] - 66..70 'true': bool - 71..96 '{ ... }': &[i32] - 81..84 'foo': fn foo(&[i32]) -> &[i32] - 81..90 'foo(&[1])': &[i32] - 85..89 '&[1]': &[i32; 1] - 86..89 '[1]': [i32; 1] - 87..88 '1': i32 - 102..122 '{ ... }': &[i32; 1] - 112..116 '&[1]': &[i32; 1] - 113..116 '[1]': [i32; 1] - 114..115 '1': i32 - "#]], ); } #[test] -fn infer_if_else_coerce() { - check_infer( +fn if_else_coerce() { + check_no_mismatches( r#" //- minicore: coerce_unsized -fn foo(x: &[T]) -> &[T] { loop {} } +fn foo(x: &[T]) -> &[T] { x } fn test() { let x = if true { &[1] @@ -223,35 +118,15 @@ fn test() { }; } "#, - expect![[r#" - 10..11 'x': &[T] - 27..38 '{ loop {} }': &[T] - 29..36 'loop {}': ! - 34..36 '{}': () - 49..125 '{ ... }; }': () - 59..60 'x': &[i32] - 63..122 'if tru... }': &[i32] - 66..70 'true': bool - 71..91 '{ ... }': &[i32; 1] - 81..85 '&[1]': &[i32; 1] - 82..85 '[1]': [i32; 1] - 83..84 '1': i32 - 97..122 '{ ... }': &[i32] - 107..110 'foo': fn foo(&[i32]) -> &[i32] - 107..116 'foo(&[1])': &[i32] - 111..115 '&[1]': &[i32; 1] - 112..115 '[1]': [i32; 1] - 113..114 '1': i32 - "#]], ) } #[test] -fn infer_match_first_coerce() { - check_infer( +fn match_first_coerce() { + check_no_mismatches( r#" -//- minicore: unsize -fn foo(x: &[T]) -> &[T] { loop {} } +//- minicore: coerce_unsized +fn foo(x: &[T]) -> &[T] { x } fn test(i: i32) { let x = match i { 2 => foo(&[2]), @@ -260,39 +135,12 @@ fn test(i: i32) { }; } "#, - expect![[r#" - 10..11 'x': &[T] - 27..38 '{ loop {} }': &[T] - 29..36 'loop {}': ! - 34..36 '{}': () - 47..48 'i': i32 - 55..149 '{ ... }; }': () - 65..66 'x': &[i32] - 69..146 'match ... }': &[i32] - 75..76 'i': i32 - 87..88 '2': i32 - 87..88 '2': i32 - 92..95 'foo': fn foo(&[i32]) -> &[i32] - 92..101 'foo(&[2])': &[i32] - 96..100 '&[2]': &[i32; 1] - 97..100 '[2]': [i32; 1] - 98..99 '2': i32 - 111..112 '1': i32 - 111..112 '1': i32 - 116..120 '&[1]': &[i32; 1] - 117..120 '[1]': [i32; 1] - 118..119 '1': i32 - 130..131 '_': i32 - 135..139 '&[3]': &[i32; 1] - 136..139 '[3]': [i32; 1] - 137..138 '3': i32 - "#]], ); } #[test] -fn infer_match_second_coerce() { - check_infer( +fn match_second_coerce() { + check_no_mismatches( r#" //- minicore: coerce_unsized fn foo(x: &[T]) -> &[T] { loop {} } @@ -304,33 +152,6 @@ fn test(i: i32) { }; } "#, - expect![[r#" - 10..11 'x': &[T] - 27..38 '{ loop {} }': &[T] - 29..36 'loop {}': ! - 34..36 '{}': () - 47..48 'i': i32 - 55..149 '{ ... }; }': () - 65..66 'x': &[i32] - 69..146 'match ... }': &[i32] - 75..76 'i': i32 - 87..88 '1': i32 - 87..88 '1': i32 - 92..96 '&[1]': &[i32; 1] - 93..96 '[1]': [i32; 1] - 94..95 '1': i32 - 106..107 '2': i32 - 106..107 '2': i32 - 111..114 'foo': fn foo(&[i32]) -> &[i32] - 111..120 'foo(&[2])': &[i32] - 115..119 '&[2]': &[i32; 1] - 116..119 '[2]': [i32; 1] - 117..118 '2': i32 - 130..131 '_': i32 - 135..139 '&[3]': &[i32; 1] - 136..139 '[3]': [i32; 1] - 137..138 '3': i32 - "#]], ); } @@ -338,94 +159,52 @@ fn test(i: i32) { fn coerce_merge_one_by_one1() { cov_mark::check!(coerce_merge_fail_fallback); - check_infer( + check( r" - fn test() { - let t = &mut 1; - let x = match 1 { - 1 => t as *mut i32, - 2 => t as &i32, - _ => t as *const i32, - }; - } +fn test() { + let t = &mut 1; + let x = match 1 { + 1 => t as *mut i32, + 2 => t as &i32, + //^^^^^^^^^ expected *mut i32, got &i32 + _ => t as *const i32, + }; + x; + //^ type: *const i32 +} ", - expect![[r" - 10..144 '{ ... }; }': () - 20..21 't': &mut i32 - 24..30 '&mut 1': &mut i32 - 29..30 '1': i32 - 40..41 'x': *const i32 - 44..141 'match ... }': *const i32 - 50..51 '1': i32 - 62..63 '1': i32 - 62..63 '1': i32 - 67..68 't': &mut i32 - 67..80 't as *mut i32': *mut i32 - 90..91 '2': i32 - 90..91 '2': i32 - 95..96 't': &mut i32 - 95..104 't as &i32': &i32 - 114..115 '_': i32 - 119..120 't': &mut i32 - 119..134 't as *const i32': *const i32 - "]], ); } #[test] fn return_coerce_unknown() { - check_infer_with_mismatches( + check_types( r" - fn foo() -> u32 { - return unknown; - } +fn foo() -> u32 { + return unknown; + //^^^^^^^ u32 +} ", - expect![[r" - 16..39 '{ ...own; }': u32 - 22..36 'return unknown': ! - 29..36 'unknown': u32 - "]], ); } #[test] fn coerce_autoderef() { - check_infer_with_mismatches( + check_no_mismatches( r" - struct Foo; - fn takes_ref_foo(x: &Foo) {} - fn test() { - takes_ref_foo(&Foo); - takes_ref_foo(&&Foo); - takes_ref_foo(&&&Foo); - } - ", - expect![[r" - 29..30 'x': &Foo - 38..40 '{}': () - 51..132 '{ ...oo); }': () - 57..70 'takes_ref_foo': fn takes_ref_foo(&Foo) - 57..76 'takes_...(&Foo)': () - 71..75 '&Foo': &Foo - 72..75 'Foo': Foo - 82..95 'takes_ref_foo': fn takes_ref_foo(&Foo) - 82..102 'takes_...&&Foo)': () - 96..101 '&&Foo': &&Foo - 97..101 '&Foo': &Foo - 98..101 'Foo': Foo - 108..121 'takes_ref_foo': fn takes_ref_foo(&Foo) - 108..129 'takes_...&&Foo)': () - 122..128 '&&&Foo': &&&Foo - 123..128 '&&Foo': &&Foo - 124..128 '&Foo': &Foo - 125..128 'Foo': Foo - "]], +struct Foo; +fn takes_ref_foo(x: &Foo) {} +fn test() { + takes_ref_foo(&Foo); + takes_ref_foo(&&Foo); + takes_ref_foo(&&&Foo); +}", ); } #[test] fn coerce_autoderef_generic() { - check_infer_with_mismatches( + check_no_mismatches( r#" struct Foo; fn takes_ref(x: &T) -> T { *x } @@ -435,34 +214,12 @@ fn test() { takes_ref(&&&Foo); } "#, - expect![[r" - 28..29 'x': &T - 40..46 '{ *x }': T - 42..44 '*x': T - 43..44 'x': &T - 57..126 '{ ...oo); }': () - 63..72 'takes_ref': fn takes_ref(&Foo) -> Foo - 63..78 'takes_ref(&Foo)': Foo - 73..77 '&Foo': &Foo - 74..77 'Foo': Foo - 84..93 'takes_ref': fn takes_ref<&Foo>(&&Foo) -> &Foo - 84..100 'takes_...&&Foo)': &Foo - 94..99 '&&Foo': &&Foo - 95..99 '&Foo': &Foo - 96..99 'Foo': Foo - 106..115 'takes_ref': fn takes_ref<&&Foo>(&&&Foo) -> &&Foo - 106..123 'takes_...&&Foo)': &&Foo - 116..122 '&&&Foo': &&&Foo - 117..122 '&&Foo': &&Foo - 118..122 '&Foo': &Foo - 119..122 'Foo': Foo - "]], ); } #[test] fn coerce_autoderef_block() { - check_infer_with_mismatches( + check_no_mismatches( r#" //- minicore: deref struct String {} @@ -473,71 +230,32 @@ fn test() { takes_ref_str(&{ returns_string() }); } "#, - expect![[r#" - 90..91 'x': &str - 99..101 '{}': () - 132..143 '{ loop {} }': String - 134..141 'loop {}': ! - 139..141 '{}': () - 154..199 '{ ... }); }': () - 160..173 'takes_ref_str': fn takes_ref_str(&str) - 160..196 'takes_...g() })': () - 174..195 '&{ ret...ng() }': &String - 175..195 '{ retu...ng() }': String - 177..191 'returns_string': fn returns_string() -> String - 177..193 'return...ring()': String - "#]], ); } #[test] fn closure_return_coerce() { - check_infer_with_mismatches( + check_no_mismatches( r" - fn foo() { - let x = || { - if true { - return &1u32; - } - &&1u32 - }; +fn foo() { + let x = || { + if true { + return &1u32; } - ", - expect![[r" - 9..105 '{ ... }; }': () - 19..20 'x': || -> &u32 - 23..102 '|| { ... }': || -> &u32 - 26..102 '{ ... }': &u32 - 36..81 'if tru... }': () - 39..43 'true': bool - 44..81 '{ ... }': () - 58..70 'return &1u32': ! - 65..70 '&1u32': &u32 - 66..70 '1u32': u32 - 90..96 '&&1u32': &&u32 - 91..96 '&1u32': &u32 - 92..96 '1u32': u32 - "]], + &&1u32 + }; +}", ); } #[test] fn coerce_fn_item_to_fn_ptr() { - check_infer_with_mismatches( + check_no_mismatches( r" - fn foo(x: u32) -> isize { 1 } - fn test() { - let f: fn(u32) -> isize = foo; - } - ", - expect![[r" - 7..8 'x': u32 - 24..29 '{ 1 }': isize - 26..27 '1': isize - 40..78 '{ ...foo; }': () - 50..51 'f': fn(u32) -> isize - 72..75 'foo': fn foo(u32) -> isize - "]], +fn foo(x: u32) -> isize { 1 } +fn test() { + let f: fn(u32) -> isize = foo; +}", ); } @@ -545,110 +263,62 @@ fn coerce_fn_item_to_fn_ptr() { fn coerce_fn_items_in_match_arms() { cov_mark::check!(coerce_fn_reification); - check_infer_with_mismatches( + check_types( r" - fn foo1(x: u32) -> isize { 1 } - fn foo2(x: u32) -> isize { 2 } - fn foo3(x: u32) -> isize { 3 } - fn test() { - let x = match 1 { - 1 => foo1, - 2 => foo2, - _ => foo3, - }; - } - ", - expect![[r" - 8..9 'x': u32 - 25..30 '{ 1 }': isize - 27..28 '1': isize - 39..40 'x': u32 - 56..61 '{ 2 }': isize - 58..59 '2': isize - 70..71 'x': u32 - 87..92 '{ 3 }': isize - 89..90 '3': isize - 103..192 '{ ... }; }': () - 113..114 'x': fn(u32) -> isize - 117..189 'match ... }': fn(u32) -> isize - 123..124 '1': i32 - 135..136 '1': i32 - 135..136 '1': i32 - 140..144 'foo1': fn foo1(u32) -> isize - 154..155 '2': i32 - 154..155 '2': i32 - 159..163 'foo2': fn foo2(u32) -> isize - 173..174 '_': i32 - 178..182 'foo3': fn foo3(u32) -> isize - "]], +fn foo1(x: u32) -> isize { 1 } +fn foo2(x: u32) -> isize { 2 } +fn foo3(x: u32) -> isize { 3 } +fn test() { + let x = match 1 { + 1 => foo1, + 2 => foo2, + _ => foo3, + }; + x; + //^ fn(u32) -> isize +}", ); } #[test] fn coerce_closure_to_fn_ptr() { - check_infer_with_mismatches( + check_no_mismatches( r" - fn test() { - let f: fn(u32) -> isize = |x| { 1 }; - } - ", - expect![[r" - 10..54 '{ ...1 }; }': () - 20..21 'f': fn(u32) -> isize - 42..51 '|x| { 1 }': |u32| -> isize - 43..44 'x': u32 - 46..51 '{ 1 }': isize - 48..49 '1': isize - "]], +fn test() { + let f: fn(u32) -> isize = |x| { 1 }; +}", ); } #[test] fn coerce_placeholder_ref() { // placeholders should unify, even behind references - check_infer_with_mismatches( + check_no_mismatches( r" - struct S { t: T } - impl S { - fn get(&self) -> &TT { - &self.t - } - } - ", - expect![[r" - 50..54 'self': &S - 63..86 '{ ... }': &TT - 73..80 '&self.t': &TT - 74..78 'self': &S - 74..80 'self.t': TT - "]], +struct S { t: T } +impl S { + fn get(&self) -> &TT { + &self.t + } +}", ); } #[test] fn coerce_unsize_array() { - check_infer_with_mismatches( + check_types( r#" //- minicore: coerce_unsized fn test() { let f: &[usize] = &[1, 2, 3]; -} - "#, - expect![[r#" - 10..47 '{ ... 3]; }': () - 20..21 'f': &[usize] - 34..44 '&[1, 2, 3]': &[usize; 3] - 35..44 '[1, 2, 3]': [usize; 3] - 36..37 '1': usize - 39..40 '2': usize - 42..43 '3': usize - "#]], + //^ usize +}"#, ); } #[test] fn coerce_unsize_trait_object_simple() { - check_infer_with_mismatches( + check_types( r#" //- minicore: coerce_unsized trait Foo {} @@ -662,88 +332,18 @@ impl Baz for S {} fn test() { let obj: &dyn Baz = &S; + //^ S let obj: &dyn Bar<_, i8, i16> = &S; + //^ S let obj: &dyn Foo = &S; -} -"#, - expect![[r#" - 236..351 '{ ... &S; }': () - 246..249 'obj': &dyn Baz - 271..273 '&S': &S - 272..273 'S': S - 283..286 'obj': &dyn Bar - 311..313 '&S': &S - 312..313 'S': S - 323..326 'obj': &dyn Foo - 346..348 '&S': &S - 347..348 'S': S - "#]], - ); -} - -#[test] -fn coerce_unsize_trait_object_to_trait_object() { - // FIXME: The rust reference says this should be possible, but rustc doesn't - // implement it. We used to support it, but Chalk doesn't. Here's the - // correct expect: - // - // 424..609 '{ ...bj2; }': () - // 434..437 'obj': &dyn Baz - // 459..461 '&S': &S - // 460..461 'S': S - // 471..474 'obj': &dyn Bar - // 496..499 'obj': &dyn Baz - // 509..512 'obj': &dyn Foo - // 531..534 'obj': &dyn Bar - // 544..548 'obj2': &dyn Baz - // 570..572 '&S': &S - // 571..572 'S': S - // 582..583 '_': &dyn Foo - // 602..606 'obj2': &dyn Baz - check_infer_with_mismatches( - r#" -//- minicore: coerce_unsized -trait Foo {} -trait Bar: Foo {} -trait Baz: Bar {} - -struct S; -impl Foo for S {} -impl Bar for S {} -impl Baz for S {} - -fn test() { - let obj: &dyn Baz = &S; - let obj: &dyn Bar<_, _, _> = obj; - let obj: &dyn Foo<_, _> = obj; - let obj2: &dyn Baz = &S; - let _: &dyn Foo<_, _> = obj2; -} -"#, - expect![[r#" - 236..421 '{ ...bj2; }': () - 246..249 'obj': &dyn Baz - 271..273 '&S': &S - 272..273 'S': S - 283..286 'obj': &dyn Bar<{unknown}, {unknown}, {unknown}> - 308..311 'obj': &dyn Baz - 321..324 'obj': &dyn Foo<{unknown}, {unknown}> - 343..346 'obj': &dyn Bar<{unknown}, {unknown}, {unknown}> - 356..360 'obj2': &dyn Baz - 382..384 '&S': &S - 383..384 'S': S - 394..395 '_': &dyn Foo<{unknown}, {unknown}> - 414..418 'obj2': &dyn Baz - 308..311: expected &dyn Bar<{unknown}, {unknown}, {unknown}>, got &dyn Baz - 343..346: expected &dyn Foo<{unknown}, {unknown}>, got &dyn Bar<{unknown}, {unknown}, {unknown}> - 414..418: expected &dyn Foo<{unknown}, {unknown}>, got &dyn Baz - "#]], + //^ S +}"#, ); } #[test] fn coerce_unsize_super_trait_cycle() { - check_infer_with_mismatches( + check_no_mismatches( r#" //- minicore: coerce_unsized trait A {} @@ -762,22 +362,13 @@ fn test() { let obj: &dyn A = &S; } "#, - expect![[r#" - 140..195 '{ ... &S; }': () - 150..153 'obj': &dyn D - 164..166 '&S': &S - 165..166 'S': S - 176..179 'obj': &dyn A - 190..192 '&S': &S - 191..192 'S': S - "#]], ); } #[test] fn coerce_unsize_generic() { // FIXME: fix the type mismatches here - check_infer_with_mismatches( + check( r#" //- minicore: coerce_unsized struct Foo { t: T }; @@ -785,58 +376,32 @@ struct Bar(Foo); fn test() { let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] }; + //^^^^^^^^^ expected [usize], got [usize; 3] let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] }); + //^^^^^^^^^^^^^^^^^^^^^^^^^^ expected &Bar<[usize]>, got &Bar<[i32; 3]> } "#, - expect![[r#" - 58..166 '{ ... }); }': () - 68..69 '_': &Foo<[usize]> - 87..108 '&Foo {..., 3] }': &Foo<[usize]> - 88..108 'Foo { ..., 3] }': Foo<[usize]> - 97..106 '[1, 2, 3]': [usize; 3] - 98..99 '1': usize - 101..102 '2': usize - 104..105 '3': usize - 118..119 '_': &Bar<[usize]> - 137..163 '&Bar(F... 3] })': &Bar<[i32; 3]> - 138..141 'Bar': Bar<[i32; 3]>(Foo<[i32; 3]>) -> Bar<[i32; 3]> - 138..163 'Bar(Fo... 3] })': Bar<[i32; 3]> - 142..162 'Foo { ..., 3] }': Foo<[i32; 3]> - 151..160 '[1, 2, 3]': [i32; 3] - 152..153 '1': i32 - 155..156 '2': i32 - 158..159 '3': i32 - 97..106: expected [usize], got [usize; 3] - 137..163: expected &Bar<[usize]>, got &Bar<[i32; 3]> - "#]], ); } #[test] fn coerce_unsize_apit() { // FIXME: #8984 - check_infer_with_mismatches( + check( r#" //- minicore: coerce_unsized trait Foo {} fn test(f: impl Foo) { let _: &dyn Foo = &f; + //^^ expected &dyn Foo, got &impl Foo } "#, - expect![[r#" - 22..23 'f': impl Foo - 35..64 '{ ... &f; }': () - 45..46 '_': &dyn Foo - 59..61 '&f': &impl Foo - 60..61 'f': impl Foo - 59..61: expected &dyn Foo, got &impl Foo - "#]], ); } #[test] -fn infer_two_closures_lub() { +fn two_closures_lub() { check_types( r#" fn foo(c: i32) { @@ -851,7 +416,7 @@ fn foo(c: i32) { } #[test] -fn infer_match_diverging_branch_1() { +fn match_diverging_branch_1() { check_types( r#" enum Result { Ok(T), Err } @@ -870,7 +435,7 @@ fn test() -> i32 { } #[test] -fn infer_match_diverging_branch_2() { +fn match_diverging_branch_2() { // same as 1 except for order of branches check_types( r#" -- cgit v1.2.3 From 78419779f1bd5f5f51179af7d2c768c8eeab637e Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 20 Jun 2021 19:10:45 +0200 Subject: More cleanups, use `check` for `display_source_code` tests --- crates/hir_ty/src/tests.rs | 142 +++++++++++-------------- crates/hir_ty/src/tests/display_source_code.rs | 10 +- 2 files changed, 67 insertions(+), 85 deletions(-) diff --git a/crates/hir_ty/src/tests.rs b/crates/hir_ty/src/tests.rs index c4f981b44..0651f34ae 100644 --- a/crates/hir_ty/src/tests.rs +++ b/crates/hir_ty/src/tests.rs @@ -11,23 +11,21 @@ mod incremental; use std::{collections::HashMap, env, sync::Arc}; -use base_db::{fixture::WithFixture, FileRange, SourceDatabase, SourceDatabaseExt}; +use base_db::{fixture::WithFixture, FileRange, SourceDatabaseExt}; use expect_test::Expect; use hir_def::{ body::{Body, BodySourceMap, SyntheticSyntax}, - child_by_source::ChildBySource, db::DefDatabase, + expr::{ExprId, PatId}, item_scope::ItemScope, - keys, nameres::DefMap, src::HasSource, - AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, + AssocItemId, DefWithBodyId, HasModule, LocalModuleId, Lookup, ModuleDefId, }; use hir_expand::{db::AstDatabase, InFile}; use once_cell::race::OnceBool; use stdx::format_to; use syntax::{ - algo, ast::{self, AstNode, NameOwner}, SyntaxNode, }; @@ -59,45 +57,22 @@ fn setup_tracing() -> Option { } fn check_types(ra_fixture: &str) { - check_impl(ra_fixture, false, true) + check_impl(ra_fixture, false, true, false) } fn check_types_source_code(ra_fixture: &str) { - // TODO - check_types_impl(ra_fixture, true) -} - -fn check_types_impl(ra_fixture: &str, display_source: bool) { - // TODO - let _tracing = setup_tracing(); - let db = TestDB::with_files(ra_fixture); - let mut checked_one = false; - for (file_id, annotations) in db.extract_annotations() { - for (range, expected) in annotations { - let ty = type_at_range(&db, FileRange { file_id, range }); - let actual = if display_source { - let module = db.module_for_file(file_id); - ty.display_source_code(&db, module).unwrap() - } else { - ty.display_test(&db).to_string() - }; - assert_eq!(expected, actual); - checked_one = true; - } - } - - assert!(checked_one, "no `//^` annotations found"); + check_impl(ra_fixture, false, true, true) } fn check_no_mismatches(ra_fixture: &str) { - check_impl(ra_fixture, true, false) + check_impl(ra_fixture, true, false, false) } fn check(ra_fixture: &str) { - check_impl(ra_fixture, false, false) + check_impl(ra_fixture, false, false, false) } -fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool) { +fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_source: bool) { let _tracing = setup_tracing(); let (db, files) = TestDB::with_many_files(ra_fixture); @@ -151,50 +126,41 @@ fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool) { let inference_result = db.infer(def); for (pat, ty) in inference_result.type_of_pat.iter() { - let node = match body_source_map.pat_syntax(pat) { - Ok(sp) => { - let root = db.parse_or_expand(sp.file_id).unwrap(); - sp.map(|ptr| { - ptr.either( - |it| it.to_node(&root).syntax().clone(), - |it| it.to_node(&root).syntax().clone(), - ) - }) - } - Err(SyntheticSyntax) => continue, + let node = match pat_node(&body_source_map, pat, &db) { + Some(value) => value, + None => continue, }; let range = node.as_ref().original_file_range(&db); - if let Some(annotation) = types.remove(&range) { - assert_eq!(ty.display_test(&db).to_string(), annotation); + if let Some(expected) = types.remove(&range) { + let actual = if display_source { + ty.display_source_code(&db, def.module(&db)).unwrap() + } else { + ty.display_test(&db).to_string() + }; + assert_eq!(actual, expected); } } for (expr, ty) in inference_result.type_of_expr.iter() { - let node = match body_source_map.expr_syntax(expr) { - Ok(sp) => { - let root = db.parse_or_expand(sp.file_id).unwrap(); - sp.map(|ptr| ptr.to_node(&root).syntax().clone()) - } - Err(SyntheticSyntax) => continue, + let node = match expr_node(&body_source_map, expr, &db) { + Some(value) => value, + None => continue, }; let range = node.as_ref().original_file_range(&db); - if let Some(annotation) = types.remove(&range) { - assert_eq!(ty.display_test(&db).to_string(), annotation); + if let Some(expected) = types.remove(&range) { + let actual = if display_source { + ty.display_source_code(&db, def.module(&db)).unwrap() + } else { + ty.display_test(&db).to_string() + }; + assert_eq!(actual, expected); } } for (pat, mismatch) in inference_result.pat_type_mismatches() { - let node = match body_source_map.pat_syntax(pat) { - Ok(sp) => { - let root = db.parse_or_expand(sp.file_id).unwrap(); - sp.map(|ptr| { - ptr.either( - |it| it.to_node(&root).syntax().clone(), - |it| it.to_node(&root).syntax().clone(), - ) - }) - } - Err(SyntheticSyntax) => continue, + let node = match pat_node(&body_source_map, pat, &db) { + Some(value) => value, + None => continue, }; let range = node.as_ref().original_file_range(&db); let actual = format!( @@ -249,21 +215,37 @@ fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool) { assert!(buf.is_empty(), "{}", buf); } -fn type_at_range(db: &TestDB, pos: FileRange) -> Ty { - let file = db.parse(pos.file_id).ok().unwrap(); - let expr = algo::find_node_at_range::(file.syntax(), pos.range).unwrap(); - let fn_def = expr.syntax().ancestors().find_map(ast::Fn::cast).unwrap(); - let module = db.module_for_file(pos.file_id); - let func = *module.child_by_source(db)[keys::FUNCTION] - .get(&InFile::new(pos.file_id.into(), fn_def)) - .unwrap(); - - let (_body, source_map) = db.body_with_source_map(func.into()); - if let Some(expr_id) = source_map.node_expr(InFile::new(pos.file_id.into(), &expr)) { - let infer = db.infer(func.into()); - return infer[expr_id].clone(); - } - panic!("Can't find expression") +fn expr_node( + body_source_map: &BodySourceMap, + expr: ExprId, + db: &TestDB, +) -> Option> { + Some(match body_source_map.expr_syntax(expr) { + Ok(sp) => { + let root = db.parse_or_expand(sp.file_id).unwrap(); + sp.map(|ptr| ptr.to_node(&root).syntax().clone()) + } + Err(SyntheticSyntax) => return None, + }) +} + +fn pat_node( + body_source_map: &BodySourceMap, + pat: PatId, + db: &TestDB, +) -> Option> { + Some(match body_source_map.pat_syntax(pat) { + Ok(sp) => { + let root = db.parse_or_expand(sp.file_id).unwrap(); + sp.map(|ptr| { + ptr.either( + |it| it.to_node(&root).syntax().clone(), + |it| it.to_node(&root).syntax().clone(), + ) + }) + } + Err(SyntheticSyntax) => return None, + }) } fn infer(ra_fixture: &str) -> String { diff --git a/crates/hir_ty/src/tests/display_source_code.rs b/crates/hir_ty/src/tests/display_source_code.rs index 3d29021aa..058cd02d7 100644 --- a/crates/hir_ty/src/tests/display_source_code.rs +++ b/crates/hir_ty/src/tests/display_source_code.rs @@ -10,8 +10,8 @@ mod foo { fn bar() { let foo: foo::Foo = foo::Foo; - foo -} //^ foo::Foo + foo; +} //^^^ foo::Foo "#, ); @@ -25,7 +25,7 @@ struct Foo { t: T } fn main() { let foo = Foo { t: 5u8 }; foo; -} //^ Foo +} //^^^ Foo "#, ); @@ -35,7 +35,7 @@ struct Foo { k: K, t: T } fn main() { let foo = Foo { k: 400, t: 5u8 }; foo; -} //^ Foo +} //^^^ Foo "#, ); } @@ -50,7 +50,7 @@ fn foo() -> *const (impl Unpin + Sized) { loop {} } fn main() { let foo = foo(); foo; -} //^ *const (impl Unpin + Sized) +} //^^^ *const (impl Unpin + Sized) "#, ); } -- cgit v1.2.3 From a1120b6879afe39f69a04eb0f6ee84d4cb4e03f6 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 20 Jun 2021 19:37:45 +0200 Subject: Fix `benchmark_include_macro` --- crates/hir_ty/src/tests/macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs index 6c3d46caf..2cf41e49e 100644 --- a/crates/hir_ty/src/tests/macros.rs +++ b/crates/hir_ty/src/tests/macros.rs @@ -853,7 +853,7 @@ include!("foo.rs"); fn main() { RegisterBlock { }; - //^ RegisterBlock + //^^^^^^^^^^^^^^^^^ RegisterBlock } "#; let fixture = format!("{}\n//- /foo.rs\n{}", fixture, data); -- cgit v1.2.3