2019-11-15 15:56:51 -06:00
|
|
|
mod never_type;
|
|
|
|
mod coercion;
|
2019-12-03 06:38:54 -06:00
|
|
|
mod regression;
|
|
|
|
mod simple;
|
|
|
|
mod patterns;
|
|
|
|
mod traits;
|
|
|
|
mod method_resolution;
|
|
|
|
mod macros;
|
2020-04-25 09:57:59 -05:00
|
|
|
mod display_source_code;
|
2021-05-27 13:21:52 -05:00
|
|
|
mod incremental;
|
2022-03-29 10:51:11 -05:00
|
|
|
mod diagnostics;
|
2019-11-15 15:56:51 -06:00
|
|
|
|
2023-05-02 09:12:22 -05:00
|
|
|
use std::{collections::HashMap, env};
|
2018-12-20 14:56:28 -06:00
|
|
|
|
2021-06-20 12:10:45 -05:00
|
|
|
use base_db::{fixture::WithFixture, FileRange, SourceDatabaseExt};
|
2020-08-21 06:19:31 -05:00
|
|
|
use expect_test::Expect;
|
2019-11-27 08:46:02 -06:00
|
|
|
use hir_def::{
|
2021-03-05 07:53:32 -06:00
|
|
|
body::{Body, BodySourceMap, SyntheticSyntax},
|
2022-08-06 11:50:21 -05:00
|
|
|
db::{DefDatabase, InternDatabase},
|
2023-05-04 07:33:36 -05:00
|
|
|
hir::{ExprId, Pat, PatId},
|
2020-03-06 07:44:44 -06:00
|
|
|
item_scope::ItemScope,
|
2021-01-18 13:18:05 -06:00
|
|
|
nameres::DefMap,
|
2021-03-12 16:54:29 -06:00
|
|
|
src::HasSource,
|
2021-06-20 12:10:45 -05:00
|
|
|
AssocItemId, DefWithBodyId, HasModule, LocalModuleId, Lookup, ModuleDefId,
|
2019-11-27 08:46:02 -06:00
|
|
|
};
|
2023-03-13 10:33:52 -05:00
|
|
|
use hir_expand::{db::ExpandDatabase, InFile};
|
2020-11-10 20:11:40 -06:00
|
|
|
use once_cell::race::OnceBool;
|
|
|
|
use stdx::format_to;
|
2020-08-12 11:26:51 -05:00
|
|
|
use syntax::{
|
2021-09-27 05:54:24 -05:00
|
|
|
ast::{self, AstNode, HasName},
|
2020-04-23 14:23:36 -05:00
|
|
|
SyntaxNode,
|
2019-07-04 15:05:17 -05:00
|
|
|
};
|
2023-06-17 16:23:25 -05:00
|
|
|
use tracing_subscriber::{layer::SubscriberExt, Registry};
|
2020-08-18 10:20:10 -05:00
|
|
|
use tracing_tree::HierarchicalLayer;
|
2023-05-02 09:12:22 -05:00
|
|
|
use triomphe::Arc;
|
2018-12-20 14:56:28 -06:00
|
|
|
|
2020-04-23 14:23:36 -05:00
|
|
|
use crate::{
|
2021-07-06 11:05:40 -05:00
|
|
|
db::HirDatabase,
|
|
|
|
display::HirDisplay,
|
|
|
|
infer::{Adjustment, TypeMismatch},
|
|
|
|
test_db::TestDB,
|
|
|
|
InferenceResult, Ty,
|
2020-04-23 14:23:36 -05:00
|
|
|
};
|
2018-12-20 14:56:28 -06:00
|
|
|
|
2018-12-24 08:36:54 -06:00
|
|
|
// These tests compare the inference results for all expressions in a file
|
2020-07-21 05:11:02 -05:00
|
|
|
// against snapshots of the expected results using expect. Use
|
2020-08-13 09:35:29 -05:00
|
|
|
// `env UPDATE_EXPECT=1 cargo test -p hir_ty` to update the snapshots.
|
2018-12-24 08:36:54 -06:00
|
|
|
|
2020-08-18 10:20:10 -05:00
|
|
|
fn setup_tracing() -> Option<tracing::subscriber::DefaultGuard> {
|
2020-11-10 20:11:40 -06:00
|
|
|
static ENABLE: OnceBool = OnceBool::new();
|
|
|
|
if !ENABLE.get_or_init(|| env::var("CHALK_DEBUG").is_ok()) {
|
2020-08-18 10:20:10 -05:00
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
2023-06-17 16:23:25 -05:00
|
|
|
let filter: tracing_subscriber::filter::Targets =
|
|
|
|
env::var("CHALK_DEBUG").ok().and_then(|it| it.parse().ok()).unwrap_or_default();
|
2020-07-12 08:26:02 -05:00
|
|
|
let layer = HierarchicalLayer::default()
|
|
|
|
.with_indent_lines(true)
|
|
|
|
.with_ansi(false)
|
|
|
|
.with_indent_amount(2)
|
|
|
|
.with_writer(std::io::stderr);
|
2020-07-10 11:30:32 -05:00
|
|
|
let subscriber = Registry::default().with(filter).with(layer);
|
2020-08-18 10:20:10 -05:00
|
|
|
Some(tracing::subscriber::set_default(subscriber))
|
2020-07-10 11:30:32 -05:00
|
|
|
}
|
|
|
|
|
2023-03-04 07:45:57 -06:00
|
|
|
#[track_caller]
|
2020-06-29 07:21:57 -05:00
|
|
|
fn check_types(ra_fixture: &str) {
|
2021-06-20 12:10:45 -05:00
|
|
|
check_impl(ra_fixture, false, true, false)
|
2020-06-29 10:22:47 -05:00
|
|
|
}
|
|
|
|
|
2023-03-04 07:45:57 -06:00
|
|
|
#[track_caller]
|
2020-06-29 10:22:47 -05:00
|
|
|
fn check_types_source_code(ra_fixture: &str) {
|
2021-06-20 12:10:45 -05:00
|
|
|
check_impl(ra_fixture, false, true, true)
|
2020-06-29 07:21:57 -05:00
|
|
|
}
|
|
|
|
|
2023-03-04 07:45:57 -06:00
|
|
|
#[track_caller]
|
2021-06-03 16:12:35 -05:00
|
|
|
fn check_no_mismatches(ra_fixture: &str) {
|
2021-06-20 12:10:45 -05:00
|
|
|
check_impl(ra_fixture, true, false, false)
|
2021-06-03 16:12:35 -05:00
|
|
|
}
|
|
|
|
|
2023-03-04 07:45:57 -06:00
|
|
|
#[track_caller]
|
2021-06-20 09:37:50 -05:00
|
|
|
fn check(ra_fixture: &str) {
|
2021-06-20 12:10:45 -05:00
|
|
|
check_impl(ra_fixture, false, false, false)
|
2021-06-03 16:12:35 -05:00
|
|
|
}
|
|
|
|
|
2023-03-04 07:45:57 -06:00
|
|
|
#[track_caller]
|
2021-06-20 12:10:45 -05:00
|
|
|
fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_source: bool) {
|
2021-06-03 16:12:35 -05:00
|
|
|
let _tracing = setup_tracing();
|
2021-06-20 09:37:50 -05:00
|
|
|
let (db, files) = TestDB::with_many_files(ra_fixture);
|
|
|
|
|
|
|
|
let mut had_annotations = false;
|
|
|
|
let mut mismatches = HashMap::new();
|
|
|
|
let mut types = HashMap::new();
|
2021-07-06 11:05:40 -05:00
|
|
|
let mut adjustments = HashMap::<_, Vec<_>>::new();
|
2021-06-20 09:37:50 -05:00
|
|
|
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);
|
2023-01-02 16:16:09 -06:00
|
|
|
} else if expected.starts_with("adjustments:") {
|
2021-07-06 11:05:40 -05:00
|
|
|
adjustments.insert(
|
|
|
|
file_range,
|
|
|
|
expected
|
2023-01-02 16:16:09 -06:00
|
|
|
.trim_start_matches("adjustments:")
|
|
|
|
.trim()
|
2021-07-06 11:05:40 -05:00
|
|
|
.split(',')
|
|
|
|
.map(|it| it.trim().to_string())
|
Refactor autoderef and method resolution
- don't return the receiver type from method resolution; instead just
return the autorefs/autoderefs that happened and repeat them. This
ensures all the effects like trait obligations and whatever we learned
about type variables from derefing them are actually applied. Also, it
allows us to get rid of `decanonicalize_ty`, which was just wrong in
principle.
- Autoderef itself now directly works with an inference table. Sadly
this has the effect of making it harder to use as an iterator, often
requiring manual `while let` loops. (rustc works around this by using
inner mutability in the inference context, so that things like unifying
types don't require a unique reference.)
- We now record the adjustments (autoref/deref) for method receivers
and index expressions, which we didn't before.
- Removed the redundant crate parameter from method resolution, since
the trait_env contains the crate as well.
- in the HIR API, the methods now take a scope to determine the trait env.
`Type` carries a trait env, but I think that's probably a bad decision
because it's easy to create it with the wrong env, e.g. by using
`Adt::ty`. This mostly didn't matter so far because
`iterate_method_candidates` took a crate parameter and ignored
`self.krate`, but the trait env would still have been wrong in those
cases, which I think would give some wrong results in some edge cases.
Fixes #10058.
2022-02-16 10:44:03 -06:00
|
|
|
.filter(|it| !it.is_empty())
|
2021-07-06 11:05:40 -05:00
|
|
|
.collect(),
|
|
|
|
);
|
2021-06-20 09:37:50 -05:00
|
|
|
} else {
|
2022-12-23 12:42:58 -06:00
|
|
|
panic!("unexpected annotation: {expected}");
|
2021-06-20 09:37:50 -05:00
|
|
|
}
|
|
|
|
had_annotations = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert!(had_annotations || allow_none, "no `//^` annotations found");
|
2021-06-03 16:12:35 -05:00
|
|
|
|
|
|
|
let mut defs: Vec<DefWithBodyId> = Vec::new();
|
2021-06-20 09:37:50 -05:00
|
|
|
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));
|
|
|
|
}
|
2021-06-03 16:12:35 -05:00
|
|
|
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()
|
|
|
|
}
|
2022-08-06 11:50:21 -05:00
|
|
|
DefWithBodyId::VariantId(it) => {
|
|
|
|
let loc = db.lookup_intern_enum(it.parent);
|
|
|
|
loc.source(&db).value.syntax().text_range().start()
|
|
|
|
}
|
2023-06-05 06:27:19 -05:00
|
|
|
DefWithBodyId::InTypeConstId(it) => it.source(&db).syntax().text_range().start(),
|
2021-06-03 16:12:35 -05:00
|
|
|
});
|
2021-06-20 09:37:50 -05:00
|
|
|
let mut unexpected_type_mismatches = String::new();
|
2021-06-03 16:12:35 -05:00
|
|
|
for def in defs {
|
2023-05-04 07:33:36 -05:00
|
|
|
let (body, body_source_map) = db.body_with_source_map(def);
|
2021-06-03 16:12:35 -05:00
|
|
|
let inference_result = db.infer(def);
|
2021-06-20 09:37:50 -05:00
|
|
|
|
2023-05-04 07:33:36 -05:00
|
|
|
for (pat, mut ty) in inference_result.type_of_pat.iter() {
|
|
|
|
if let Pat::Bind { id, .. } = body.pats[pat] {
|
|
|
|
ty = &inference_result.type_of_binding[id];
|
|
|
|
}
|
2021-06-20 12:10:45 -05:00
|
|
|
let node = match pat_node(&body_source_map, pat, &db) {
|
|
|
|
Some(value) => value,
|
|
|
|
None => continue,
|
2021-06-20 09:37:50 -05:00
|
|
|
};
|
|
|
|
let range = node.as_ref().original_file_range(&db);
|
2021-06-20 12:10:45 -05:00
|
|
|
if let Some(expected) = types.remove(&range) {
|
|
|
|
let actual = if display_source {
|
2023-04-07 08:45:04 -05:00
|
|
|
ty.display_source_code(&db, def.module(&db), true).unwrap()
|
2021-06-20 12:10:45 -05:00
|
|
|
} else {
|
|
|
|
ty.display_test(&db).to_string()
|
|
|
|
};
|
2023-03-05 07:37:44 -06:00
|
|
|
assert_eq!(actual, expected, "type annotation differs at {:#?}", range.range);
|
2021-06-20 09:37:50 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (expr, ty) in inference_result.type_of_expr.iter() {
|
2021-06-20 12:10:45 -05:00
|
|
|
let node = match expr_node(&body_source_map, expr, &db) {
|
|
|
|
Some(value) => value,
|
|
|
|
None => continue,
|
2021-06-20 09:37:50 -05:00
|
|
|
};
|
|
|
|
let range = node.as_ref().original_file_range(&db);
|
2021-06-20 12:10:45 -05:00
|
|
|
if let Some(expected) = types.remove(&range) {
|
|
|
|
let actual = if display_source {
|
2023-04-07 08:45:04 -05:00
|
|
|
ty.display_source_code(&db, def.module(&db), true).unwrap()
|
2021-06-20 12:10:45 -05:00
|
|
|
} else {
|
|
|
|
ty.display_test(&db).to_string()
|
|
|
|
};
|
2023-03-05 07:37:44 -06:00
|
|
|
assert_eq!(actual, expected, "type annotation differs at {:#?}", range.range);
|
2021-06-20 09:37:50 -05:00
|
|
|
}
|
2021-07-06 11:05:40 -05:00
|
|
|
if let Some(expected) = adjustments.remove(&range) {
|
2023-01-02 16:16:09 -06:00
|
|
|
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:?}"))
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
);
|
2021-07-06 11:05:40 -05:00
|
|
|
}
|
2021-06-20 09:37:50 -05:00
|
|
|
}
|
|
|
|
|
2023-02-28 08:13:45 -06:00
|
|
|
for (expr_or_pat, mismatch) in inference_result.type_mismatches() {
|
|
|
|
let Some(node) = (match expr_or_pat {
|
2023-04-06 12:36:25 -05:00
|
|
|
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),
|
2023-07-03 13:34:09 -05:00
|
|
|
}) else {
|
|
|
|
continue;
|
|
|
|
};
|
2021-06-20 09:37:50 -05:00
|
|
|
let range = node.as_ref().original_file_range(&db);
|
|
|
|
let actual = format!(
|
|
|
|
"expected {}, got {}",
|
|
|
|
mismatch.expected.display_test(&db),
|
|
|
|
mismatch.actual.display_test(&db)
|
|
|
|
);
|
2021-10-03 07:53:01 -05:00
|
|
|
match mismatches.remove(&range) {
|
|
|
|
Some(annotation) => assert_eq!(actual, annotation),
|
|
|
|
None => format_to!(unexpected_type_mismatches, "{:?}: {}\n", range.range, actual),
|
2021-06-03 16:12:35 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-06-20 09:37:50 -05:00
|
|
|
|
2021-06-03 16:12:35 -05:00
|
|
|
let mut buf = String::new();
|
2021-06-20 09:37:50 -05:00
|
|
|
if !unexpected_type_mismatches.is_empty() {
|
|
|
|
format_to!(buf, "Unexpected type mismatches:\n{}", unexpected_type_mismatches);
|
2021-06-03 16:12:35 -05:00
|
|
|
}
|
2021-06-20 09:37:50 -05:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2021-07-06 11:05:40 -05:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2021-06-20 09:37:50 -05:00
|
|
|
assert!(buf.is_empty(), "{}", buf);
|
2021-06-03 16:12:35 -05:00
|
|
|
}
|
|
|
|
|
2021-06-20 12:10:45 -05:00
|
|
|
fn expr_node(
|
|
|
|
body_source_map: &BodySourceMap,
|
|
|
|
expr: ExprId,
|
|
|
|
db: &TestDB,
|
|
|
|
) -> Option<InFile<SyntaxNode>> {
|
|
|
|
Some(match body_source_map.expr_syntax(expr) {
|
|
|
|
Ok(sp) => {
|
2023-04-16 12:20:48 -05:00
|
|
|
let root = db.parse_or_expand(sp.file_id);
|
2021-06-20 12:10:45 -05:00
|
|
|
sp.map(|ptr| ptr.to_node(&root).syntax().clone())
|
|
|
|
}
|
|
|
|
Err(SyntheticSyntax) => return None,
|
|
|
|
})
|
|
|
|
}
|
2019-12-05 14:17:17 -06:00
|
|
|
|
2021-06-20 12:10:45 -05:00
|
|
|
fn pat_node(
|
|
|
|
body_source_map: &BodySourceMap,
|
|
|
|
pat: PatId,
|
|
|
|
db: &TestDB,
|
|
|
|
) -> Option<InFile<SyntaxNode>> {
|
|
|
|
Some(match body_source_map.pat_syntax(pat) {
|
|
|
|
Ok(sp) => {
|
2023-04-16 12:20:48 -05:00
|
|
|
let root = db.parse_or_expand(sp.file_id);
|
2023-10-06 05:32:37 -05:00
|
|
|
sp.map(|ptr| ptr.to_node(&root).syntax().clone())
|
2021-06-20 12:10:45 -05:00
|
|
|
}
|
|
|
|
Err(SyntheticSyntax) => return None,
|
|
|
|
})
|
2019-02-23 05:32:25 -06:00
|
|
|
}
|
|
|
|
|
2020-02-27 09:05:35 -06:00
|
|
|
fn infer(ra_fixture: &str) -> String {
|
|
|
|
infer_with_mismatches(ra_fixture, false)
|
2019-12-05 16:02:31 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
|
2020-07-10 11:30:32 -05:00
|
|
|
let _tracing = setup_tracing();
|
2019-11-04 13:21:15 -06:00
|
|
|
let (db, file_id) = TestDB::with_single_file(content);
|
2019-04-18 13:35:47 -05:00
|
|
|
|
2020-03-28 05:20:34 -05:00
|
|
|
let mut buf = String::new();
|
2019-03-30 06:17:31 -05:00
|
|
|
|
|
|
|
let mut infer_def = |inference_result: Arc<InferenceResult>,
|
2023-05-04 07:33:36 -05:00
|
|
|
body: Arc<Body>,
|
2019-03-30 06:17:31 -05:00
|
|
|
body_source_map: Arc<BodySourceMap>| {
|
2020-04-23 14:23:36 -05:00
|
|
|
let mut types: Vec<(InFile<SyntaxNode>, &Ty)> = Vec::new();
|
|
|
|
let mut mismatches: Vec<(InFile<SyntaxNode>, &TypeMismatch)> = Vec::new();
|
2019-03-30 06:17:31 -05:00
|
|
|
|
2023-05-04 07:33:36 -05:00
|
|
|
for (pat, mut ty) in inference_result.type_of_pat.iter() {
|
|
|
|
if let Pat::Bind { id, .. } = body.pats[pat] {
|
|
|
|
ty = &inference_result.type_of_binding[id];
|
|
|
|
}
|
2019-03-02 06:14:37 -06:00
|
|
|
let syntax_ptr = match body_source_map.pat_syntax(pat) {
|
2020-03-06 07:44:44 -06:00
|
|
|
Ok(sp) => {
|
2023-04-16 12:20:48 -05:00
|
|
|
let root = db.parse_or_expand(sp.file_id);
|
2023-10-06 05:32:37 -05:00
|
|
|
sp.map(|ptr| ptr.to_node(&root).syntax().clone())
|
2019-09-03 03:04:38 -05:00
|
|
|
}
|
2020-03-06 07:44:44 -06:00
|
|
|
Err(SyntheticSyntax) => continue,
|
2019-01-06 09:47:59 -06:00
|
|
|
};
|
2021-05-18 23:23:16 -05:00
|
|
|
types.push((syntax_ptr.clone(), ty));
|
|
|
|
if let Some(mismatch) = inference_result.type_mismatch_for_pat(pat) {
|
|
|
|
mismatches.push((syntax_ptr, mismatch));
|
|
|
|
}
|
2019-01-06 09:47:59 -06:00
|
|
|
}
|
2019-03-30 06:17:31 -05:00
|
|
|
|
2019-01-06 16:57:39 -06:00
|
|
|
for (expr, ty) in inference_result.type_of_expr.iter() {
|
2020-04-23 14:23:36 -05:00
|
|
|
let node = match body_source_map.expr_syntax(expr) {
|
|
|
|
Ok(sp) => {
|
2023-04-16 12:20:48 -05:00
|
|
|
let root = db.parse_or_expand(sp.file_id);
|
2020-04-23 14:23:36 -05:00
|
|
|
sp.map(|ptr| ptr.to_node(&root).syntax().clone())
|
|
|
|
}
|
2020-03-06 07:44:44 -06:00
|
|
|
Err(SyntheticSyntax) => continue,
|
2019-01-06 09:47:59 -06:00
|
|
|
};
|
2020-04-23 14:23:36 -05:00
|
|
|
types.push((node.clone(), ty));
|
2019-12-05 16:02:31 -06:00
|
|
|
if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr) {
|
2020-04-23 14:23:36 -05:00
|
|
|
mismatches.push((node, mismatch));
|
2019-12-05 16:02:31 -06:00
|
|
|
}
|
2019-01-06 09:47:59 -06:00
|
|
|
}
|
2019-04-18 13:35:47 -05:00
|
|
|
|
2019-01-06 16:01:33 -06:00
|
|
|
// sort ranges for consistency
|
2020-04-23 14:23:36 -05:00
|
|
|
types.sort_by_key(|(node, _)| {
|
|
|
|
let range = node.value.text_range();
|
|
|
|
(range.start(), range.end())
|
2019-11-20 00:40:36 -06:00
|
|
|
});
|
2020-04-23 14:23:36 -05:00
|
|
|
for (node, ty) in &types {
|
|
|
|
let (range, text) = if let Some(self_param) = ast::SelfParam::cast(node.value.clone()) {
|
2021-01-15 14:07:38 -06:00
|
|
|
(self_param.name().unwrap().syntax().text_range(), "self".to_string())
|
2019-03-30 05:25:53 -05:00
|
|
|
} else {
|
2022-03-12 06:22:12 -06:00
|
|
|
(node.value.text_range(), node.value.text().to_string().replace('\n', " "))
|
2019-03-30 05:25:53 -05:00
|
|
|
};
|
2020-04-23 14:23:36 -05:00
|
|
|
let macro_prefix = if node.file_id != file_id.into() { "!" } else { "" };
|
2020-03-28 05:20:34 -05:00
|
|
|
format_to!(
|
|
|
|
buf,
|
2020-04-24 16:40:41 -05:00
|
|
|
"{}{:?} '{}': {}\n",
|
2019-09-03 03:04:38 -05:00
|
|
|
macro_prefix,
|
|
|
|
range,
|
|
|
|
ellipsize(text, 15),
|
2020-10-28 09:09:47 -05:00
|
|
|
ty.display_test(&db)
|
2020-03-28 05:20:34 -05:00
|
|
|
);
|
2018-12-20 14:56:28 -06:00
|
|
|
}
|
2019-12-05 16:02:31 -06:00
|
|
|
if include_mismatches {
|
2020-04-23 14:23:36 -05:00
|
|
|
mismatches.sort_by_key(|(node, _)| {
|
|
|
|
let range = node.value.text_range();
|
|
|
|
(range.start(), range.end())
|
2019-12-05 16:02:31 -06:00
|
|
|
});
|
|
|
|
for (src_ptr, mismatch) in &mismatches {
|
2020-04-23 14:23:36 -05:00
|
|
|
let range = src_ptr.value.text_range();
|
2019-12-05 16:02:31 -06:00
|
|
|
let macro_prefix = if src_ptr.file_id != file_id.into() { "!" } else { "" };
|
2020-03-28 05:20:34 -05:00
|
|
|
format_to!(
|
|
|
|
buf,
|
2020-04-24 16:40:41 -05:00
|
|
|
"{}{:?}: expected {}, got {}\n",
|
2019-12-05 16:02:31 -06:00
|
|
|
macro_prefix,
|
|
|
|
range,
|
2020-10-28 09:09:47 -05:00
|
|
|
mismatch.expected.display_test(&db),
|
|
|
|
mismatch.actual.display_test(&db),
|
2020-03-28 05:20:34 -05:00
|
|
|
);
|
2019-12-05 16:02:31 -06:00
|
|
|
}
|
|
|
|
}
|
2019-03-30 06:17:31 -05:00
|
|
|
};
|
|
|
|
|
2019-11-27 08:46:02 -06:00
|
|
|
let module = db.module_for_file(file_id);
|
2021-01-22 09:31:40 -06:00
|
|
|
let def_map = module.def_map(&db);
|
2019-11-27 08:46:02 -06:00
|
|
|
|
|
|
|
let mut defs: Vec<DefWithBodyId> = Vec::new();
|
2021-01-22 09:31:40 -06:00
|
|
|
visit_module(&db, &def_map, module.local_id, &mut |it| defs.push(it));
|
2019-11-27 08:46:02 -06:00
|
|
|
defs.sort_by_key(|def| match def {
|
|
|
|
DefWithBodyId::FunctionId(it) => {
|
2020-06-22 08:07:06 -05:00
|
|
|
let loc = it.lookup(&db);
|
2021-03-12 16:54:29 -06:00
|
|
|
loc.source(&db).value.syntax().text_range().start()
|
2019-11-27 08:46:02 -06:00
|
|
|
}
|
|
|
|
DefWithBodyId::ConstId(it) => {
|
2020-06-22 08:07:06 -05:00
|
|
|
let loc = it.lookup(&db);
|
2021-03-12 16:54:29 -06:00
|
|
|
loc.source(&db).value.syntax().text_range().start()
|
2019-11-27 08:46:02 -06:00
|
|
|
}
|
|
|
|
DefWithBodyId::StaticId(it) => {
|
2020-06-22 08:07:06 -05:00
|
|
|
let loc = it.lookup(&db);
|
2021-03-12 16:54:29 -06:00
|
|
|
loc.source(&db).value.syntax().text_range().start()
|
2019-04-12 16:56:57 -05:00
|
|
|
}
|
2022-08-06 11:50:21 -05:00
|
|
|
DefWithBodyId::VariantId(it) => {
|
|
|
|
let loc = db.lookup_intern_enum(it.parent);
|
|
|
|
loc.source(&db).value.syntax().text_range().start()
|
|
|
|
}
|
2023-06-05 06:27:19 -05:00
|
|
|
DefWithBodyId::InTypeConstId(it) => it.source(&db).syntax().text_range().start(),
|
2019-11-27 08:46:02 -06:00
|
|
|
});
|
|
|
|
for def in defs {
|
2023-05-04 07:33:36 -05:00
|
|
|
let (body, source_map) = db.body_with_source_map(def);
|
2019-11-27 08:46:02 -06:00
|
|
|
let infer = db.infer(def);
|
2023-05-04 07:33:36 -05:00
|
|
|
infer_def(infer, body, source_map);
|
2019-03-30 06:17:31 -05:00
|
|
|
}
|
|
|
|
|
2020-03-28 05:20:34 -05:00
|
|
|
buf.truncate(buf.trim_end().len());
|
|
|
|
buf
|
2018-12-23 05:05:54 -06:00
|
|
|
}
|
|
|
|
|
2019-11-27 08:46:02 -06:00
|
|
|
fn visit_module(
|
|
|
|
db: &TestDB,
|
2021-01-18 13:18:05 -06:00
|
|
|
crate_def_map: &DefMap,
|
2019-11-27 08:46:02 -06:00
|
|
|
module_id: LocalModuleId,
|
|
|
|
cb: &mut dyn FnMut(DefWithBodyId),
|
|
|
|
) {
|
2019-12-29 07:46:24 -06:00
|
|
|
visit_scope(db, crate_def_map, &crate_def_map[module_id].scope, cb);
|
2019-12-20 08:58:20 -06:00
|
|
|
for impl_id in crate_def_map[module_id].scope.impls() {
|
2019-11-27 08:46:02 -06:00
|
|
|
let impl_data = db.impl_data(impl_id);
|
|
|
|
for &item in impl_data.items.iter() {
|
|
|
|
match item {
|
2019-12-29 07:46:24 -06:00
|
|
|
AssocItemId::FunctionId(it) => {
|
|
|
|
let def = it.into();
|
|
|
|
cb(def);
|
|
|
|
let body = db.body(def);
|
2021-03-05 07:53:32 -06:00
|
|
|
visit_body(db, &body, cb);
|
2019-12-29 07:46:24 -06:00
|
|
|
}
|
|
|
|
AssocItemId::ConstId(it) => {
|
|
|
|
let def = it.into();
|
|
|
|
cb(def);
|
|
|
|
let body = db.body(def);
|
2021-03-05 07:53:32 -06:00
|
|
|
visit_body(db, &body, cb);
|
2019-12-29 07:46:24 -06:00
|
|
|
}
|
2019-11-27 08:46:02 -06:00
|
|
|
AssocItemId::TypeAliasId(_) => (),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-12-29 07:46:24 -06:00
|
|
|
|
|
|
|
fn visit_scope(
|
|
|
|
db: &TestDB,
|
2021-01-18 13:18:05 -06:00
|
|
|
crate_def_map: &DefMap,
|
2019-12-29 07:46:24 -06:00
|
|
|
scope: &ItemScope,
|
|
|
|
cb: &mut dyn FnMut(DefWithBodyId),
|
|
|
|
) {
|
|
|
|
for decl in scope.declarations() {
|
|
|
|
match decl {
|
|
|
|
ModuleDefId::FunctionId(it) => {
|
|
|
|
let def = it.into();
|
|
|
|
cb(def);
|
|
|
|
let body = db.body(def);
|
2021-03-05 07:53:32 -06:00
|
|
|
visit_body(db, &body, cb);
|
2019-12-29 07:46:24 -06:00
|
|
|
}
|
|
|
|
ModuleDefId::ConstId(it) => {
|
|
|
|
let def = it.into();
|
|
|
|
cb(def);
|
|
|
|
let body = db.body(def);
|
2021-03-05 07:53:32 -06:00
|
|
|
visit_body(db, &body, cb);
|
2019-12-29 07:46:24 -06:00
|
|
|
}
|
|
|
|
ModuleDefId::StaticId(it) => {
|
|
|
|
let def = it.into();
|
|
|
|
cb(def);
|
|
|
|
let body = db.body(def);
|
2021-03-05 07:53:32 -06:00
|
|
|
visit_body(db, &body, cb);
|
2019-12-29 07:46:24 -06:00
|
|
|
}
|
2022-09-20 10:43:29 -05:00
|
|
|
ModuleDefId::AdtId(hir_def::AdtId::EnumId(it)) => {
|
|
|
|
db.enum_data(it)
|
|
|
|
.variants
|
|
|
|
.iter()
|
|
|
|
.map(|(id, _)| hir_def::EnumVariantId { parent: it, local_id: id })
|
|
|
|
.for_each(|it| {
|
|
|
|
let def = it.into();
|
|
|
|
cb(def);
|
|
|
|
let body = db.body(def);
|
|
|
|
visit_body(db, &body, cb);
|
|
|
|
});
|
|
|
|
}
|
2019-12-29 07:46:24 -06:00
|
|
|
ModuleDefId::TraitId(it) => {
|
|
|
|
let trait_data = db.trait_data(it);
|
|
|
|
for &(_, item) in trait_data.items.iter() {
|
|
|
|
match item {
|
|
|
|
AssocItemId::FunctionId(it) => cb(it.into()),
|
|
|
|
AssocItemId::ConstId(it) => cb(it.into()),
|
|
|
|
AssocItemId::TypeAliasId(_) => (),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ModuleDefId::ModuleId(it) => visit_module(db, crate_def_map, it.local_id, cb),
|
|
|
|
_ => (),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-03-05 07:53:32 -06:00
|
|
|
|
|
|
|
fn visit_body(db: &TestDB, body: &Body, cb: &mut dyn FnMut(DefWithBodyId)) {
|
2021-04-03 20:03:18 -05:00
|
|
|
for (_, def_map) in body.blocks(db) {
|
2021-03-05 07:53:32 -06:00
|
|
|
for (mod_id, _) in def_map.modules() {
|
|
|
|
visit_module(db, &def_map, mod_id, cb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-11-27 08:46:02 -06:00
|
|
|
}
|
|
|
|
|
2018-12-23 05:05:54 -06:00
|
|
|
fn ellipsize(mut text: String, max_len: usize) -> String {
|
|
|
|
if text.len() <= max_len {
|
|
|
|
return text;
|
|
|
|
}
|
|
|
|
let ellipsis = "...";
|
|
|
|
let e_len = ellipsis.len();
|
|
|
|
let mut prefix_len = (max_len - e_len) / 2;
|
|
|
|
while !text.is_char_boundary(prefix_len) {
|
|
|
|
prefix_len += 1;
|
|
|
|
}
|
|
|
|
let mut suffix_len = max_len - e_len - prefix_len;
|
|
|
|
while !text.is_char_boundary(text.len() - suffix_len) {
|
|
|
|
suffix_len += 1;
|
|
|
|
}
|
|
|
|
text.replace_range(prefix_len..text.len() - suffix_len, ellipsis);
|
|
|
|
text
|
2018-12-20 14:56:28 -06:00
|
|
|
}
|
|
|
|
|
2020-07-20 11:38:52 -05:00
|
|
|
fn check_infer(ra_fixture: &str, expect: Expect) {
|
2020-07-20 14:01:09 -05:00
|
|
|
let mut actual = infer(ra_fixture);
|
2020-07-20 11:38:52 -05:00
|
|
|
actual.push('\n');
|
|
|
|
expect.assert_eq(&actual);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn check_infer_with_mismatches(ra_fixture: &str, expect: Expect) {
|
|
|
|
let mut actual = infer_with_mismatches(ra_fixture, true);
|
|
|
|
actual.push('\n');
|
|
|
|
expect.assert_eq(&actual);
|
|
|
|
}
|
2021-03-20 09:26:42 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn salsa_bug() {
|
|
|
|
let (mut db, pos) = TestDB::with_position(
|
|
|
|
"
|
|
|
|
//- /lib.rs
|
|
|
|
trait Index {
|
|
|
|
type Output;
|
|
|
|
}
|
|
|
|
|
|
|
|
type Key<S: UnificationStoreBase> = <S as UnificationStoreBase>::Key;
|
|
|
|
|
|
|
|
pub trait UnificationStoreBase: Index<Output = Key<Self>> {
|
|
|
|
type Key;
|
|
|
|
|
|
|
|
fn len(&self) -> usize;
|
|
|
|
}
|
|
|
|
|
|
|
|
pub trait UnificationStoreMut: UnificationStoreBase {
|
|
|
|
fn push(&mut self, value: Self::Key);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
let x = 1;
|
|
|
|
x.push(1);$0
|
|
|
|
}
|
|
|
|
",
|
|
|
|
);
|
|
|
|
|
|
|
|
let module = db.module_for_file(pos.file_id);
|
|
|
|
let crate_def_map = module.def_map(&db);
|
|
|
|
visit_module(&db, &crate_def_map, module.local_id, &mut |def| {
|
|
|
|
db.infer(def);
|
|
|
|
});
|
|
|
|
|
|
|
|
let new_text = "
|
|
|
|
//- /lib.rs
|
|
|
|
trait Index {
|
|
|
|
type Output;
|
|
|
|
}
|
|
|
|
|
|
|
|
type Key<S: UnificationStoreBase> = <S as UnificationStoreBase>::Key;
|
|
|
|
|
|
|
|
pub trait UnificationStoreBase: Index<Output = Key<Self>> {
|
|
|
|
type Key;
|
|
|
|
|
|
|
|
fn len(&self) -> usize;
|
|
|
|
}
|
|
|
|
|
|
|
|
pub trait UnificationStoreMut: UnificationStoreBase {
|
|
|
|
fn push(&mut self, value: Self::Key);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
|
|
|
|
let x = 1;
|
|
|
|
x.push(1);
|
|
|
|
}
|
2023-04-22 02:48:37 -05:00
|
|
|
";
|
2021-03-20 09:26:42 -05:00
|
|
|
|
2023-04-22 02:48:37 -05:00
|
|
|
db.set_file_text(pos.file_id, Arc::from(new_text));
|
2021-03-20 09:26:42 -05:00
|
|
|
|
|
|
|
let module = db.module_for_file(pos.file_id);
|
|
|
|
let crate_def_map = module.def_map(&db);
|
|
|
|
visit_module(&db, &crate_def_map, module.local_id, &mut |def| {
|
|
|
|
db.infer(def);
|
|
|
|
});
|
|
|
|
}
|