mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-28 02:29:44 +00:00
Add a test for field default value body as defining usage of TAIT
This commit is contained in:
parent
ce9da90630
commit
4fe18a6fb5
3 changed files with 141 additions and 27 deletions
|
|
@ -1399,11 +1399,7 @@ impl HasModule for DefWithBodyId {
|
||||||
DefWithBodyId::ConstId(it) => it.module(db),
|
DefWithBodyId::ConstId(it) => it.module(db),
|
||||||
DefWithBodyId::VariantId(it) => it.module(db),
|
DefWithBodyId::VariantId(it) => it.module(db),
|
||||||
DefWithBodyId::InTypeConstId(it) => it.lookup(db).owner.module(db),
|
DefWithBodyId::InTypeConstId(it) => it.lookup(db).owner.module(db),
|
||||||
DefWithBodyId::FieldId(it) => match it.parent {
|
DefWithBodyId::FieldId(it) => it.module(db),
|
||||||
VariantId::EnumVariantId(it) => it.module(db),
|
|
||||||
VariantId::StructId(it) => it.module(db),
|
|
||||||
VariantId::UnionId(it) => it.module(db),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ use std::env;
|
||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
use base_db::SourceDatabaseFileInputExt as _;
|
use base_db::SourceDatabaseFileInputExt as _;
|
||||||
|
use either::Either;
|
||||||
use expect_test::Expect;
|
use expect_test::Expect;
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
db::DefDatabase,
|
db::DefDatabase,
|
||||||
|
|
@ -23,12 +24,14 @@ use hir_def::{
|
||||||
hir::{ExprId, Pat, PatId},
|
hir::{ExprId, Pat, PatId},
|
||||||
item_scope::ItemScope,
|
item_scope::ItemScope,
|
||||||
nameres::DefMap,
|
nameres::DefMap,
|
||||||
src::HasSource,
|
src::{HasChildSource, HasSource},
|
||||||
AssocItemId, DefWithBodyId, HasModule, LocalModuleId, Lookup, ModuleDefId, SyntheticSyntax,
|
AdtId, AssocItemId, DefWithBodyId, FieldId, HasModule, LocalModuleId, Lookup, ModuleDefId,
|
||||||
|
SyntheticSyntax,
|
||||||
};
|
};
|
||||||
use hir_expand::{db::ExpandDatabase, FileRange, InFile};
|
use hir_expand::{db::ExpandDatabase, FileRange, InFile};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
use span::TextSize;
|
||||||
use stdx::format_to;
|
use stdx::format_to;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, AstNode, HasName},
|
ast::{self, AstNode, HasName},
|
||||||
|
|
@ -132,14 +135,40 @@ fn check_impl(
|
||||||
None => continue,
|
None => continue,
|
||||||
};
|
};
|
||||||
let def_map = module.def_map(&db);
|
let def_map = module.def_map(&db);
|
||||||
visit_module(&db, &def_map, module.local_id, &mut |it| {
|
visit_module(&db, &def_map, module.local_id, &mut |it| match it {
|
||||||
defs.push(match it {
|
ModuleDefId::FunctionId(it) => defs.push(it.into()),
|
||||||
ModuleDefId::FunctionId(it) => it.into(),
|
ModuleDefId::EnumVariantId(it) => {
|
||||||
ModuleDefId::EnumVariantId(it) => it.into(),
|
defs.push(it.into());
|
||||||
ModuleDefId::ConstId(it) => it.into(),
|
let variant_id = it.into();
|
||||||
ModuleDefId::StaticId(it) => it.into(),
|
let vd = db.variant_data(variant_id);
|
||||||
_ => return,
|
defs.extend(vd.fields().iter().filter_map(|(local_id, fd)| {
|
||||||
})
|
if fd.has_default {
|
||||||
|
let field = FieldId { parent: variant_id, local_id, has_default: true };
|
||||||
|
Some(DefWithBodyId::FieldId(field))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
ModuleDefId::ConstId(it) => defs.push(it.into()),
|
||||||
|
ModuleDefId::StaticId(it) => defs.push(it.into()),
|
||||||
|
ModuleDefId::AdtId(it) => {
|
||||||
|
let variant_id = match it {
|
||||||
|
AdtId::StructId(it) => it.into(),
|
||||||
|
AdtId::UnionId(it) => it.into(),
|
||||||
|
AdtId::EnumId(_) => return,
|
||||||
|
};
|
||||||
|
let vd = db.variant_data(variant_id);
|
||||||
|
defs.extend(vd.fields().iter().filter_map(|(local_id, fd)| {
|
||||||
|
if fd.has_default {
|
||||||
|
let field = FieldId { parent: variant_id, local_id, has_default: true };
|
||||||
|
Some(DefWithBodyId::FieldId(field))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
defs.sort_by_key(|def| match def {
|
defs.sort_by_key(|def| match def {
|
||||||
|
|
@ -160,12 +189,20 @@ fn check_impl(
|
||||||
loc.source(&db).value.syntax().text_range().start()
|
loc.source(&db).value.syntax().text_range().start()
|
||||||
}
|
}
|
||||||
DefWithBodyId::InTypeConstId(it) => it.source(&db).syntax().text_range().start(),
|
DefWithBodyId::InTypeConstId(it) => it.source(&db).syntax().text_range().start(),
|
||||||
DefWithBodyId::FieldId(_) => unreachable!(),
|
DefWithBodyId::FieldId(it) => {
|
||||||
|
let cs = it.parent.child_source(&db);
|
||||||
|
match cs.value.get(it.local_id) {
|
||||||
|
Some(Either::Left(it)) => it.syntax().text_range().start(),
|
||||||
|
Some(Either::Right(it)) => it.syntax().text_range().end(),
|
||||||
|
None => TextSize::new(u32::MAX),
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
let mut unexpected_type_mismatches = String::new();
|
let mut unexpected_type_mismatches = String::new();
|
||||||
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);
|
||||||
|
dbg!(&inference_result);
|
||||||
|
|
||||||
for (pat, mut ty) in inference_result.type_of_pat.iter() {
|
for (pat, mut ty) in inference_result.type_of_pat.iter() {
|
||||||
if let Pat::Bind { id, .. } = body.pats[pat] {
|
if let Pat::Bind { id, .. } = body.pats[pat] {
|
||||||
|
|
@ -389,14 +426,40 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
|
||||||
let def_map = module.def_map(&db);
|
let def_map = module.def_map(&db);
|
||||||
|
|
||||||
let mut defs: Vec<DefWithBodyId> = Vec::new();
|
let mut defs: Vec<DefWithBodyId> = Vec::new();
|
||||||
visit_module(&db, &def_map, module.local_id, &mut |it| {
|
visit_module(&db, &def_map, module.local_id, &mut |it| match it {
|
||||||
defs.push(match it {
|
ModuleDefId::FunctionId(it) => defs.push(it.into()),
|
||||||
ModuleDefId::FunctionId(it) => it.into(),
|
ModuleDefId::EnumVariantId(it) => {
|
||||||
ModuleDefId::EnumVariantId(it) => it.into(),
|
defs.push(it.into());
|
||||||
ModuleDefId::ConstId(it) => it.into(),
|
let variant_id = it.into();
|
||||||
ModuleDefId::StaticId(it) => it.into(),
|
let vd = db.variant_data(variant_id);
|
||||||
_ => return,
|
defs.extend(vd.fields().iter().filter_map(|(local_id, fd)| {
|
||||||
})
|
if fd.has_default {
|
||||||
|
let field = FieldId { parent: variant_id, local_id, has_default: true };
|
||||||
|
Some(DefWithBodyId::FieldId(field))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
ModuleDefId::ConstId(it) => defs.push(it.into()),
|
||||||
|
ModuleDefId::StaticId(it) => defs.push(it.into()),
|
||||||
|
ModuleDefId::AdtId(it) => {
|
||||||
|
let variant_id = match it {
|
||||||
|
AdtId::StructId(it) => it.into(),
|
||||||
|
AdtId::UnionId(it) => it.into(),
|
||||||
|
AdtId::EnumId(_) => return,
|
||||||
|
};
|
||||||
|
let vd = db.variant_data(variant_id);
|
||||||
|
defs.extend(vd.fields().iter().filter_map(|(local_id, fd)| {
|
||||||
|
if fd.has_default {
|
||||||
|
let field = FieldId { parent: variant_id, local_id, has_default: true };
|
||||||
|
Some(DefWithBodyId::FieldId(field))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
});
|
});
|
||||||
defs.sort_by_key(|def| match def {
|
defs.sort_by_key(|def| match def {
|
||||||
DefWithBodyId::FunctionId(it) => {
|
DefWithBodyId::FunctionId(it) => {
|
||||||
|
|
@ -416,7 +479,14 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
|
||||||
loc.source(&db).value.syntax().text_range().start()
|
loc.source(&db).value.syntax().text_range().start()
|
||||||
}
|
}
|
||||||
DefWithBodyId::InTypeConstId(it) => it.source(&db).syntax().text_range().start(),
|
DefWithBodyId::InTypeConstId(it) => it.source(&db).syntax().text_range().start(),
|
||||||
DefWithBodyId::FieldId(_) => unreachable!(),
|
DefWithBodyId::FieldId(it) => {
|
||||||
|
let cs = it.parent.child_source(&db);
|
||||||
|
match cs.value.get(it.local_id) {
|
||||||
|
Some(Either::Left(it)) => it.syntax().text_range().start(),
|
||||||
|
Some(Either::Right(it)) => it.syntax().text_range().end(),
|
||||||
|
None => TextSize::new(u32::MAX),
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
for def in defs {
|
for def in defs {
|
||||||
let (body, source_map) = db.body_with_source_map(def);
|
let (body, source_map) = db.body_with_source_map(def);
|
||||||
|
|
@ -477,7 +547,7 @@ pub(crate) fn visit_module(
|
||||||
let body = db.body(it.into());
|
let body = db.body(it.into());
|
||||||
visit_body(db, &body, cb);
|
visit_body(db, &body, cb);
|
||||||
}
|
}
|
||||||
ModuleDefId::AdtId(hir_def::AdtId::EnumId(it)) => {
|
ModuleDefId::AdtId(AdtId::EnumId(it)) => {
|
||||||
db.enum_data(it).variants.iter().for_each(|&(it, _)| {
|
db.enum_data(it).variants.iter().for_each(|&(it, _)| {
|
||||||
let body = db.body(it.into());
|
let body = db.body(it.into());
|
||||||
cb(it.into());
|
cb(it.into());
|
||||||
|
|
|
||||||
|
|
@ -157,5 +157,53 @@ static ALIAS: i32 = {
|
||||||
217..218 '5': i32
|
217..218 '5': i32
|
||||||
205..211: expected impl Trait + ?Sized, got Struct
|
205..211: expected impl Trait + ?Sized, got Struct
|
||||||
"#]],
|
"#]],
|
||||||
)
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn defining_type_alias_impl_trait_from_default_fields() {
|
||||||
|
check_no_mismatches(
|
||||||
|
r#"
|
||||||
|
trait Trait {}
|
||||||
|
|
||||||
|
struct Struct;
|
||||||
|
|
||||||
|
impl Trait for Struct {}
|
||||||
|
|
||||||
|
type AliasTy = impl Trait;
|
||||||
|
|
||||||
|
struct Foo {
|
||||||
|
foo: AliasTy = {
|
||||||
|
let x: AliasTy = Struct;
|
||||||
|
x
|
||||||
|
},
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
check_infer_with_mismatches(
|
||||||
|
r#"
|
||||||
|
trait Trait {}
|
||||||
|
|
||||||
|
struct Struct;
|
||||||
|
|
||||||
|
impl Trait for Struct {}
|
||||||
|
|
||||||
|
type AliasTy = impl Trait;
|
||||||
|
|
||||||
|
struct Foo {
|
||||||
|
foo: i32 = {
|
||||||
|
let x: AliasTy = Struct;
|
||||||
|
5
|
||||||
|
},
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
114..164 '{ ... }': i32
|
||||||
|
128..129 'x': impl Trait + ?Sized
|
||||||
|
141..147 'Struct': Struct
|
||||||
|
157..158 '5': i32
|
||||||
|
141..147: expected impl Trait + ?Sized, got Struct
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue