mod macros;
mod display_source_code;
mod incremental;
+mod diagnostics;
use std::{collections::HashMap, env, sync::Arc};
use once_cell::race::OnceBool;
use stdx::format_to;
use syntax::{
- ast::{self, AstNode, NameOwner},
+ ast::{self, AstNode, HasName},
SyntaxNode,
};
use tracing_subscriber::{layer::SubscriberExt, EnvFilter, Registry};
use tracing_tree::HierarchicalLayer;
use crate::{
- db::HirDatabase, display::HirDisplay, infer::TypeMismatch, test_db::TestDB, InferenceResult, Ty,
+ db::HirDatabase,
+ display::HirDisplay,
+ infer::{Adjustment, TypeMismatch},
+ test_db::TestDB,
+ InferenceResult, Ty,
};
// These tests compare the inference results for all expressions in a file
let mut had_annotations = false;
let mut mismatches = HashMap::new();
let mut types = HashMap::new();
+ let mut adjustments = HashMap::<_, Vec<_>>::new();
for (file_id, annotations) in db.extract_annotations() {
for (range, expected) in annotations {
let file_range = FileRange { file_id, range };
types.insert(file_range, expected.trim_start_matches("type: ").to_string());
} 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: ")
+ .split(',')
+ .map(|it| it.trim().to_string())
+ .filter(|it| !it.is_empty())
+ .collect(),
+ );
} else {
panic!("unexpected annotation: {}", expected);
}
};
assert_eq!(actual, expected);
}
+ if let Some(expected) = adjustments.remove(&range) {
+ if let Some(adjustments) = inference_result.expr_adjustments.get(&expr) {
+ assert_eq!(
+ expected,
+ adjustments
+ .iter()
+ .map(|Adjustment { kind, .. }| format!("{:?}", kind))
+ .collect::<Vec<_>>()
+ );
+ } else {
+ panic!("expected {:?} adjustments, found none", expected);
+ }
+ }
}
for (pat, mismatch) in inference_result.pat_type_mismatches() {
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);
+ match mismatches.remove(&range) {
+ Some(annotation) => assert_eq!(actual, annotation),
+ None => format_to!(unexpected_type_mismatches, "{:?}: {}\n", range.range, actual),
}
}
for (expr, mismatch) in inference_result.expr_type_mismatches() {
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);
+ match mismatches.remove(&range) {
+ Some(annotation) => assert_eq!(actual, annotation),
+ None => format_to!(unexpected_type_mismatches, "{:?}: {}\n", range.range, actual),
}
}
}
format_to!(buf, "{:?}: type {}\n", t.0.range, t.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);
+ }
+ }
assert!(buf.is_empty(), "{}", buf);
}
let (range, text) = if let Some(self_param) = ast::SelfParam::cast(node.value.clone()) {
(self_param.name().unwrap().syntax().text_range(), "self".to_string())
} else {
- (node.value.text_range(), node.value.text().to_string().replace("\n", " "))
+ (node.value.text_range(), node.value.text().to_string().replace('\n', " "))
};
let macro_prefix = if node.file_id != file_id.into() { "!" } else { "" };
format_to!(