mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-11 20:58:54 +00:00
Merge #9346
9346: Refactor / clean up hir_ty tests r=flodiebold a=flodiebold Notable changes: - unify `check_types` and `check_mismatches` into `check`, which supports both kinds of annotations (`check_types` still exists because I didn't want to change all the annotations, but uses the same implementation) - because of that, `check_types` now fails on any type mismatches; also annotations always have to hit the exact range - there's also `check_no_mismatches` for when we explicitly just want to check that there are no type mismatches without giving any annotations (`check` will fail without annotations) - test annotations can now be overlapping (they point to the nearest line that has actual code in that range): ``` // ^^^^ annotation // ^^^^^^^^^ another annotation ``` Co-authored-by: Florian Diebold <flodiebold@gmail.com>
This commit is contained in:
commit
3898387f3b
12 changed files with 572 additions and 1011 deletions
|
@ -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<Interner> for ChalkContext<'a> {
|
|||
};
|
||||
|
||||
fn local_impls(db: &dyn HirDatabase, module: ModuleId) -> Option<Arc<TraitImpls>> {
|
||||
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
|
||||
|
|
|
@ -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<ModuleId> {
|
||||
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<FileId, Vec<(TextRange, String)>> {
|
||||
|
|
|
@ -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,51 +57,55 @@ fn setup_tracing() -> Option<tracing::subscriber::DefaultGuard> {
|
|||
}
|
||||
|
||||
fn check_types(ra_fixture: &str) {
|
||||
check_types_impl(ra_fixture, false)
|
||||
check_impl(ra_fixture, false, true, false)
|
||||
}
|
||||
|
||||
fn check_types_source_code(ra_fixture: &str) {
|
||||
check_types_impl(ra_fixture, true)
|
||||
}
|
||||
|
||||
fn check_types_impl(ra_fixture: &str, display_source: bool) {
|
||||
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_mismatches_impl(ra_fixture, true)
|
||||
check_impl(ra_fixture, true, false, 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, false)
|
||||
}
|
||||
|
||||
fn check_mismatches_impl(ra_fixture: &str, allow_none: bool) {
|
||||
fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_source: 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<DefWithBodyId> = 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,37 +120,59 @@ 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<SyntaxNode>, 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, mismatch) in inference_result.pat_type_mismatches() {
|
||||
let syntax_ptr = 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,
|
||||
|
||||
for (pat, ty) in inference_result.type_of_pat.iter() {
|
||||
let node = match pat_node(&body_source_map, pat, &db) {
|
||||
Some(value) => value,
|
||||
None => continue,
|
||||
};
|
||||
push_mismatch(syntax_ptr, mismatch.clone());
|
||||
let range = node.as_ref().original_file_range(&db);
|
||||
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 expr_node(&body_source_map, expr, &db) {
|
||||
Some(value) => value,
|
||||
None => continue,
|
||||
};
|
||||
let range = node.as_ref().original_file_range(&db);
|
||||
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 pat_node(&body_source_map, pat, &db) {
|
||||
Some(value) => value,
|
||||
None => continue,
|
||||
};
|
||||
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,45 +182,70 @@ 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,);
|
||||
}
|
||||
assert!(buf.is_empty(), "Unexpected type mismatches:\n{}", buf);
|
||||
|
||||
assert!(checked_one || allow_none, "no `//^` annotations found");
|
||||
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);
|
||||
}
|
||||
}
|
||||
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 {
|
||||
let file = db.parse(pos.file_id).ok().unwrap();
|
||||
let expr = algo::find_node_at_range::<ast::Expr>(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();
|
||||
fn expr_node(
|
||||
body_source_map: &BodySourceMap,
|
||||
expr: ExprId,
|
||||
db: &TestDB,
|
||||
) -> Option<InFile<SyntaxNode>> {
|
||||
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,
|
||||
})
|
||||
}
|
||||
|
||||
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 pat_node(
|
||||
body_source_map: &BodySourceMap,
|
||||
pat: PatId,
|
||||
db: &TestDB,
|
||||
) -> Option<InFile<SyntaxNode>> {
|
||||
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 {
|
||||
|
|
|
@ -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<T> { 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<U>() -> *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]) -> 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<u8>(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,83 +77,39 @@ fn foo3<T>(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<u8>(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<u8>(C<[u8]>) -> C<[u8]>
|
||||
519..526 'foo3(c)': C<[u8]>
|
||||
524..525 'c': C<[u8; 2]>
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn infer_if_coerce() {
|
||||
check_infer(
|
||||
r#"
|
||||
//- minicore: unsize
|
||||
fn foo<T>(x: &[T]) -> &[T] { loop {} }
|
||||
fn test() {
|
||||
let x = if true {
|
||||
foo(&[1])
|
||||
} else {
|
||||
&[1]
|
||||
};
|
||||
}
|
||||
"#,
|
||||
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]) -> &[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_coerce() {
|
||||
check_no_mismatches(
|
||||
r#"
|
||||
//- minicore: coerce_unsized
|
||||
fn foo<T>(x: &[T]) -> &[T] { loop {} }
|
||||
fn foo<T>(x: &[T]) -> &[T] { x }
|
||||
fn test() {
|
||||
let x = if true {
|
||||
foo(&[1])
|
||||
} else {
|
||||
&[1]
|
||||
};
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn if_else_coerce() {
|
||||
check_no_mismatches(
|
||||
r#"
|
||||
//- minicore: coerce_unsized
|
||||
fn foo<T>(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]) -> &[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<T>(x: &[T]) -> &[T] { loop {} }
|
||||
//- minicore: coerce_unsized
|
||||
fn foo<T>(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]) -> &[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<T>(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]) -> &[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<T>(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) -> 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: T }
|
||||
impl<TT> S<TT> {
|
||||
fn get(&self) -> &TT {
|
||||
&self.t
|
||||
}
|
||||
}
|
||||
",
|
||||
expect![[r"
|
||||
50..54 'self': &S<TT>
|
||||
63..86 '{ ... }': &TT
|
||||
73..80 '&self.t': &TT
|
||||
74..78 'self': &S<TT>
|
||||
74..80 'self.t': TT
|
||||
"]],
|
||||
struct S<T> { t: T }
|
||||
impl<TT> S<TT> {
|
||||
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<T, U> {}
|
||||
|
@ -662,88 +332,18 @@ impl<T, X> Baz<T, X> for S<T, X> {}
|
|||
|
||||
fn test() {
|
||||
let obj: &dyn Baz<i8, i16> = &S;
|
||||
//^ S<i8, i16>
|
||||
let obj: &dyn Bar<_, i8, i16> = &S;
|
||||
//^ S<i8, i16>
|
||||
let obj: &dyn Foo<i8, _> = &S;
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
236..351 '{ ... &S; }': ()
|
||||
246..249 'obj': &dyn Baz<i8, i16>
|
||||
271..273 '&S': &S<i8, i16>
|
||||
272..273 'S': S<i8, i16>
|
||||
283..286 'obj': &dyn Bar<usize, i8, i16>
|
||||
311..313 '&S': &S<i8, i16>
|
||||
312..313 'S': S<i8, i16>
|
||||
323..326 'obj': &dyn Foo<i8, usize>
|
||||
346..348 '&S': &S<i8, {unknown}>
|
||||
347..348 'S': S<i8, {unknown}>
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[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<i8, i16>
|
||||
// 459..461 '&S': &S<i8, i16>
|
||||
// 460..461 'S': S<i8, i16>
|
||||
// 471..474 'obj': &dyn Bar<usize, i8, i16>
|
||||
// 496..499 'obj': &dyn Baz<i8, i16>
|
||||
// 509..512 'obj': &dyn Foo<i8, usize>
|
||||
// 531..534 'obj': &dyn Bar<usize, i8, i16>
|
||||
// 544..548 'obj2': &dyn Baz<i8, i16>
|
||||
// 570..572 '&S': &S<i8, i16>
|
||||
// 571..572 'S': S<i8, i16>
|
||||
// 582..583 '_': &dyn Foo<i8, usize>
|
||||
// 602..606 'obj2': &dyn Baz<i8, i16>
|
||||
check_infer_with_mismatches(
|
||||
r#"
|
||||
//- minicore: coerce_unsized
|
||||
trait Foo<T, U> {}
|
||||
trait Bar<U, T, X>: Foo<T, U> {}
|
||||
trait Baz<T, X>: Bar<usize, T, X> {}
|
||||
|
||||
struct S<T, X>;
|
||||
impl<T, X> Foo<T, usize> for S<T, X> {}
|
||||
impl<T, X> Bar<usize, T, X> for S<T, X> {}
|
||||
impl<T, X> Baz<T, X> for S<T, X> {}
|
||||
|
||||
fn test() {
|
||||
let obj: &dyn Baz<i8, i16> = &S;
|
||||
let obj: &dyn Bar<_, _, _> = obj;
|
||||
let obj: &dyn Foo<_, _> = obj;
|
||||
let obj2: &dyn Baz<i8, i16> = &S;
|
||||
let _: &dyn Foo<_, _> = obj2;
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
236..421 '{ ...bj2; }': ()
|
||||
246..249 'obj': &dyn Baz<i8, i16>
|
||||
271..273 '&S': &S<i8, i16>
|
||||
272..273 'S': S<i8, i16>
|
||||
283..286 'obj': &dyn Bar<{unknown}, {unknown}, {unknown}>
|
||||
308..311 'obj': &dyn Baz<i8, i16>
|
||||
321..324 'obj': &dyn Foo<{unknown}, {unknown}>
|
||||
343..346 'obj': &dyn Bar<{unknown}, {unknown}, {unknown}>
|
||||
356..360 'obj2': &dyn Baz<i8, i16>
|
||||
382..384 '&S': &S<i8, i16>
|
||||
383..384 'S': S<i8, i16>
|
||||
394..395 '_': &dyn Foo<{unknown}, {unknown}>
|
||||
414..418 'obj2': &dyn Baz<i8, i16>
|
||||
308..311: expected &dyn Bar<{unknown}, {unknown}, {unknown}>, got &dyn Baz<i8, i16>
|
||||
343..346: expected &dyn Foo<{unknown}, {unknown}>, got &dyn Bar<{unknown}, {unknown}, {unknown}>
|
||||
414..418: expected &dyn Foo<{unknown}, {unknown}>, got &dyn Baz<i8, i16>
|
||||
"#]],
|
||||
//^ S<i8, {unknown}>
|
||||
}"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[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: T };
|
||||
|
@ -785,73 +376,47 @@ struct Bar<T>(Foo<T>);
|
|||
|
||||
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) {
|
||||
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
|
||||
}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn infer_match_diverging_branch_1() {
|
||||
fn match_diverging_branch_1() {
|
||||
check_types(
|
||||
r#"
|
||||
enum Result<T> { 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#"
|
||||
|
|
|
@ -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 = u8> { t: T }
|
|||
fn main() {
|
||||
let foo = Foo { t: 5u8 };
|
||||
foo;
|
||||
} //^ Foo
|
||||
} //^^^ Foo
|
||||
"#,
|
||||
);
|
||||
|
||||
|
@ -35,7 +35,7 @@ struct Foo<K, T = u8> { k: K, t: T }
|
|||
fn main() {
|
||||
let foo = Foo { k: 400, t: 5u8 };
|
||||
foo;
|
||||
} //^ Foo<i32>
|
||||
} //^^^ Foo<i32>
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -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)
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
@ -853,7 +853,7 @@ include!("foo.rs");
|
|||
|
||||
fn main() {
|
||||
RegisterBlock { };
|
||||
//^ RegisterBlock
|
||||
//^^^^^^^^^^^^^^^^^ RegisterBlock
|
||||
}
|
||||
"#;
|
||||
let fixture = format!("{}\n//- /foo.rs\n{}", fixture, data);
|
||||
|
@ -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>(T);
|
||||
struct NonClone;
|
||||
fn test() {
|
||||
(Wrapper(S).clone(), Wrapper(NonClone).clone());
|
||||
let x = (Wrapper(S).clone(), Wrapper(NonClone).clone());
|
||||
x;
|
||||
//^ (Wrapper<S>, {unknown})
|
||||
}
|
||||
|
||||
|
@ -1079,7 +1080,7 @@ struct S{}
|
|||
|
||||
fn test() {
|
||||
S{};
|
||||
} //^ S
|
||||
} //^^^ S
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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<T> {
|
||||
fn method(&self) -> T;
|
||||
}
|
||||
struct S;
|
||||
impl Trait<u32> for S {}
|
||||
fn test() {
|
||||
S.method();
|
||||
}
|
||||
trait Trait<T> {
|
||||
fn method(&self) -> T;
|
||||
}
|
||||
struct S;
|
||||
impl Trait<u32> 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<T1, T2, T3> {
|
||||
fn method1(&self) -> (T1, T2, T3);
|
||||
fn method2(&self) -> (T3, T2, T1);
|
||||
}
|
||||
struct S1;
|
||||
impl Trait<u8, u16, u32> for S1 {}
|
||||
struct S2;
|
||||
impl<T> Trait<i8, i16, T> 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<T1, T2, T3> {
|
||||
fn method1(&self) -> (T1, T2, T3);
|
||||
fn method2(&self) -> (T3, T2, T1);
|
||||
}
|
||||
struct S1;
|
||||
impl Trait<u8, u16, u32> for S1 {}
|
||||
struct S2;
|
||||
impl<T> Trait<i8, i16, T> 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<T> {
|
||||
fn method(&self) -> T;
|
||||
}
|
||||
struct S<T>(T);
|
||||
impl<U> Trait<U> for S<U> {}
|
||||
fn test() {
|
||||
S(1u32).method();
|
||||
}
|
||||
trait Trait<T> {
|
||||
fn method(&self) -> T;
|
||||
}
|
||||
struct S<T>(T);
|
||||
impl<U> Trait<U> for S<U> {}
|
||||
fn test() {
|
||||
S(1u32).method();
|
||||
//^^^^^^^^^^^^^^^^ u32
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
32..36 'self': &Self
|
||||
101..126 '{ ...d(); }': ()
|
||||
107..108 'S': S<u32>(u32) -> S<u32>
|
||||
107..114 'S(1u32)': S<u32>
|
||||
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<T>;
|
||||
impl S<u32> { fn foo(&self) -> u8 {} }
|
||||
impl S<i32> { fn foo(&self) -> i8 {} }
|
||||
impl S<u32> { fn foo(&self) -> u8 { 0 } }
|
||||
impl S<i32> { fn foo(&self) -> i8 { 0 } }
|
||||
fn test() { (S::<u32>.foo(), S::<i32>.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<T> 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<T> 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<T: Clone> Trait for T {}
|
||||
fn test() { (&S).foo(); }
|
||||
//^ {unknown}
|
||||
//^^^^^^^^^^ {unknown}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -871,7 +835,7 @@ struct S;
|
|||
impl Clone for S {}
|
||||
impl<T> Trait for T where T: Clone {}
|
||||
fn test() { S.foo(); }
|
||||
//^ u128
|
||||
//^^^^^^^ u128
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -887,7 +851,7 @@ struct S2;
|
|||
impl From<S2> for S1 {}
|
||||
impl<T, U> Into<U> for T where U: From<T> {}
|
||||
fn test() { S2.into(); }
|
||||
//^ {unknown}
|
||||
//^^^^^^^^^ {unknown}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -903,7 +867,7 @@ struct S2;
|
|||
impl From<S2> for S1 {}
|
||||
impl<T, U: From<T>> Into<U> for T {}
|
||||
fn test() { S2.into(); }
|
||||
//^ {unknown}
|
||||
//^^^^^^^^^ {unknown}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -933,7 +897,7 @@ fn main() {
|
|||
let a = Wrapper::<Foo<f32>>::new(1.0);
|
||||
let b = Wrapper::<Bar<f32>>::new(1.0);
|
||||
(a, b);
|
||||
//^ (Wrapper<Foo<f32>>, Wrapper<Bar<f32>>)
|
||||
//^^^^^^ (Wrapper<Foo<f32>>, Wrapper<Bar<f32>>)
|
||||
}
|
||||
"#,
|
||||
);
|
||||
|
@ -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<T>: a::Foo,
|
||||
{
|
||||
t.foo();
|
||||
} //^ {unknown}
|
||||
} //^^^^^^^ {unknown}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -1030,7 +994,7 @@ impl A<i32> {
|
|||
|
||||
fn main() {
|
||||
A::from(3);
|
||||
} //^ A<i32>
|
||||
} //^^^^^^^^^^ A<i32>
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -1058,7 +1022,7 @@ trait FnX {}
|
|||
impl<B, C> Trait for S<B, C> where C: FnX, B: SendX {}
|
||||
|
||||
fn test() { (S {}).method(); }
|
||||
//^ ()
|
||||
//^^^^^^^^^^^^^^^ ()
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -1143,8 +1107,8 @@ impl<T> Slice<T> {
|
|||
|
||||
fn main() {
|
||||
let foo: Slice<u32>;
|
||||
(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<T> 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 {} }
|
||||
}
|
||||
"#,
|
||||
);
|
||||
|
|
|
@ -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<T> { None }
|
||||
use Option::None;
|
||||
|
|
|
@ -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<char> {}
|
||||
fn next(&mut self) -> Option<char> { loop {} }
|
||||
}
|
||||
|
||||
fn test() {
|
||||
let chars: Chars<'_>;
|
||||
(chars.next(), chars.nth(1));
|
||||
} //^ (Option<char>, Option<char>)
|
||||
} //^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (Option<char>, Option<char>)
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[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<Item = &'a T> {
|
|||
|
||||
fn clone_iter<T>(s: Iter<T>) {
|
||||
s.inner.clone_box();
|
||||
//^^^^^^^^^^^^^^^^^^^ ()
|
||||
//^^^^^^^^^^^^^^^^^^^ ()
|
||||
}
|
||||
"#,
|
||||
)
|
||||
|
|
|
@ -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<T> { Some(T), None }
|
|||
fn test() {
|
||||
let foo: Option<f32> = 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
|
||||
|
|
|
@ -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<T> {}
|
||||
struct S<T>(T);
|
||||
|
@ -293,99 +294,62 @@ impl<U> Trait<U> for S<U> {}
|
|||
fn foo<T: Trait<u32>>(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<u32>
|
||||
118..119 'S': S<u32>(u32) -> S<u32>
|
||||
118..128 'S(unknown)': S<u32>
|
||||
120..127 'unknown': u32
|
||||
134..137 'foo': fn foo<S<u32>>(S<u32>)
|
||||
134..140 'foo(s)': ()
|
||||
138..139 's': S<u32>
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn infer_from_bound_2() {
|
||||
check_infer(
|
||||
check_types(
|
||||
r#"
|
||||
trait Trait<T> {}
|
||||
struct S<T>(T);
|
||||
impl<U> Trait<U> for S<U> {}
|
||||
fn foo<U, T: Trait<U>>(t: T) -> U {}
|
||||
fn foo<U, T: Trait<U>>(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<u32>
|
||||
124..125 'S': S<u32>(u32) -> S<u32>
|
||||
124..134 'S(unknown)': S<u32>
|
||||
126..133 'unknown': u32
|
||||
144..145 'x': u32
|
||||
153..156 'foo': fn foo<u32, S<u32>>(S<u32>) -> u32
|
||||
153..159 'foo(s)': u32
|
||||
157..158 's': S<u32>
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[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<T: Iterable>() {
|
||||
let x: <S as Iterable>::Item = 1;
|
||||
let y: <T as Iterable>::Item = no_matter;
|
||||
let z: T::Item = no_matter;
|
||||
let a: <T>::Item = no_matter;
|
||||
// ^ u32
|
||||
let y: <T as Iterable>::Item = u;
|
||||
// ^ Iterable::Item<T>
|
||||
let z: T::Item = u;
|
||||
// ^ Iterable::Item<T>
|
||||
let a: <T>::Item = u;
|
||||
// ^ Iterable::Item<T>
|
||||
}"#,
|
||||
expect![[r#"
|
||||
108..261 '{ ...ter; }': ()
|
||||
118..119 'x': u32
|
||||
145..146 '1': u32
|
||||
156..157 'y': Iterable::Item<T>
|
||||
183..192 'no_matter': Iterable::Item<T>
|
||||
202..203 'z': Iterable::Item<T>
|
||||
215..224 'no_matter': Iterable::Item<T>
|
||||
234..235 'a': Iterable::Item<T>
|
||||
249..258 'no_matter': Iterable::Item<T>
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[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: Iterable>(t: T) -> T::Item {}
|
||||
fn foo2<T: Iterable>(t: T) -> <T as Iterable>::Item {}
|
||||
fn foo3<T: Iterable>(t: T) -> <T>::Item {}
|
||||
fn foo1<T: Iterable>(t: T) -> T::Item { loop {} }
|
||||
fn foo2<T: Iterable>(t: T) -> <T as Iterable>::Item { loop {} }
|
||||
fn foo3<T: Iterable>(t: 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>(S) -> <S as Iterable>::Item
|
||||
248..255 'foo1(S)': u32
|
||||
253..254 'S': S
|
||||
265..266 'y': u32
|
||||
269..273 'foo2': fn foo2<S>(S) -> <S as Iterable>::Item
|
||||
269..276 'foo2(S)': u32
|
||||
274..275 'S': S
|
||||
286..287 'z': u32
|
||||
290..294 'foo3': fn foo3<S>(S) -> <S as Iterable>::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<T: Iterable<Item=u32>>() {
|
||||
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<T> core::ops::Deref for Arc<T> {
|
|||
|
||||
struct S;
|
||||
impl S {
|
||||
fn foo(&self) -> u128 {}
|
||||
fn foo(&self) -> u128 { 0 }
|
||||
}
|
||||
|
||||
fn test(s: Arc<S>) {
|
||||
(*s, s.foo());
|
||||
} //^ (S, u128)
|
||||
} //^^^^^^^^^^^^^ (S, u128)
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -653,7 +590,7 @@ fn deref_trait_with_inference_var() {
|
|||
r#"
|
||||
//- minicore: deref
|
||||
struct Arc<T>;
|
||||
fn new_arc<T>() -> Arc<T> {}
|
||||
fn new_arc<T>() -> Arc<T> { Arc }
|
||||
impl<T> core::ops::Deref for Arc<T> {
|
||||
type Target = T;
|
||||
}
|
||||
|
@ -663,8 +600,8 @@ fn foo(a: Arc<S>) {}
|
|||
|
||||
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<T: ?Sized> core::ops::Deref for Arc<T> {
|
|||
|
||||
struct S;
|
||||
impl S {
|
||||
fn foo(&self) -> u128 {}
|
||||
fn foo(&self) -> u128 { 0 }
|
||||
}
|
||||
|
||||
fn test(s: Arc<S>) {
|
||||
(*s, s.foo());
|
||||
} //^ (S, u128)
|
||||
} //^^^^^^^^^^^^^ (S, u128)
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -720,11 +657,11 @@ struct S;
|
|||
trait Trait<T> {}
|
||||
impl Trait<u32> for S {}
|
||||
|
||||
fn foo<T: Trait<U>, U>(t: T) -> U {}
|
||||
fn foo<T: Trait<U>, U>(t: T) -> U { loop {} }
|
||||
|
||||
fn test(s: S) {
|
||||
(foo(s));
|
||||
} //^ u32
|
||||
foo(s);
|
||||
} //^^^^^^ u32
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -741,12 +678,12 @@ impl Trait<isize> for S {}
|
|||
|
||||
struct O;
|
||||
impl O {
|
||||
fn foo<T: Trait<U>, U>(&self, t: T) -> U {}
|
||||
fn foo<T: Trait<U>, U>(&self, t: T) -> U { loop {} }
|
||||
}
|
||||
|
||||
fn test() {
|
||||
O.foo(S);
|
||||
} //^ isize
|
||||
} //^^^^^^^^ isize
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -761,12 +698,12 @@ trait Trait<T> {}
|
|||
impl Trait<i64> for S {}
|
||||
|
||||
impl S {
|
||||
fn foo<U>(&self) -> U where Self: Trait<U> {}
|
||||
fn foo<U>(&self) -> U where Self: Trait<U> { loop {} }
|
||||
}
|
||||
|
||||
fn test() {
|
||||
S.foo();
|
||||
} //^ i64
|
||||
} //^^^^^^^ i64
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -782,12 +719,12 @@ impl Trait<&str> for S {}
|
|||
|
||||
struct O<T>;
|
||||
impl<U, T: Trait<U>> O<T> {
|
||||
fn foo(&self) -> U {}
|
||||
fn foo(&self) -> U { loop {} }
|
||||
}
|
||||
|
||||
fn test(o: O<S>) {
|
||||
o.foo();
|
||||
} //^ &str
|
||||
} //^^^^^^^ &str
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -802,7 +739,7 @@ struct S;
|
|||
impl Clone for S {}
|
||||
impl<T> Trait for T where T: Clone {}
|
||||
fn test<T: Clone>(t: T) { t.foo(); }
|
||||
//^ u128
|
||||
//^^^^^^^ u128
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -818,7 +755,7 @@ struct S;
|
|||
impl Clone for S {}
|
||||
impl<T> Trait for T where T: Clone {}
|
||||
fn test<T>(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: Trait>(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) { t.foo(); }
|
||||
//^ {unknown}
|
||||
//^^^^^^^ {unknown}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -858,8 +795,8 @@ trait Trait {}
|
|||
impl<T> core::ops::Deref for T where T: Trait {
|
||||
type Target = i128;
|
||||
}
|
||||
fn test<T: Trait>(t: T) { (*t); }
|
||||
//^ i128
|
||||
fn test<T: Trait>(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<T: foo::Trait>(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: FnOnce() -> U>(f: F) -> U { f() }
|
||||
|
||||
|
@ -2009,7 +1946,7 @@ trait Trait2 {
|
|||
fn test<T: Trait>() where T::Item: Trait2 {
|
||||
let x: T::Item = no_matter;
|
||||
x.foo();
|
||||
} //^ u32
|
||||
} //^^^^^^^ u32
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -2029,7 +1966,7 @@ trait Trait2 {
|
|||
fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, 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<I: Interner>(interner: &I, t: Ty<I>) {
|
||||
fold(interner, t);
|
||||
} //^ Ty<I>
|
||||
} //^^^^^^^^^^^^^^^^^ Ty<I>
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -2139,7 +2076,7 @@ impl Trait<Self> for S {}
|
|||
|
||||
fn test() {
|
||||
S.foo();
|
||||
} //^ ()
|
||||
} //^^^^^^^ ()
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -2158,7 +2095,7 @@ impl Trait for S<Self> {}
|
|||
|
||||
fn test() {
|
||||
S.foo();
|
||||
} //^ {unknown}
|
||||
} //^^^^^^^ {unknown}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -2176,7 +2113,7 @@ trait Trait2<T> {}
|
|||
|
||||
fn test<T: Trait>() where T: Trait2<T::Item> {
|
||||
let x: T::Item = no_matter;
|
||||
} //^ {unknown}
|
||||
} //^^^^^^^^^ {unknown}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -2193,7 +2130,7 @@ trait Trait<T> {
|
|||
|
||||
fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> {
|
||||
let x: T::Item = no_matter;
|
||||
} //^ {unknown}
|
||||
} //^^^^^^^^^ {unknown}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -2211,7 +2148,7 @@ trait Trait {
|
|||
|
||||
fn test<T>() where T: Trait<OtherItem = T::Item> {
|
||||
let x: T::Item = no_matter;
|
||||
} //^ Trait::Item<T>
|
||||
} //^^^^^^^^^ Trait::Item<T>
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -2243,7 +2180,7 @@ fn test<T>(t: T) where T: UnificationStoreMut {
|
|||
t.push(x);
|
||||
let y: Key<T>;
|
||||
(x, y);
|
||||
} //^ (UnificationStoreBase::Key<T>, UnificationStoreBase::Key<T>)
|
||||
} //^^^^^^ (UnificationStoreBase::Key<T>, UnificationStoreBase::Key<T>)
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -2268,7 +2205,7 @@ impl<T: Iterator> Iterator for S<T> {
|
|||
fn test<I: Iterator<Item: OtherTrait<u32>>>() {
|
||||
let x: <S<I> as Iterator>::Item;
|
||||
x.foo();
|
||||
} //^ u32
|
||||
} //^^^^^^^ u32
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -2470,7 +2407,7 @@ impl<T: Trait> Trait for S<T> {
|
|||
fn test<T: Trait>() {
|
||||
let y: <S<T> as Trait>::Item = no_matter;
|
||||
y.foo();
|
||||
} //^ u32
|
||||
} //^^^^^^^ u32
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -2490,7 +2427,7 @@ trait Trait {
|
|||
|
||||
fn test(x: Box<dyn Trait>) {
|
||||
x.foo();
|
||||
} //^ ()
|
||||
} //^^^^^^^ ()
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -2509,7 +2446,7 @@ impl ToOwned for str {
|
|||
}
|
||||
fn test() {
|
||||
"foo".to_owned();
|
||||
} //^ String
|
||||
} //^^^^^^^^^^^^^^^^ String
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -2649,7 +2586,7 @@ impl<T:A> 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<u32, ()> {
|
||||
let ret = Fooey.collect();
|
||||
// ^ u32
|
||||
// ^^^^^^^^^^^^^^^ u32
|
||||
Ok(ret)
|
||||
}
|
||||
"#,
|
||||
|
@ -3493,6 +3428,7 @@ async fn get_accounts() -> Result<u32, ()> {
|
|||
|
||||
#[test]
|
||||
fn local_impl_1() {
|
||||
check!(block_local_impls);
|
||||
check_types(
|
||||
r#"
|
||||
trait Trait<T> {
|
||||
|
@ -3502,7 +3438,7 @@ trait Trait<T> {
|
|||
fn test() {
|
||||
struct S;
|
||||
impl Trait<u32> 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<u32> 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<T> {
|
||||
|
@ -3547,7 +3485,7 @@ fn test() {
|
|||
struct S2;
|
||||
|
||||
impl Trait<S1> for S2 {
|
||||
fn foo(&self) { S1 }
|
||||
fn foo(&self) -> S1 { S1 }
|
||||
}
|
||||
|
||||
S2.foo();
|
||||
|
|
|
@ -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<TextSize> = 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<LineAnnotation> {
|
|||
}
|
||||
|
||||
#[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::<Vec<_>>();
|
||||
|
||||
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.
|
||||
|
|
Loading…
Reference in a new issue