Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/tests.rs')
-rw-r--r--crates/hir-ty/src/tests.rs556
1 files changed, 281 insertions, 275 deletions
diff --git a/crates/hir-ty/src/tests.rs b/crates/hir-ty/src/tests.rs
index 1c3da438cb..95a02d534b 100644
--- a/crates/hir-ty/src/tests.rs
+++ b/crates/hir-ty/src/tests.rs
@@ -36,10 +36,11 @@ use test_fixture::WithFixture;
use triomphe::Arc;
use crate::{
- InferenceResult, Ty,
+ InferenceResult,
db::HirDatabase,
display::{DisplayTarget, HirDisplay},
infer::{Adjustment, TypeMismatch},
+ next_solver::Ty,
setup_tracing,
test_db::TestDB,
};
@@ -78,172 +79,172 @@ fn check_impl(
let _tracing = setup_tracing();
let (db, files) = TestDB::with_many_files(ra_fixture);
- let mut had_annotations = false;
- let mut mismatches = FxHashMap::default();
- let mut types = FxHashMap::default();
- let mut adjustments = FxHashMap::default();
- 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_owned());
- } else if expected.starts_with("expected") {
- mismatches.insert(file_range, expected);
- } else if expected.starts_with("adjustments:") {
- adjustments.insert(
- file_range,
- expected.trim_start_matches("adjustments:").trim().to_owned(),
- );
- } else {
- panic!("unexpected annotation: {expected} @ {range:?}");
+ crate::attach_db(&db, || {
+ let mut had_annotations = false;
+ let mut mismatches = FxHashMap::default();
+ let mut types = FxHashMap::default();
+ let mut adjustments = FxHashMap::default();
+ 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_owned());
+ } else if expected.starts_with("expected") {
+ mismatches.insert(file_range, expected);
+ } else if expected.starts_with("adjustments:") {
+ adjustments.insert(
+ file_range,
+ expected.trim_start_matches("adjustments:").trim().to_owned(),
+ );
+ } else {
+ panic!("unexpected annotation: {expected} @ {range:?}");
+ }
+ had_annotations = true;
}
- had_annotations = true;
}
- }
- assert!(had_annotations || allow_none, "no `//^` annotations found");
-
- let mut defs: Vec<(DefWithBodyId, Crate)> = Vec::new();
- for file_id in files {
- let module = db.module_for_file_opt(file_id.file_id(&db));
- 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| {
- let def = match it {
- ModuleDefId::FunctionId(it) => it.into(),
- ModuleDefId::EnumVariantId(it) => it.into(),
- ModuleDefId::ConstId(it) => it.into(),
- ModuleDefId::StaticId(it) => it.into(),
- _ => return,
+ assert!(had_annotations || allow_none, "no `//^` annotations found");
+
+ let mut defs: Vec<(DefWithBodyId, Crate)> = Vec::new();
+ for file_id in files {
+ let module = db.module_for_file_opt(file_id.file_id(&db));
+ let module = match module {
+ Some(m) => m,
+ None => continue,
};
- defs.push((def, module.krate()))
- });
- }
- defs.sort_by_key(|(def, _)| match def {
- DefWithBodyId::FunctionId(it) => {
- let loc = it.lookup(&db);
- loc.source(&db).value.syntax().text_range().start()
- }
- DefWithBodyId::ConstId(it) => {
- let loc = it.lookup(&db);
- loc.source(&db).value.syntax().text_range().start()
- }
- DefWithBodyId::StaticId(it) => {
- let loc = it.lookup(&db);
- loc.source(&db).value.syntax().text_range().start()
- }
- DefWithBodyId::VariantId(it) => {
- let loc = it.lookup(&db);
- loc.source(&db).value.syntax().text_range().start()
+ let def_map = module.def_map(&db);
+ visit_module(&db, def_map, module.local_id, &mut |it| {
+ let def = match it {
+ ModuleDefId::FunctionId(it) => it.into(),
+ ModuleDefId::EnumVariantId(it) => it.into(),
+ ModuleDefId::ConstId(it) => it.into(),
+ ModuleDefId::StaticId(it) => it.into(),
+ _ => return,
+ };
+ defs.push((def, module.krate()))
+ });
}
- });
- let mut unexpected_type_mismatches = String::new();
- for (def, krate) in defs {
- let display_target = DisplayTarget::from_crate(&db, krate);
- let (body, body_source_map) = db.body_with_source_map(def);
- let inference_result = db.infer(def);
-
- for (pat, mut ty) in inference_result.type_of_pat.iter() {
- if let Pat::Bind { id, .. } = body[pat] {
- ty = &inference_result.type_of_binding[id];
+ defs.sort_by_key(|(def, _)| match def {
+ DefWithBodyId::FunctionId(it) => {
+ let loc = it.lookup(&db);
+ loc.source(&db).value.syntax().text_range().start()
}
- let node = match pat_node(&body_source_map, pat, &db) {
- Some(value) => value,
- None => continue,
- };
- let range = node.as_ref().original_file_range_rooted(&db);
- if let Some(expected) = types.remove(&range) {
- let actual = salsa::attach(&db, || {
- if display_source {
+ DefWithBodyId::ConstId(it) => {
+ let loc = it.lookup(&db);
+ loc.source(&db).value.syntax().text_range().start()
+ }
+ DefWithBodyId::StaticId(it) => {
+ let loc = it.lookup(&db);
+ loc.source(&db).value.syntax().text_range().start()
+ }
+ DefWithBodyId::VariantId(it) => {
+ let loc = it.lookup(&db);
+ loc.source(&db).value.syntax().text_range().start()
+ }
+ });
+ let mut unexpected_type_mismatches = String::new();
+ for (def, krate) in defs {
+ let display_target = DisplayTarget::from_crate(&db, krate);
+ let (body, body_source_map) = db.body_with_source_map(def);
+ let inference_result = db.infer(def);
+
+ for (pat, mut ty) in inference_result.type_of_pat.iter() {
+ if let Pat::Bind { id, .. } = body[pat] {
+ ty = &inference_result.type_of_binding[id];
+ }
+ let node = match pat_node(&body_source_map, pat, &db) {
+ Some(value) => value,
+ None => continue,
+ };
+ let range = node.as_ref().original_file_range_rooted(&db);
+ if let Some(expected) = types.remove(&range) {
+ let actual = if display_source {
ty.display_source_code(&db, def.module(&db), true).unwrap()
} else {
ty.display_test(&db, display_target).to_string()
- }
- });
- assert_eq!(actual, expected, "type annotation differs at {:#?}", range.range);
+ };
+ assert_eq!(actual, expected, "type annotation differs at {:#?}", range.range);
+ }
}
- }
- for (expr, ty) in inference_result.type_of_expr.iter() {
- let node = match expr_node(&body_source_map, expr, &db) {
- Some(value) => value,
- None => continue,
- };
- let range = node.as_ref().original_file_range_rooted(&db);
- if let Some(expected) = types.remove(&range) {
- let actual = salsa::attach(&db, || {
- if display_source {
+ for (expr, ty) in inference_result.type_of_expr.iter() {
+ let node = match expr_node(&body_source_map, expr, &db) {
+ Some(value) => value,
+ None => continue,
+ };
+ let range = node.as_ref().original_file_range_rooted(&db);
+ if let Some(expected) = types.remove(&range) {
+ let actual = if display_source {
ty.display_source_code(&db, def.module(&db), true).unwrap()
} else {
ty.display_test(&db, display_target).to_string()
- }
- });
- assert_eq!(actual, expected, "type annotation differs at {:#?}", range.range);
- }
- if let Some(expected) = adjustments.remove(&range) {
- let adjustments = inference_result
- .expr_adjustments
- .get(&expr)
- .map_or_else(Default::default, |it| &**it);
- assert_eq!(
- expected,
- adjustments
- .iter()
- .map(|Adjustment { kind, .. }| format!("{kind:?}"))
- .join(", ")
- );
+ };
+ assert_eq!(actual, expected, "type annotation differs at {:#?}", range.range);
+ }
+ if let Some(expected) = adjustments.remove(&range) {
+ let adjustments = inference_result
+ .expr_adjustments
+ .get(&expr)
+ .map_or_else(Default::default, |it| &**it);
+ assert_eq!(
+ expected,
+ adjustments
+ .iter()
+ .map(|Adjustment { kind, .. }| format!("{kind:?}"))
+ .join(", ")
+ );
+ }
}
- }
- for (expr_or_pat, mismatch) in inference_result.type_mismatches() {
- let Some(node) = (match expr_or_pat {
- hir_def::hir::ExprOrPatId::ExprId(expr) => expr_node(&body_source_map, expr, &db),
- hir_def::hir::ExprOrPatId::PatId(pat) => pat_node(&body_source_map, pat, &db),
- }) else {
- continue;
- };
- let range = node.as_ref().original_file_range_rooted(&db);
- let actual = salsa::attach(&db, || {
- format!(
+ for (expr_or_pat, mismatch) in inference_result.type_mismatches() {
+ let Some(node) = (match expr_or_pat {
+ hir_def::hir::ExprOrPatId::ExprId(expr) => {
+ expr_node(&body_source_map, expr, &db)
+ }
+ hir_def::hir::ExprOrPatId::PatId(pat) => pat_node(&body_source_map, pat, &db),
+ }) else {
+ continue;
+ };
+ let range = node.as_ref().original_file_range_rooted(&db);
+ let actual = format!(
"expected {}, got {}",
mismatch.expected.display_test(&db, display_target),
mismatch.actual.display_test(&db, display_target)
- )
- });
- match mismatches.remove(&range) {
- Some(annotation) => assert_eq!(actual, annotation),
- None => format_to!(unexpected_type_mismatches, "{:?}: {}\n", range.range, actual),
+ );
+ match mismatches.remove(&range) {
+ Some(annotation) => assert_eq!(actual, annotation),
+ None => {
+ format_to!(unexpected_type_mismatches, "{:?}: {}\n", range.range, actual)
+ }
+ }
}
}
- }
- let mut buf = String::new();
- if !unexpected_type_mismatches.is_empty() {
- format_to!(buf, "Unexpected type mismatches:\n{}", unexpected_type_mismatches);
- }
- if !mismatches.is_empty() {
- format_to!(buf, "Unchecked mismatch annotations:\n");
- for m in mismatches {
- format_to!(buf, "{:?}: {}\n", m.0.range, m.1);
+ let mut buf = String::new();
+ if !unexpected_type_mismatches.is_empty() {
+ format_to!(buf, "Unexpected type mismatches:\n{}", unexpected_type_mismatches);
}
- }
- 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);
+ 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 !adjustments.is_empty() {
- format_to!(buf, "Unchecked adjustments annotations:\n");
- for t in adjustments {
- format_to!(buf, "{:?}: type {:?}\n", t.0.range, t.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);
+ if !adjustments.is_empty() {
+ format_to!(buf, "Unchecked adjustments annotations:\n");
+ for t in adjustments {
+ format_to!(buf, "{:?}: type {:?}\n", t.0.range, t.1);
+ }
+ }
+ assert!(buf.is_empty(), "{}", buf);
+ });
}
fn expr_node(
@@ -282,139 +283,140 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
let _tracing = setup_tracing();
let (db, file_id) = TestDB::with_single_file(content);
- let mut buf = String::new();
-
- let mut infer_def = |inference_result: Arc<InferenceResult>,
- body: Arc<Body>,
- body_source_map: Arc<BodySourceMap>,
- krate: Crate| {
- let display_target = DisplayTarget::from_crate(&db, krate);
- let mut types: Vec<(InFile<SyntaxNode>, &Ty)> = Vec::new();
- let mut mismatches: Vec<(InFile<SyntaxNode>, &TypeMismatch)> = Vec::new();
-
- if let Some(self_param) = body.self_param {
- let ty = &inference_result.type_of_binding[self_param];
- if let Some(syntax_ptr) = body_source_map.self_param_syntax() {
- let root = db.parse_or_expand(syntax_ptr.file_id);
- let node = syntax_ptr.map(|ptr| ptr.to_node(&root).syntax().clone());
- types.push((node, ty));
+ crate::attach_db(&db, || {
+ let mut buf = String::new();
+
+ let mut infer_def = |inference_result: Arc<InferenceResult<'_>>,
+ body: Arc<Body>,
+ body_source_map: Arc<BodySourceMap>,
+ krate: Crate| {
+ let display_target = DisplayTarget::from_crate(&db, krate);
+ let mut types: Vec<(InFile<SyntaxNode>, &Ty<'_>)> = Vec::new();
+ let mut mismatches: Vec<(InFile<SyntaxNode>, &TypeMismatch<'_>)> = Vec::new();
+
+ if let Some(self_param) = body.self_param {
+ let ty = &inference_result.type_of_binding[self_param];
+ if let Some(syntax_ptr) = body_source_map.self_param_syntax() {
+ let root = db.parse_or_expand(syntax_ptr.file_id);
+ let node = syntax_ptr.map(|ptr| ptr.to_node(&root).syntax().clone());
+ types.push((node, ty));
+ }
}
- }
- for (pat, mut ty) in inference_result.type_of_pat.iter() {
- if let Pat::Bind { id, .. } = body[pat] {
- ty = &inference_result.type_of_binding[id];
- }
- let node = match body_source_map.pat_syntax(pat) {
- Ok(sp) => {
- let root = db.parse_or_expand(sp.file_id);
- sp.map(|ptr| ptr.to_node(&root).syntax().clone())
+ for (pat, mut ty) in inference_result.type_of_pat.iter() {
+ if let Pat::Bind { id, .. } = body[pat] {
+ ty = &inference_result.type_of_binding[id];
+ }
+ let node = match body_source_map.pat_syntax(pat) {
+ Ok(sp) => {
+ let root = db.parse_or_expand(sp.file_id);
+ sp.map(|ptr| ptr.to_node(&root).syntax().clone())
+ }
+ Err(SyntheticSyntax) => continue,
+ };
+ types.push((node.clone(), ty));
+ if let Some(mismatch) = inference_result.type_mismatch_for_pat(pat) {
+ mismatches.push((node, mismatch));
}
- Err(SyntheticSyntax) => continue,
- };
- types.push((node.clone(), ty));
- if let Some(mismatch) = inference_result.type_mismatch_for_pat(pat) {
- mismatches.push((node, mismatch));
}
- }
- 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);
- sp.map(|ptr| ptr.to_node(&root).syntax().clone())
+ 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);
+ sp.map(|ptr| ptr.to_node(&root).syntax().clone())
+ }
+ Err(SyntheticSyntax) => continue,
+ };
+ types.push((node.clone(), ty));
+ if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr) {
+ mismatches.push((node, mismatch));
}
- Err(SyntheticSyntax) => continue,
- };
- types.push((node.clone(), ty));
- if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr) {
- mismatches.push((node, mismatch));
}
- }
- // sort ranges for consistency
- types.sort_by_key(|(node, _)| {
- let range = node.value.text_range();
- (range.start(), range.end())
- });
- for (node, ty) in &types {
- let (range, text) = if let Some(self_param) = ast::SelfParam::cast(node.value.clone()) {
- (self_param.name().unwrap().syntax().text_range(), "self".to_owned())
- } else {
- (node.value.text_range(), node.value.text().to_string().replace('\n', " "))
- };
- let macro_prefix = if node.file_id != file_id { "!" } else { "" };
- format_to!(
- buf,
- "{}{:?} '{}': {}\n",
- macro_prefix,
- range,
- ellipsize(text, 15),
- ty.display_test(&db, display_target)
- );
- }
- if include_mismatches {
- mismatches.sort_by_key(|(node, _)| {
+ // sort ranges for consistency
+ types.sort_by_key(|(node, _)| {
let range = node.value.text_range();
(range.start(), range.end())
});
- for (src_ptr, mismatch) in &mismatches {
- let range = src_ptr.value.text_range();
- let macro_prefix = if src_ptr.file_id != file_id { "!" } else { "" };
+ for (node, ty) in &types {
+ let (range, text) =
+ if let Some(self_param) = ast::SelfParam::cast(node.value.clone()) {
+ (self_param.name().unwrap().syntax().text_range(), "self".to_owned())
+ } else {
+ (node.value.text_range(), node.value.text().to_string().replace('\n', " "))
+ };
+ let macro_prefix = if node.file_id != file_id { "!" } else { "" };
format_to!(
buf,
- "{}{:?}: expected {}, got {}\n",
+ "{}{:?} '{}': {}\n",
macro_prefix,
range,
- mismatch.expected.display_test(&db, display_target),
- mismatch.actual.display_test(&db, display_target),
+ ellipsize(text, 15),
+ ty.display_test(&db, display_target)
);
}
- }
- };
-
- let module = db.module_for_file(file_id.file_id(&db));
- let def_map = module.def_map(&db);
-
- let mut defs: Vec<(DefWithBodyId, Crate)> = Vec::new();
- visit_module(&db, def_map, module.local_id, &mut |it| {
- let def = match it {
- ModuleDefId::FunctionId(it) => it.into(),
- ModuleDefId::EnumVariantId(it) => it.into(),
- ModuleDefId::ConstId(it) => it.into(),
- ModuleDefId::StaticId(it) => it.into(),
- _ => return,
+ if include_mismatches {
+ mismatches.sort_by_key(|(node, _)| {
+ let range = node.value.text_range();
+ (range.start(), range.end())
+ });
+ for (src_ptr, mismatch) in &mismatches {
+ let range = src_ptr.value.text_range();
+ let macro_prefix = if src_ptr.file_id != file_id { "!" } else { "" };
+ format_to!(
+ buf,
+ "{}{:?}: expected {}, got {}\n",
+ macro_prefix,
+ range,
+ mismatch.expected.display_test(&db, display_target),
+ mismatch.actual.display_test(&db, display_target),
+ );
+ }
+ }
};
- defs.push((def, module.krate()))
- });
- defs.sort_by_key(|(def, _)| match def {
- DefWithBodyId::FunctionId(it) => {
- let loc = it.lookup(&db);
- loc.source(&db).value.syntax().text_range().start()
- }
- DefWithBodyId::ConstId(it) => {
- let loc = it.lookup(&db);
- loc.source(&db).value.syntax().text_range().start()
- }
- DefWithBodyId::StaticId(it) => {
- let loc = it.lookup(&db);
- loc.source(&db).value.syntax().text_range().start()
- }
- DefWithBodyId::VariantId(it) => {
- let loc = it.lookup(&db);
- loc.source(&db).value.syntax().text_range().start()
- }
- });
- for (def, krate) in defs {
- let (body, source_map) = db.body_with_source_map(def);
- let infer = db.infer(def);
- salsa::attach(&db, || {
+
+ let module = db.module_for_file(file_id.file_id(&db));
+ let def_map = module.def_map(&db);
+
+ let mut defs: Vec<(DefWithBodyId, Crate)> = Vec::new();
+ visit_module(&db, def_map, module.local_id, &mut |it| {
+ let def = match it {
+ ModuleDefId::FunctionId(it) => it.into(),
+ ModuleDefId::EnumVariantId(it) => it.into(),
+ ModuleDefId::ConstId(it) => it.into(),
+ ModuleDefId::StaticId(it) => it.into(),
+ _ => return,
+ };
+ defs.push((def, module.krate()))
+ });
+ defs.sort_by_key(|(def, _)| match def {
+ DefWithBodyId::FunctionId(it) => {
+ let loc = it.lookup(&db);
+ loc.source(&db).value.syntax().text_range().start()
+ }
+ DefWithBodyId::ConstId(it) => {
+ let loc = it.lookup(&db);
+ loc.source(&db).value.syntax().text_range().start()
+ }
+ DefWithBodyId::StaticId(it) => {
+ let loc = it.lookup(&db);
+ loc.source(&db).value.syntax().text_range().start()
+ }
+ DefWithBodyId::VariantId(it) => {
+ let loc = it.lookup(&db);
+ loc.source(&db).value.syntax().text_range().start()
+ }
+ });
+ for (def, krate) in defs {
+ let (body, source_map) = db.body_with_source_map(def);
+ let infer = db.infer(def);
infer_def(infer, body, source_map, krate);
- })
- }
+ }
- buf.truncate(buf.trim_end().len());
- buf
+ buf.truncate(buf.trim_end().len());
+ buf
+ })
}
pub(crate) fn visit_module(
@@ -556,15 +558,17 @@ fn salsa_bug() {
",
);
- let module = db.module_for_file(pos.file_id.file_id(&db));
- let crate_def_map = module.def_map(&db);
- visit_module(&db, crate_def_map, module.local_id, &mut |def| {
- db.infer(match def {
- ModuleDefId::FunctionId(it) => it.into(),
- ModuleDefId::EnumVariantId(it) => it.into(),
- ModuleDefId::ConstId(it) => it.into(),
- ModuleDefId::StaticId(it) => it.into(),
- _ => return,
+ crate::attach_db(&db, || {
+ let module = db.module_for_file(pos.file_id.file_id(&db));
+ let crate_def_map = module.def_map(&db);
+ visit_module(&db, crate_def_map, module.local_id, &mut |def| {
+ db.infer(match def {
+ ModuleDefId::FunctionId(it) => it.into(),
+ ModuleDefId::EnumVariantId(it) => it.into(),
+ ModuleDefId::ConstId(it) => it.into(),
+ ModuleDefId::StaticId(it) => it.into(),
+ _ => return,
+ });
});
});
@@ -595,15 +599,17 @@ fn salsa_bug() {
db.set_file_text(pos.file_id.file_id(&db), new_text);
- let module = db.module_for_file(pos.file_id.file_id(&db));
- let crate_def_map = module.def_map(&db);
- visit_module(&db, crate_def_map, module.local_id, &mut |def| {
- db.infer(match def {
- ModuleDefId::FunctionId(it) => it.into(),
- ModuleDefId::EnumVariantId(it) => it.into(),
- ModuleDefId::ConstId(it) => it.into(),
- ModuleDefId::StaticId(it) => it.into(),
- _ => return,
+ crate::attach_db(&db, || {
+ let module = db.module_for_file(pos.file_id.file_id(&db));
+ let crate_def_map = module.def_map(&db);
+ visit_module(&db, crate_def_map, module.local_id, &mut |def| {
+ db.infer(match def {
+ ModuleDefId::FunctionId(it) => it.into(),
+ ModuleDefId::EnumVariantId(it) => it.into(),
+ ModuleDefId::ConstId(it) => it.into(),
+ ModuleDefId::StaticId(it) => it.into(),
+ _ => return,
+ });
});
- });
+ })
}