mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-27 20:42:04 +00:00
Unify check_mismatches and check_types
This commit is contained in:
parent
679bb21633
commit
04fbdce426
9 changed files with 355 additions and 382 deletions
|
@ -86,16 +86,20 @@ impl FileLoader for TestDB {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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() {
|
for &krate in self.relevant_crates(file_id).iter() {
|
||||||
let crate_def_map = self.crate_def_map(krate);
|
let crate_def_map = self.crate_def_map(krate);
|
||||||
for (local_id, data) in crate_def_map.modules() {
|
for (local_id, data) in crate_def_map.modules() {
|
||||||
if data.origin.file_id() == Some(file_id) {
|
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)>> {
|
pub(crate) fn extract_annotations(&self) -> FxHashMap<FileId, Vec<(TextRange, String)>> {
|
||||||
|
|
|
@ -59,14 +59,16 @@ fn setup_tracing() -> Option<tracing::subscriber::DefaultGuard> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_types(ra_fixture: &str) {
|
fn check_types(ra_fixture: &str) {
|
||||||
check_types_impl(ra_fixture, false)
|
check_impl(ra_fixture, false, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_types_source_code(ra_fixture: &str) {
|
fn check_types_source_code(ra_fixture: &str) {
|
||||||
|
// TODO
|
||||||
check_types_impl(ra_fixture, true)
|
check_types_impl(ra_fixture, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_types_impl(ra_fixture: &str, display_source: bool) {
|
fn check_types_impl(ra_fixture: &str, display_source: bool) {
|
||||||
|
// TODO
|
||||||
let _tracing = setup_tracing();
|
let _tracing = setup_tracing();
|
||||||
let db = TestDB::with_files(ra_fixture);
|
let db = TestDB::with_files(ra_fixture);
|
||||||
let mut checked_one = false;
|
let mut checked_one = false;
|
||||||
|
@ -88,22 +90,47 @@ fn check_types_impl(ra_fixture: &str, display_source: bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_no_mismatches(ra_fixture: &str) {
|
fn check_no_mismatches(ra_fixture: &str) {
|
||||||
check_mismatches_impl(ra_fixture, true)
|
check_impl(ra_fixture, true, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
fn check(ra_fixture: &str) {
|
||||||
fn check_mismatches(ra_fixture: &str) {
|
check_impl(ra_fixture, false, false)
|
||||||
check_mismatches_impl(ra_fixture, false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_mismatches_impl(ra_fixture: &str, allow_none: bool) {
|
fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool) {
|
||||||
let _tracing = setup_tracing();
|
let _tracing = setup_tracing();
|
||||||
let (db, file_id) = TestDB::with_single_file(ra_fixture);
|
let (db, files) = TestDB::with_many_files(ra_fixture);
|
||||||
let module = db.module_for_file(file_id);
|
|
||||||
let def_map = module.def_map(&db);
|
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();
|
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 {
|
defs.sort_by_key(|def| match def {
|
||||||
DefWithBodyId::FunctionId(it) => {
|
DefWithBodyId::FunctionId(it) => {
|
||||||
let loc = it.lookup(&db);
|
let loc = it.lookup(&db);
|
||||||
|
@ -118,25 +145,13 @@ fn check_mismatches_impl(ra_fixture: &str, allow_none: bool) {
|
||||||
loc.source(&db).value.syntax().text_range().start()
|
loc.source(&db).value.syntax().text_range().start()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let mut mismatches = HashMap::new();
|
let mut unexpected_type_mismatches = String::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);
|
|
||||||
};
|
|
||||||
for def in defs {
|
for def in defs {
|
||||||
let (_body, body_source_map) = db.body_with_source_map(def);
|
let (_body, body_source_map) = db.body_with_source_map(def);
|
||||||
let inference_result = db.infer(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) {
|
for (pat, ty) in inference_result.type_of_pat.iter() {
|
||||||
|
let node = match body_source_map.pat_syntax(pat) {
|
||||||
Ok(sp) => {
|
Ok(sp) => {
|
||||||
let root = db.parse_or_expand(sp.file_id).unwrap();
|
let root = db.parse_or_expand(sp.file_id).unwrap();
|
||||||
sp.map(|ptr| {
|
sp.map(|ptr| {
|
||||||
|
@ -148,7 +163,50 @@ fn check_mismatches_impl(ra_fixture: &str, allow_none: bool) {
|
||||||
}
|
}
|
||||||
Err(SyntheticSyntax) => continue,
|
Err(SyntheticSyntax) => continue,
|
||||||
};
|
};
|
||||||
push_mismatch(syntax_ptr, mismatch.clone());
|
let range = node.as_ref().original_file_range(&db);
|
||||||
|
if let Some(annotation) = types.remove(&range) {
|
||||||
|
assert_eq!(ty.display_test(&db).to_string(), annotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (expr, ty) in inference_result.type_of_expr.iter() {
|
||||||
|
let node = match body_source_map.expr_syntax(expr) {
|
||||||
|
Ok(sp) => {
|
||||||
|
let root = db.parse_or_expand(sp.file_id).unwrap();
|
||||||
|
sp.map(|ptr| ptr.to_node(&root).syntax().clone())
|
||||||
|
}
|
||||||
|
Err(SyntheticSyntax) => continue,
|
||||||
|
};
|
||||||
|
let range = node.as_ref().original_file_range(&db);
|
||||||
|
if let Some(annotation) = types.remove(&range) {
|
||||||
|
assert_eq!(ty.display_test(&db).to_string(), annotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (pat, mismatch) in inference_result.pat_type_mismatches() {
|
||||||
|
let node = match body_source_map.pat_syntax(pat) {
|
||||||
|
Ok(sp) => {
|
||||||
|
let root = db.parse_or_expand(sp.file_id).unwrap();
|
||||||
|
sp.map(|ptr| {
|
||||||
|
ptr.either(
|
||||||
|
|it| it.to_node(&root).syntax().clone(),
|
||||||
|
|it| it.to_node(&root).syntax().clone(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Err(SyntheticSyntax) => continue,
|
||||||
|
};
|
||||||
|
let range = node.as_ref().original_file_range(&db);
|
||||||
|
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() {
|
for (expr, mismatch) in inference_result.expr_type_mismatches() {
|
||||||
let node = match body_source_map.expr_syntax(expr) {
|
let node = match body_source_map.expr_syntax(expr) {
|
||||||
|
@ -158,28 +216,37 @@ fn check_mismatches_impl(ra_fixture: &str, allow_none: bool) {
|
||||||
}
|
}
|
||||||
Err(SyntheticSyntax) => continue,
|
Err(SyntheticSyntax) => continue,
|
||||||
};
|
};
|
||||||
push_mismatch(node, mismatch.clone());
|
let range = node.as_ref().original_file_range(&db);
|
||||||
}
|
let actual = format!(
|
||||||
}
|
"expected {}, got {}",
|
||||||
let mut checked_one = false;
|
mismatch.expected.display_test(&db),
|
||||||
for (file_id, annotations) in db.extract_annotations() {
|
mismatch.actual.display_test(&db)
|
||||||
for (range, expected) in annotations {
|
);
|
||||||
let file_range = FileRange { file_id, range };
|
if let Some(annotation) = mismatches.remove(&range) {
|
||||||
if let Some(mismatch) = mismatches.remove(&file_range) {
|
assert_eq!(actual, annotation);
|
||||||
assert_eq!(mismatch, expected);
|
|
||||||
} else {
|
} 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 {
|
fn type_at_range(db: &TestDB, pos: FileRange) -> Ty {
|
||||||
|
|
|
@ -842,9 +842,9 @@ fn infer_two_closures_lub() {
|
||||||
fn foo(c: i32) {
|
fn foo(c: i32) {
|
||||||
let add = |a: i32, b: i32| a + b;
|
let add = |a: i32, b: i32| a + b;
|
||||||
let sub = |a, b| a - b;
|
let sub = |a, b| a - b;
|
||||||
//^ |i32, i32| -> i32
|
//^^^^^^^^^^^^ |i32, i32| -> i32
|
||||||
if c > 42 { add } else { sub };
|
if c > 42 { add } else { sub };
|
||||||
//^ fn(i32, i32) -> i32
|
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ fn(i32, i32) -> i32
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
)
|
)
|
||||||
|
|
|
@ -435,11 +435,11 @@ fn processes_impls_generated_by_macros() {
|
||||||
macro_rules! m {
|
macro_rules! m {
|
||||||
($ident:ident) => (impl Trait for $ident {})
|
($ident:ident) => (impl Trait for $ident {})
|
||||||
}
|
}
|
||||||
trait Trait { fn foo(self) -> u128 {} }
|
trait Trait { fn foo(self) -> u128 { 0 } }
|
||||||
struct S;
|
struct S;
|
||||||
m!(S);
|
m!(S);
|
||||||
fn test() { S.foo(); }
|
fn test() { S.foo(); }
|
||||||
//^ u128
|
//^^^^^^^ u128
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -457,7 +457,7 @@ impl S {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test() { S.foo(); }
|
fn test() { S.foo(); }
|
||||||
//^ u128
|
//^^^^^^^ u128
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -479,7 +479,7 @@ impl S {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test() { S.foo(); }
|
fn test() { S.foo(); }
|
||||||
//^ u128
|
//^^^^^^^ u128
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -743,7 +743,7 @@ include!("foo.rs");
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
bar();
|
bar();
|
||||||
} //^ u32
|
} //^^^^^ u32
|
||||||
|
|
||||||
//- /foo.rs
|
//- /foo.rs
|
||||||
fn bar() -> u32 {0}
|
fn bar() -> u32 {0}
|
||||||
|
@ -781,7 +781,7 @@ include!("f/foo.rs");
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
bar::bar();
|
bar::bar();
|
||||||
} //^ u32
|
} //^^^^^^^^^^ u32
|
||||||
|
|
||||||
//- /f/foo.rs
|
//- /f/foo.rs
|
||||||
pub mod bar;
|
pub mod bar;
|
||||||
|
@ -879,7 +879,7 @@ include!(concat!("f", "oo.rs"));
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
bar();
|
bar();
|
||||||
} //^ u32
|
} //^^^^^ u32
|
||||||
|
|
||||||
//- /foo.rs
|
//- /foo.rs
|
||||||
fn bar() -> u32 {0}
|
fn bar() -> u32 {0}
|
||||||
|
@ -905,7 +905,7 @@ include!(concat!(env!("OUT_DIR"), "/foo.rs"));
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
bar();
|
bar();
|
||||||
} //^ {unknown}
|
} //^^^^^ {unknown}
|
||||||
|
|
||||||
//- /foo.rs
|
//- /foo.rs
|
||||||
fn bar() -> u32 {0}
|
fn bar() -> u32 {0}
|
||||||
|
@ -923,7 +923,7 @@ macro_rules! include {() => {}}
|
||||||
include!("main.rs");
|
include!("main.rs");
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
0
|
0;
|
||||||
} //^ i32
|
} //^ i32
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
|
@ -979,7 +979,7 @@ fn infer_derive_clone_simple() {
|
||||||
struct S;
|
struct S;
|
||||||
fn test() {
|
fn test() {
|
||||||
S.clone();
|
S.clone();
|
||||||
} //^ S
|
} //^^^^^^^^^ S
|
||||||
|
|
||||||
//- /lib.rs crate:core
|
//- /lib.rs crate:core
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
|
@ -1028,7 +1028,7 @@ pub struct S;
|
||||||
use core::S;
|
use core::S;
|
||||||
fn test() {
|
fn test() {
|
||||||
S.clone();
|
S.clone();
|
||||||
} //^ S
|
} //^^^^^^^^^ S
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1044,7 +1044,8 @@ struct S;
|
||||||
struct Wrapper<T>(T);
|
struct Wrapper<T>(T);
|
||||||
struct NonClone;
|
struct NonClone;
|
||||||
fn test() {
|
fn test() {
|
||||||
(Wrapper(S).clone(), Wrapper(NonClone).clone());
|
let x = (Wrapper(S).clone(), Wrapper(NonClone).clone());
|
||||||
|
x;
|
||||||
//^ (Wrapper<S>, {unknown})
|
//^ (Wrapper<S>, {unknown})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1079,7 +1080,7 @@ struct S{}
|
||||||
|
|
||||||
fn test() {
|
fn test() {
|
||||||
S{};
|
S{};
|
||||||
} //^ S
|
} //^^^ S
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -257,7 +257,7 @@ fn test() {
|
||||||
mod foo {
|
mod foo {
|
||||||
struct S;
|
struct S;
|
||||||
impl S {
|
impl S {
|
||||||
fn thing() -> i128 {}
|
fn thing() -> i128 { 0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
|
@ -267,164 +267,128 @@ mod foo {
|
||||||
#[test]
|
#[test]
|
||||||
fn infer_trait_method_simple() {
|
fn infer_trait_method_simple() {
|
||||||
// the trait implementation is intentionally incomplete -- it shouldn't matter
|
// the trait implementation is intentionally incomplete -- it shouldn't matter
|
||||||
check_infer(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
trait Trait1 {
|
trait Trait1 {
|
||||||
fn method(&self) -> u32;
|
fn method(&self) -> u32;
|
||||||
}
|
}
|
||||||
struct S1;
|
struct S1;
|
||||||
impl Trait1 for S1 {}
|
impl Trait1 for S1 {}
|
||||||
trait Trait2 {
|
trait Trait2 {
|
||||||
fn method(&self) -> i128;
|
fn method(&self) -> i128;
|
||||||
}
|
}
|
||||||
struct S2;
|
struct S2;
|
||||||
impl Trait2 for S2 {}
|
impl Trait2 for S2 {}
|
||||||
fn test() {
|
fn test() {
|
||||||
S1.method(); // -> u32
|
S1.method();
|
||||||
S2.method(); // -> i128
|
//^^^^^^^^^^^ 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]
|
#[test]
|
||||||
fn infer_trait_method_scoped() {
|
fn infer_trait_method_scoped() {
|
||||||
// the trait implementation is intentionally incomplete -- it shouldn't matter
|
// the trait implementation is intentionally incomplete -- it shouldn't matter
|
||||||
check_infer(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
struct S;
|
struct S;
|
||||||
mod foo {
|
mod foo {
|
||||||
pub trait Trait1 {
|
pub trait Trait1 {
|
||||||
fn method(&self) -> u32;
|
fn method(&self) -> u32;
|
||||||
}
|
}
|
||||||
impl Trait1 for super::S {}
|
impl Trait1 for super::S {}
|
||||||
}
|
}
|
||||||
mod bar {
|
mod bar {
|
||||||
pub trait Trait2 {
|
pub trait Trait2 {
|
||||||
fn method(&self) -> i128;
|
fn method(&self) -> i128;
|
||||||
}
|
}
|
||||||
impl Trait2 for super::S {}
|
impl Trait2 for super::S {}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod foo_test {
|
mod foo_test {
|
||||||
use super::S;
|
use super::S;
|
||||||
use super::foo::Trait1;
|
use super::foo::Trait1;
|
||||||
fn test() {
|
fn test() {
|
||||||
S.method(); // -> u32
|
S.method();
|
||||||
}
|
//^^^^^^^^^^ u32
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mod bar_test {
|
mod bar_test {
|
||||||
use super::S;
|
use super::S;
|
||||||
use super::bar::Trait2;
|
use super::bar::Trait2;
|
||||||
fn test() {
|
fn test() {
|
||||||
S.method(); // -> i128
|
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]
|
#[test]
|
||||||
fn infer_trait_method_generic_1() {
|
fn infer_trait_method_generic_1() {
|
||||||
// the trait implementation is intentionally incomplete -- it shouldn't matter
|
// the trait implementation is intentionally incomplete -- it shouldn't matter
|
||||||
check_infer(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
trait Trait<T> {
|
trait Trait<T> {
|
||||||
fn method(&self) -> T;
|
fn method(&self) -> T;
|
||||||
}
|
}
|
||||||
struct S;
|
struct S;
|
||||||
impl Trait<u32> for S {}
|
impl Trait<u32> for S {}
|
||||||
fn test() {
|
fn test() {
|
||||||
S.method();
|
S.method();
|
||||||
}
|
//^^^^^^^^^^ u32
|
||||||
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
|
||||||
32..36 'self': &Self
|
|
||||||
91..110 '{ ...d(); }': ()
|
|
||||||
97..98 'S': S
|
|
||||||
97..107 'S.method()': u32
|
|
||||||
"#]],
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn infer_trait_method_generic_more_params() {
|
fn infer_trait_method_generic_more_params() {
|
||||||
// the trait implementation is intentionally incomplete -- it shouldn't matter
|
// the trait implementation is intentionally incomplete -- it shouldn't matter
|
||||||
check_infer(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
trait Trait<T1, T2, T3> {
|
trait Trait<T1, T2, T3> {
|
||||||
fn method1(&self) -> (T1, T2, T3);
|
fn method1(&self) -> (T1, T2, T3);
|
||||||
fn method2(&self) -> (T3, T2, T1);
|
fn method2(&self) -> (T3, T2, T1);
|
||||||
}
|
}
|
||||||
struct S1;
|
struct S1;
|
||||||
impl Trait<u8, u16, u32> for S1 {}
|
impl Trait<u8, u16, u32> for S1 {}
|
||||||
struct S2;
|
struct S2;
|
||||||
impl<T> Trait<i8, i16, T> for S2 {}
|
impl<T> Trait<i8, i16, T> for S2 {}
|
||||||
fn test() {
|
fn test() {
|
||||||
S1.method1(); // u8, u16, u32
|
S1.method1();
|
||||||
S1.method2(); // u32, u16, u8
|
//^^^^^^^^^^^^ (u8, u16, u32)
|
||||||
S2.method1(); // i8, i16, {unknown}
|
S1.method2();
|
||||||
S2.method2(); // {unknown}, i16, i8
|
//^^^^^^^^^^^^ (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]
|
#[test]
|
||||||
fn infer_trait_method_generic_2() {
|
fn infer_trait_method_generic_2() {
|
||||||
// the trait implementation is intentionally incomplete -- it shouldn't matter
|
// the trait implementation is intentionally incomplete -- it shouldn't matter
|
||||||
check_infer(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
trait Trait<T> {
|
trait Trait<T> {
|
||||||
fn method(&self) -> T;
|
fn method(&self) -> T;
|
||||||
}
|
}
|
||||||
struct S<T>(T);
|
struct S<T>(T);
|
||||||
impl<U> Trait<U> for S<U> {}
|
impl<U> Trait<U> for S<U> {}
|
||||||
fn test() {
|
fn test() {
|
||||||
S(1u32).method();
|
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(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
struct S<T>;
|
struct S<T>;
|
||||||
impl S<u32> { fn foo(&self) -> u8 {} }
|
impl S<u32> { fn foo(&self) -> u8 { 0 } }
|
||||||
impl S<i32> { fn foo(&self) -> i8 {} }
|
impl S<i32> { fn foo(&self) -> i8 { 0 } }
|
||||||
fn test() { (S::<u32>.foo(), S::<i32>.foo()); }
|
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 S { fn foo(&self) -> i8 { 0 } }
|
||||||
impl Trait for S { fn foo(self) -> u128 { 0 } }
|
impl Trait for S { fn foo(self) -> u128 { 0 } }
|
||||||
fn test() { S.foo(); }
|
fn test() { S.foo(); }
|
||||||
//^ u128
|
//^^^^^^^ u128
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -716,7 +680,7 @@ struct S;
|
||||||
impl Clone for S {}
|
impl Clone for S {}
|
||||||
impl Clone for &S {}
|
impl Clone for &S {}
|
||||||
fn test() { (S.clone(), (&S).clone(), (&&S).clone()); }
|
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 S { fn foo(self) -> i8 { 0 } }
|
||||||
impl Trait for &S { fn foo(self) -> u128 { 0 } }
|
impl Trait for &S { fn foo(self) -> u128 { 0 } }
|
||||||
fn test() { (&S).foo(); }
|
fn test() { (&S).foo(); }
|
||||||
//^ u128
|
//^^^^^^^^^^ u128
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -744,7 +708,7 @@ struct S;
|
||||||
impl S { fn foo(self) -> i8 { 0 } }
|
impl S { fn foo(self) -> i8 { 0 } }
|
||||||
impl Trait for S { fn foo(self) -> u128 { 0 } }
|
impl Trait for S { fn foo(self) -> u128 { 0 } }
|
||||||
fn test() { S.foo(); }
|
fn test() { S.foo(); }
|
||||||
//^ i8
|
//^^^^^^^ i8
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -758,7 +722,7 @@ struct S;
|
||||||
impl S { fn foo(&self) -> i8 { 0 } }
|
impl S { fn foo(&self) -> i8 { 0 } }
|
||||||
impl Trait for &S { fn foo(self) -> u128 { 0 } }
|
impl Trait for &S { fn foo(self) -> u128 { 0 } }
|
||||||
fn test() { S.foo(); }
|
fn test() { S.foo(); }
|
||||||
//^ i8
|
//^^^^^^^ i8
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -771,7 +735,7 @@ trait Trait { fn foo(self) -> u128; }
|
||||||
struct S;
|
struct S;
|
||||||
impl Trait for S { fn foo(self) -> u128 { 0 } }
|
impl Trait for S { fn foo(self) -> u128 { 0 } }
|
||||||
fn test() { (&S).foo(); }
|
fn test() { (&S).foo(); }
|
||||||
//^ u128
|
//^^^^^^^^^^ u128
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -784,7 +748,7 @@ fn method_resolution_unsize_array() {
|
||||||
fn test() {
|
fn test() {
|
||||||
let a = [1, 2, 3];
|
let a = [1, 2, 3];
|
||||||
a.len();
|
a.len();
|
||||||
} //^ usize
|
} //^^^^^^^ usize
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -799,7 +763,7 @@ impl Clone for S {}
|
||||||
|
|
||||||
fn test() {
|
fn test() {
|
||||||
S.clone();
|
S.clone();
|
||||||
//^ S
|
//^^^^^^^^^ S
|
||||||
}
|
}
|
||||||
|
|
||||||
//- /lib.rs crate:core
|
//- /lib.rs crate:core
|
||||||
|
@ -823,7 +787,7 @@ trait Trait { fn foo(self) -> u128; }
|
||||||
struct S;
|
struct S;
|
||||||
impl<T> Trait for T where T: UnknownTrait {}
|
impl<T> Trait for T where T: UnknownTrait {}
|
||||||
fn test() { (&S).foo(); }
|
fn test() { (&S).foo(); }
|
||||||
//^ u128
|
//^^^^^^^^^^ u128
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -841,7 +805,7 @@ trait Trait { fn foo(self) -> u128; }
|
||||||
struct S;
|
struct S;
|
||||||
impl<T> Trait for T where T: Clone {}
|
impl<T> Trait for T where T: Clone {}
|
||||||
fn test() { (&S).foo(); }
|
fn test() { (&S).foo(); }
|
||||||
//^ {unknown}
|
//^^^^^^^^^^ {unknown}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -856,7 +820,7 @@ trait Trait { fn foo(self) -> u128; }
|
||||||
struct S;
|
struct S;
|
||||||
impl<T: Clone> Trait for T {}
|
impl<T: Clone> Trait for T {}
|
||||||
fn test() { (&S).foo(); }
|
fn test() { (&S).foo(); }
|
||||||
//^ {unknown}
|
//^^^^^^^^^^ {unknown}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -871,7 +835,7 @@ struct S;
|
||||||
impl Clone for S {}
|
impl Clone for S {}
|
||||||
impl<T> Trait for T where T: Clone {}
|
impl<T> Trait for T where T: Clone {}
|
||||||
fn test() { S.foo(); }
|
fn test() { S.foo(); }
|
||||||
//^ u128
|
//^^^^^^^ u128
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -887,7 +851,7 @@ struct S2;
|
||||||
impl From<S2> for S1 {}
|
impl From<S2> for S1 {}
|
||||||
impl<T, U> Into<U> for T where U: From<T> {}
|
impl<T, U> Into<U> for T where U: From<T> {}
|
||||||
fn test() { S2.into(); }
|
fn test() { S2.into(); }
|
||||||
//^ {unknown}
|
//^^^^^^^^^ {unknown}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -903,7 +867,7 @@ struct S2;
|
||||||
impl From<S2> for S1 {}
|
impl From<S2> for S1 {}
|
||||||
impl<T, U: From<T>> Into<U> for T {}
|
impl<T, U: From<T>> Into<U> for T {}
|
||||||
fn test() { S2.into(); }
|
fn test() { S2.into(); }
|
||||||
//^ {unknown}
|
//^^^^^^^^^ {unknown}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -933,7 +897,7 @@ fn main() {
|
||||||
let a = Wrapper::<Foo<f32>>::new(1.0);
|
let a = Wrapper::<Foo<f32>>::new(1.0);
|
||||||
let b = Wrapper::<Bar<f32>>::new(1.0);
|
let b = Wrapper::<Bar<f32>>::new(1.0);
|
||||||
(a, b);
|
(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() {}
|
fn foo() {}
|
||||||
trait FnOnce { fn call(self); }
|
trait FnOnce { fn call(self); }
|
||||||
fn test() { foo.call(); }
|
fn test() { foo.call(); }
|
||||||
//^ {unknown}
|
//^^^^^^^^^^ {unknown}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1013,7 +977,7 @@ where
|
||||||
Wrapper<T>: a::Foo,
|
Wrapper<T>: a::Foo,
|
||||||
{
|
{
|
||||||
t.foo();
|
t.foo();
|
||||||
} //^ {unknown}
|
} //^^^^^^^ {unknown}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1030,7 +994,7 @@ impl A<i32> {
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
A::from(3);
|
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 {}
|
impl<B, C> Trait for S<B, C> where C: FnX, B: SendX {}
|
||||||
|
|
||||||
fn test() { (S {}).method(); }
|
fn test() { (S {}).method(); }
|
||||||
//^ ()
|
//^^^^^^^^^^^^^^^ ()
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1143,8 +1107,8 @@ impl<T> Slice<T> {
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let foo: Slice<u32>;
|
let foo: Slice<u32>;
|
||||||
(foo.into_vec()); // we don't actually support arbitrary self types, but we shouldn't crash at least
|
foo.into_vec(); // we shouldn't crash on this at least
|
||||||
} //^ {unknown}
|
} //^^^^^^^^^^^^^^ {unknown}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1165,7 +1129,7 @@ impl dyn Foo + '_ {
|
||||||
fn main() {
|
fn main() {
|
||||||
let f = &42u32 as &dyn Foo;
|
let f = &42u32 as &dyn Foo;
|
||||||
f.dyn_foo();
|
f.dyn_foo();
|
||||||
// ^u32
|
// ^^^^^^^^^^^ u32
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
|
@ -1376,11 +1340,11 @@ pub trait IntoIterator {
|
||||||
|
|
||||||
impl<T> IntoIterator for [T; 1] {
|
impl<T> IntoIterator for [T; 1] {
|
||||||
type Out = T;
|
type Out = T;
|
||||||
fn into_iter(self) -> Self::Out {}
|
fn into_iter(self) -> Self::Out { loop {} }
|
||||||
}
|
}
|
||||||
impl<'a, T> IntoIterator for &'a [T] {
|
impl<'a, T> IntoIterator for &'a [T] {
|
||||||
type Out = &'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 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]
|
#[test]
|
||||||
fn infer_pattern() {
|
fn infer_pattern() {
|
||||||
|
@ -518,7 +518,7 @@ fn infer_generics_in_patterns() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn infer_const_pattern() {
|
fn infer_const_pattern() {
|
||||||
check_mismatches(
|
check(
|
||||||
r#"
|
r#"
|
||||||
enum Option<T> { None }
|
enum Option<T> { None }
|
||||||
use Option::None;
|
use Option::None;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use expect_test::expect;
|
use expect_test::expect;
|
||||||
|
|
||||||
use super::{check_infer, check_types};
|
use super::{check_infer, check_no_mismatches, check_types};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn bug_484() {
|
fn bug_484() {
|
||||||
|
@ -422,20 +422,20 @@ fn issue_2683_chars_impl() {
|
||||||
pub struct Chars<'a> {}
|
pub struct Chars<'a> {}
|
||||||
impl<'a> Iterator for Chars<'a> {
|
impl<'a> Iterator for Chars<'a> {
|
||||||
type Item = char;
|
type Item = char;
|
||||||
fn next(&mut self) -> Option<char> {}
|
fn next(&mut self) -> Option<char> { loop {} }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test() {
|
fn test() {
|
||||||
let chars: Chars<'_>;
|
let chars: Chars<'_>;
|
||||||
(chars.next(), chars.nth(1));
|
(chars.next(), chars.nth(1));
|
||||||
} //^ (Option<char>, Option<char>)
|
} //^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (Option<char>, Option<char>)
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn issue_3642_bad_macro_stackover() {
|
fn issue_3642_bad_macro_stackover() {
|
||||||
check_types(
|
check_no_mismatches(
|
||||||
r#"
|
r#"
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! match_ast {
|
macro_rules! match_ast {
|
||||||
|
@ -452,7 +452,6 @@ macro_rules! match_ast {
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let anchor = match_ast! {
|
let anchor = match_ast! {
|
||||||
//^ ()
|
|
||||||
match parent {
|
match parent {
|
||||||
as => {},
|
as => {},
|
||||||
_ => return None
|
_ => return None
|
||||||
|
@ -956,7 +955,7 @@ trait IterTrait<'a, T: 'a>: Iterator<Item = &'a T> {
|
||||||
|
|
||||||
fn clone_iter<T>(s: Iter<T>) {
|
fn clone_iter<T>(s: Iter<T>) {
|
||||||
s.inner.clone_box();
|
s.inner.clone_box();
|
||||||
//^^^^^^^^^^^^^^^^^^^ ()
|
//^^^^^^^^^^^^^^^^^^^ ()
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
)
|
)
|
||||||
|
|
|
@ -60,7 +60,7 @@ enum Nat { Succ(Self), Demo(Nat), Zero }
|
||||||
fn test() {
|
fn test() {
|
||||||
let foo: Nat = Nat::Zero;
|
let foo: Nat = Nat::Zero;
|
||||||
if let Nat::Succ(x) = foo {
|
if let Nat::Succ(x) = foo {
|
||||||
x
|
x;
|
||||||
} //^ Nat
|
} //^ Nat
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
|
@ -138,7 +138,7 @@ enum Option<T> { Some(T), None }
|
||||||
fn test() {
|
fn test() {
|
||||||
let foo: Option<f32> = None;
|
let foo: Option<f32> = None;
|
||||||
while let Option::Some(x) = foo {
|
while let Option::Some(x) = foo {
|
||||||
x
|
x;
|
||||||
} //^ f32
|
} //^ f32
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
|
@ -1745,7 +1745,7 @@ impl i32 { fn foo(&self) -> Foo { Foo } }
|
||||||
fn main() {
|
fn main() {
|
||||||
let x: i32 = i32;
|
let x: i32 = i32;
|
||||||
x.foo();
|
x.foo();
|
||||||
//^ Foo
|
//^^^^^^^ Foo
|
||||||
}"#,
|
}"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1763,7 +1763,7 @@ fn main() {
|
||||||
fn inner() {}
|
fn inner() {}
|
||||||
let x: i32 = i32;
|
let x: i32 = i32;
|
||||||
x.foo();
|
x.foo();
|
||||||
//^ Foo
|
//^^^^^^^ Foo
|
||||||
}"#,
|
}"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1781,7 +1781,7 @@ fn foo() -> &'static str { "" }
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
foo();
|
foo();
|
||||||
//^ &str
|
//^^^^^ &str
|
||||||
}"#,
|
}"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1799,7 +1799,7 @@ fn foo() -> &'static str { "" }
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
str::foo();
|
str::foo();
|
||||||
//^ u32
|
//^^^^^^^^^^ u32
|
||||||
}"#,
|
}"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1825,9 +1825,9 @@ mod d {
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
d::foo();
|
d::foo();
|
||||||
//^ u8
|
//^^^^^^^^ u8
|
||||||
d::foo{a:0};
|
d::foo{a:0};
|
||||||
//^ u8
|
//^^^^^^^^^^^ foo
|
||||||
}"#,
|
}"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2677,7 +2677,7 @@ fn prelude_2015() {
|
||||||
//- /main.rs edition:2015 crate:main deps:core
|
//- /main.rs edition:2015 crate:main deps:core
|
||||||
fn f() {
|
fn f() {
|
||||||
Rust;
|
Rust;
|
||||||
//^ Rust
|
//^^^^ Rust
|
||||||
}
|
}
|
||||||
|
|
||||||
//- /core.rs crate:core
|
//- /core.rs crate:core
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
use cov_mark::check;
|
||||||
use expect_test::expect;
|
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]
|
#[test]
|
||||||
fn infer_await() {
|
fn infer_await() {
|
||||||
|
@ -285,7 +286,7 @@ mod ops {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn infer_from_bound_1() {
|
fn infer_from_bound_1() {
|
||||||
check_infer(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
trait Trait<T> {}
|
trait Trait<T> {}
|
||||||
struct S<T>(T);
|
struct S<T>(T);
|
||||||
|
@ -293,99 +294,62 @@ impl<U> Trait<U> for S<U> {}
|
||||||
fn foo<T: Trait<u32>>(t: T) {}
|
fn foo<T: Trait<u32>>(t: T) {}
|
||||||
fn test() {
|
fn test() {
|
||||||
let s = S(unknown);
|
let s = S(unknown);
|
||||||
|
// ^^^^^^^ u32
|
||||||
foo(s);
|
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]
|
#[test]
|
||||||
fn infer_from_bound_2() {
|
fn infer_from_bound_2() {
|
||||||
check_infer(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
trait Trait<T> {}
|
trait Trait<T> {}
|
||||||
struct S<T>(T);
|
struct S<T>(T);
|
||||||
impl<U> Trait<U> for S<U> {}
|
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() {
|
fn test() {
|
||||||
let s = S(unknown);
|
let s = S(unknown);
|
||||||
|
// ^^^^^^^ u32
|
||||||
let x: u32 = foo(s);
|
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]
|
#[test]
|
||||||
fn trait_default_method_self_bound_implements_trait() {
|
fn trait_default_method_self_bound_implements_trait() {
|
||||||
cov_mark::check!(trait_self_implements_self);
|
cov_mark::check!(trait_self_implements_self);
|
||||||
check_infer(
|
check(
|
||||||
r#"
|
r#"
|
||||||
trait Trait {
|
trait Trait {
|
||||||
fn foo(&self) -> i64;
|
fn foo(&self) -> i64;
|
||||||
fn bar(&self) -> {
|
fn bar(&self) -> () {
|
||||||
let x = self.foo();
|
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]
|
#[test]
|
||||||
fn trait_default_method_self_bound_implements_super_trait() {
|
fn trait_default_method_self_bound_implements_super_trait() {
|
||||||
check_infer(
|
check(
|
||||||
r#"
|
r#"
|
||||||
trait SuperTrait {
|
trait SuperTrait {
|
||||||
fn foo(&self) -> i64;
|
fn foo(&self) -> i64;
|
||||||
}
|
}
|
||||||
trait Trait: SuperTrait {
|
trait Trait: SuperTrait {
|
||||||
fn bar(&self) -> {
|
fn bar(&self) -> () {
|
||||||
let x = self.foo();
|
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]
|
#[test]
|
||||||
fn infer_project_associated_type() {
|
fn infer_project_associated_type() {
|
||||||
check_infer(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
trait Iterable {
|
trait Iterable {
|
||||||
type Item;
|
type Item;
|
||||||
|
@ -394,89 +358,62 @@ struct S;
|
||||||
impl Iterable for S { type Item = u32; }
|
impl Iterable for S { type Item = u32; }
|
||||||
fn test<T: Iterable>() {
|
fn test<T: Iterable>() {
|
||||||
let x: <S as Iterable>::Item = 1;
|
let x: <S as Iterable>::Item = 1;
|
||||||
let y: <T as Iterable>::Item = no_matter;
|
// ^ u32
|
||||||
let z: T::Item = no_matter;
|
let y: <T as Iterable>::Item = u;
|
||||||
let a: <T>::Item = no_matter;
|
// ^ 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]
|
#[test]
|
||||||
fn infer_return_associated_type() {
|
fn infer_return_associated_type() {
|
||||||
check_infer(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
trait Iterable {
|
trait Iterable {
|
||||||
type Item;
|
type Item;
|
||||||
}
|
}
|
||||||
struct S;
|
struct S;
|
||||||
impl Iterable for S { type Item = u32; }
|
impl Iterable for S { type Item = u32; }
|
||||||
fn foo1<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 {}
|
fn foo2<T: Iterable>(t: T) -> <T as Iterable>::Item { loop {} }
|
||||||
fn foo3<T: Iterable>(t: T) -> <T>::Item {}
|
fn foo3<T: Iterable>(t: T) -> <T>::Item { loop {} }
|
||||||
fn test() {
|
fn test() {
|
||||||
let x = foo1(S);
|
foo1(S);
|
||||||
let y = foo2(S);
|
// ^^^^^^^ u32
|
||||||
let z = foo3(S);
|
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]
|
#[test]
|
||||||
fn infer_associated_type_bound() {
|
fn infer_associated_type_bound() {
|
||||||
check_infer(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
trait Iterable {
|
trait Iterable {
|
||||||
type Item;
|
type Item;
|
||||||
}
|
}
|
||||||
fn test<T: Iterable<Item=u32>>() {
|
fn test<T: Iterable<Item=u32>>() {
|
||||||
let y: T::Item = unknown;
|
let y: T::Item = unknown;
|
||||||
|
// ^^^^^^^ u32
|
||||||
}"#,
|
}"#,
|
||||||
expect![[r#"
|
|
||||||
67..100 '{ ...own; }': ()
|
|
||||||
77..78 'y': u32
|
|
||||||
90..97 'unknown': u32
|
|
||||||
"#]],
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn infer_const_body() {
|
fn infer_const_body() {
|
||||||
|
// FIXME make check_types work with other bodies
|
||||||
check_infer(
|
check_infer(
|
||||||
r#"
|
r#"
|
||||||
const A: u32 = 1 + 1;
|
const A: u32 = 1 + 1;
|
||||||
static B: u64 = { let x = 1; x };"#,
|
static B: u64 = { let x = 1; x };
|
||||||
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
15..16 '1': u32
|
15..16 '1': u32
|
||||||
15..20 '1 + 1': u32
|
15..20 '1 + 1': u32
|
||||||
|
@ -637,12 +574,12 @@ impl<T> core::ops::Deref for Arc<T> {
|
||||||
|
|
||||||
struct S;
|
struct S;
|
||||||
impl S {
|
impl S {
|
||||||
fn foo(&self) -> u128 {}
|
fn foo(&self) -> u128 { 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test(s: Arc<S>) {
|
fn test(s: Arc<S>) {
|
||||||
(*s, s.foo());
|
(*s, s.foo());
|
||||||
} //^ (S, u128)
|
} //^^^^^^^^^^^^^ (S, u128)
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -653,7 +590,7 @@ fn deref_trait_with_inference_var() {
|
||||||
r#"
|
r#"
|
||||||
//- minicore: deref
|
//- minicore: deref
|
||||||
struct Arc<T>;
|
struct Arc<T>;
|
||||||
fn new_arc<T>() -> Arc<T> {}
|
fn new_arc<T>() -> Arc<T> { Arc }
|
||||||
impl<T> core::ops::Deref for Arc<T> {
|
impl<T> core::ops::Deref for Arc<T> {
|
||||||
type Target = T;
|
type Target = T;
|
||||||
}
|
}
|
||||||
|
@ -663,8 +600,8 @@ fn foo(a: Arc<S>) {}
|
||||||
|
|
||||||
fn test() {
|
fn test() {
|
||||||
let a = new_arc();
|
let a = new_arc();
|
||||||
let b = (*a);
|
let b = *a;
|
||||||
//^ S
|
//^^ S
|
||||||
foo(a);
|
foo(a);
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
|
@ -684,7 +621,7 @@ impl core::ops::Deref for S {
|
||||||
|
|
||||||
fn test(s: S) {
|
fn test(s: S) {
|
||||||
s.foo();
|
s.foo();
|
||||||
} //^ {unknown}
|
} //^^^^^^^ {unknown}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -701,12 +638,12 @@ impl<T: ?Sized> core::ops::Deref for Arc<T> {
|
||||||
|
|
||||||
struct S;
|
struct S;
|
||||||
impl S {
|
impl S {
|
||||||
fn foo(&self) -> u128 {}
|
fn foo(&self) -> u128 { 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test(s: Arc<S>) {
|
fn test(s: Arc<S>) {
|
||||||
(*s, s.foo());
|
(*s, s.foo());
|
||||||
} //^ (S, u128)
|
} //^^^^^^^^^^^^^ (S, u128)
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -720,11 +657,11 @@ struct S;
|
||||||
trait Trait<T> {}
|
trait Trait<T> {}
|
||||||
impl Trait<u32> for S {}
|
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) {
|
fn test(s: S) {
|
||||||
(foo(s));
|
foo(s);
|
||||||
} //^ u32
|
} //^^^^^^ u32
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -741,12 +678,12 @@ impl Trait<isize> for S {}
|
||||||
|
|
||||||
struct O;
|
struct O;
|
||||||
impl 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() {
|
fn test() {
|
||||||
O.foo(S);
|
O.foo(S);
|
||||||
} //^ isize
|
} //^^^^^^^^ isize
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -761,12 +698,12 @@ trait Trait<T> {}
|
||||||
impl Trait<i64> for S {}
|
impl Trait<i64> for S {}
|
||||||
|
|
||||||
impl S {
|
impl S {
|
||||||
fn foo<U>(&self) -> U where Self: Trait<U> {}
|
fn foo<U>(&self) -> U where Self: Trait<U> { loop {} }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test() {
|
fn test() {
|
||||||
S.foo();
|
S.foo();
|
||||||
} //^ i64
|
} //^^^^^^^ i64
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -782,12 +719,12 @@ impl Trait<&str> for S {}
|
||||||
|
|
||||||
struct O<T>;
|
struct O<T>;
|
||||||
impl<U, T: Trait<U>> O<T> {
|
impl<U, T: Trait<U>> O<T> {
|
||||||
fn foo(&self) -> U {}
|
fn foo(&self) -> U { loop {} }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test(o: O<S>) {
|
fn test(o: O<S>) {
|
||||||
o.foo();
|
o.foo();
|
||||||
} //^ &str
|
} //^^^^^^^ &str
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -802,7 +739,7 @@ struct S;
|
||||||
impl Clone for S {}
|
impl Clone for S {}
|
||||||
impl<T> Trait for T where T: Clone {}
|
impl<T> Trait for T where T: Clone {}
|
||||||
fn test<T: Clone>(t: T) { t.foo(); }
|
fn test<T: Clone>(t: T) { t.foo(); }
|
||||||
//^ u128
|
//^^^^^^^ u128
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -818,7 +755,7 @@ struct S;
|
||||||
impl Clone for S {}
|
impl Clone for S {}
|
||||||
impl<T> Trait for T where T: Clone {}
|
impl<T> Trait for T where T: Clone {}
|
||||||
fn test<T>(t: T) { t.foo(); }
|
fn test<T>(t: T) { t.foo(); }
|
||||||
//^ {unknown}
|
//^^^^^^^ {unknown}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -831,7 +768,7 @@ trait Trait { fn foo(self) -> u128; }
|
||||||
struct S;
|
struct S;
|
||||||
impl Trait for S {}
|
impl Trait for S {}
|
||||||
fn test<T: Trait>(t: T) { t.foo(); }
|
fn test<T: Trait>(t: T) { t.foo(); }
|
||||||
//^ u128
|
//^^^^^^^ u128
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -844,7 +781,7 @@ trait Trait { fn foo(self) -> u128; }
|
||||||
struct S;
|
struct S;
|
||||||
impl Trait for S {}
|
impl Trait for S {}
|
||||||
fn test<T>(t: T) { t.foo(); }
|
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 {
|
impl<T> core::ops::Deref for T where T: Trait {
|
||||||
type Target = i128;
|
type Target = i128;
|
||||||
}
|
}
|
||||||
fn test<T: Trait>(t: T) { (*t); }
|
fn test<T: Trait>(t: T) { *t; }
|
||||||
//^ i128
|
//^^ i128
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1380,12 +1317,12 @@ fn error_bound_chalk() {
|
||||||
check_types(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
trait Trait {
|
trait Trait {
|
||||||
fn foo(&self) -> u32 {}
|
fn foo(&self) -> u32 { 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test(x: (impl Trait + UnknownTrait)) {
|
fn test(x: (impl Trait + UnknownTrait)) {
|
||||||
x.foo();
|
x.foo();
|
||||||
} //^ u32
|
} //^^^^^^^ u32
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1476,7 +1413,7 @@ trait Clone {
|
||||||
fn api_walkthrough() {
|
fn api_walkthrough() {
|
||||||
for node in foo() {
|
for node in foo() {
|
||||||
node.clone();
|
node.clone();
|
||||||
} //^ {unknown}
|
} //^^^^^^^^^^^^ {unknown}
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
|
@ -1513,13 +1450,13 @@ fn where_clause_trait_in_scope_for_method_resolution() {
|
||||||
r#"
|
r#"
|
||||||
mod foo {
|
mod foo {
|
||||||
trait Trait {
|
trait Trait {
|
||||||
fn foo(&self) -> u32 {}
|
fn foo(&self) -> u32 { 0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test<T: foo::Trait>(x: T) {
|
fn test<T: foo::Trait>(x: T) {
|
||||||
x.foo();
|
x.foo();
|
||||||
} //^ u32
|
} //^^^^^^^ u32
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1982,7 +1919,7 @@ fn fn_item_fn_trait() {
|
||||||
//- minicore: fn
|
//- minicore: fn
|
||||||
struct S;
|
struct S;
|
||||||
|
|
||||||
fn foo() -> S {}
|
fn foo() -> S { S }
|
||||||
|
|
||||||
fn takes_closure<U, F: FnOnce() -> U>(f: F) -> U { f() }
|
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 {
|
fn test<T: Trait>() where T::Item: Trait2 {
|
||||||
let x: T::Item = no_matter;
|
let x: T::Item = no_matter;
|
||||||
x.foo();
|
x.foo();
|
||||||
} //^ u32
|
} //^^^^^^^ u32
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2029,7 +1966,7 @@ trait Trait2 {
|
||||||
fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, U: Trait<()> {
|
fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, U: Trait<()> {
|
||||||
let x: T::Item = no_matter;
|
let x: T::Item = no_matter;
|
||||||
x.foo();
|
x.foo();
|
||||||
} //^ u32
|
} //^^^^^^^ u32
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2092,7 +2029,7 @@ impl Trait for S {
|
||||||
|
|
||||||
fn test() {
|
fn test() {
|
||||||
S.f();
|
S.f();
|
||||||
} //^ u32
|
} //^^^^^ u32
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2120,7 +2057,7 @@ where
|
||||||
|
|
||||||
fn foo<I: Interner>(interner: &I, t: Ty<I>) {
|
fn foo<I: Interner>(interner: &I, t: Ty<I>) {
|
||||||
fold(interner, t);
|
fold(interner, t);
|
||||||
} //^ Ty<I>
|
} //^^^^^^^^^^^^^^^^^ Ty<I>
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2139,7 +2076,7 @@ impl Trait<Self> for S {}
|
||||||
|
|
||||||
fn test() {
|
fn test() {
|
||||||
S.foo();
|
S.foo();
|
||||||
} //^ ()
|
} //^^^^^^^ ()
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2158,7 +2095,7 @@ impl Trait for S<Self> {}
|
||||||
|
|
||||||
fn test() {
|
fn test() {
|
||||||
S.foo();
|
S.foo();
|
||||||
} //^ {unknown}
|
} //^^^^^^^ {unknown}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2176,7 +2113,7 @@ trait Trait2<T> {}
|
||||||
|
|
||||||
fn test<T: Trait>() where T: Trait2<T::Item> {
|
fn test<T: Trait>() where T: Trait2<T::Item> {
|
||||||
let x: T::Item = no_matter;
|
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> {
|
fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> {
|
||||||
let x: T::Item = no_matter;
|
let x: T::Item = no_matter;
|
||||||
} //^ {unknown}
|
} //^^^^^^^^^ {unknown}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2211,7 +2148,7 @@ trait Trait {
|
||||||
|
|
||||||
fn test<T>() where T: Trait<OtherItem = T::Item> {
|
fn test<T>() where T: Trait<OtherItem = T::Item> {
|
||||||
let x: T::Item = no_matter;
|
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);
|
t.push(x);
|
||||||
let y: Key<T>;
|
let y: Key<T>;
|
||||||
(x, y);
|
(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>>>() {
|
fn test<I: Iterator<Item: OtherTrait<u32>>>() {
|
||||||
let x: <S<I> as Iterator>::Item;
|
let x: <S<I> as Iterator>::Item;
|
||||||
x.foo();
|
x.foo();
|
||||||
} //^ u32
|
} //^^^^^^^ u32
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2470,7 +2407,7 @@ impl<T: Trait> Trait for S<T> {
|
||||||
fn test<T: Trait>() {
|
fn test<T: Trait>() {
|
||||||
let y: <S<T> as Trait>::Item = no_matter;
|
let y: <S<T> as Trait>::Item = no_matter;
|
||||||
y.foo();
|
y.foo();
|
||||||
} //^ u32
|
} //^^^^^^^ u32
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2490,7 +2427,7 @@ trait Trait {
|
||||||
|
|
||||||
fn test(x: Box<dyn Trait>) {
|
fn test(x: Box<dyn Trait>) {
|
||||||
x.foo();
|
x.foo();
|
||||||
} //^ ()
|
} //^^^^^^^ ()
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2509,7 +2446,7 @@ impl ToOwned for str {
|
||||||
}
|
}
|
||||||
fn test() {
|
fn test() {
|
||||||
"foo".to_owned();
|
"foo".to_owned();
|
||||||
} //^ String
|
} //^^^^^^^^^^^^^^^^ String
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2649,7 +2586,7 @@ impl<T:A> B for T {
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
Bar::foo();
|
Bar::foo();
|
||||||
} //^ Foo
|
} //^^^^^^^^^^ Foo
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -3002,7 +2939,7 @@ fn test() {
|
||||||
S.get(1);
|
S.get(1);
|
||||||
//^^^^^^^^ u128
|
//^^^^^^^^ u128
|
||||||
S.get(1.);
|
S.get(1.);
|
||||||
//^^^^^^^^ f32
|
//^^^^^^^^^ f32
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
|
@ -3477,14 +3414,12 @@ trait Convert {
|
||||||
fn new() -> Self;
|
fn new() -> Self;
|
||||||
}
|
}
|
||||||
impl Convert for u32 {
|
impl Convert for u32 {
|
||||||
fn new() -> Self {
|
fn new() -> Self { 0 }
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_accounts() -> Result<u32, ()> {
|
async fn get_accounts() -> Result<u32, ()> {
|
||||||
let ret = Fooey.collect();
|
let ret = Fooey.collect();
|
||||||
// ^ u32
|
// ^^^^^^^^^^^^^^^ u32
|
||||||
Ok(ret)
|
Ok(ret)
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
|
@ -3493,6 +3428,7 @@ async fn get_accounts() -> Result<u32, ()> {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn local_impl_1() {
|
fn local_impl_1() {
|
||||||
|
check!(block_local_impls);
|
||||||
check_types(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
trait Trait<T> {
|
trait Trait<T> {
|
||||||
|
@ -3502,7 +3438,7 @@ trait Trait<T> {
|
||||||
fn test() {
|
fn test() {
|
||||||
struct S;
|
struct S;
|
||||||
impl Trait<u32> for S {
|
impl Trait<u32> for S {
|
||||||
fn foo(&self) { 0 }
|
fn foo(&self) -> u32 { 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
S.foo();
|
S.foo();
|
||||||
|
@ -3514,6 +3450,7 @@ fn test() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn local_impl_2() {
|
fn local_impl_2() {
|
||||||
|
check!(block_local_impls);
|
||||||
check_types(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
struct S;
|
struct S;
|
||||||
|
@ -3523,7 +3460,7 @@ fn test() {
|
||||||
fn foo(&self) -> T;
|
fn foo(&self) -> T;
|
||||||
}
|
}
|
||||||
impl Trait<u32> for S {
|
impl Trait<u32> for S {
|
||||||
fn foo(&self) { 0 }
|
fn foo(&self) -> u32 { 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
S.foo();
|
S.foo();
|
||||||
|
@ -3535,6 +3472,7 @@ fn test() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn local_impl_3() {
|
fn local_impl_3() {
|
||||||
|
check!(block_local_impls);
|
||||||
check_types(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
trait Trait<T> {
|
trait Trait<T> {
|
||||||
|
@ -3547,7 +3485,7 @@ fn test() {
|
||||||
struct S2;
|
struct S2;
|
||||||
|
|
||||||
impl Trait<S1> for S2 {
|
impl Trait<S1> for S2 {
|
||||||
fn foo(&self) { S1 }
|
fn foo(&self) -> S1 { S1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
S2.foo();
|
S2.foo();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue