10059: feat: Enable diagnostics in `const` and `static` items r=jonas-schievink a=jonas-schievink

bors r+

Co-authored-by: Jonas Schievink <jonasschievink@gmail.com>
This commit is contained in:
bors[bot] 2021-08-27 21:22:35 +00:00 committed by GitHub
commit 9ea3c4d53b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 129 additions and 75 deletions

View File

@ -347,12 +347,36 @@ pub fn diagnostics(self, db: &dyn HirDatabase) -> Vec<AnyDiagnostic> {
};
let mut acc = Vec::new();
match self.as_def_with_body() {
Some(def) => {
def.diagnostics(db, &mut acc);
}
None => {
for diag in hir_ty::diagnostics::validate_module_item(db, module.id.krate(), id) {
acc.push(diag.into())
}
}
}
acc
}
pub fn as_def_with_body(self) -> Option<DefWithBody> {
match self {
ModuleDef::Function(it) => Some(it.into()),
ModuleDef::Const(it) => Some(it.into()),
ModuleDef::Static(it) => Some(it.into()),
ModuleDef::Module(_)
| ModuleDef::Adt(_)
| ModuleDef::Variant(_)
| ModuleDef::Trait(_)
| ModuleDef::TypeAlias(_)
| ModuleDef::BuiltinType(_) => None,
}
}
pub fn attrs(&self, db: &dyn HirDatabase) -> Option<AttrsWithOwner> {
Some(match self {
ModuleDef::Module(it) => it.attrs(db),
@ -624,7 +648,6 @@ pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) {
}
for decl in self.declarations(db) {
match decl {
ModuleDef::Function(f) => f.diagnostics(db, acc),
ModuleDef::Module(m) => {
// Only add diagnostics from inline modules
if def_map[m.id.local_id].origin.is_inline() {
@ -637,9 +660,13 @@ pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) {
for impl_def in self.impl_defs(db) {
for item in impl_def.items(db) {
if let AssocItem::Function(f) = item {
f.diagnostics(db, acc);
}
let def: DefWithBody = match item {
AssocItem::Function(it) => it.into(),
AssocItem::Const(it) => it.into(),
AssocItem::TypeAlias(_) => continue,
};
def.diagnostics(db, acc);
}
}
}
@ -999,76 +1026,20 @@ pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
DefWithBody::Const(c) => c.name(db),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Function {
pub(crate) id: FunctionId,
/// Returns the type this def's body has to evaluate to.
pub fn body_type(self, db: &dyn HirDatabase) -> Type {
match self {
DefWithBody::Function(it) => it.ret_type(db),
DefWithBody::Static(it) => it.ty(db),
DefWithBody::Const(it) => it.ty(db),
}
impl Function {
pub fn module(self, db: &dyn HirDatabase) -> Module {
self.id.lookup(db.upcast()).module(db.upcast()).into()
}
pub fn name(self, db: &dyn HirDatabase) -> Name {
db.function_data(self.id).name.clone()
}
/// Get this function's return type
pub fn ret_type(self, db: &dyn HirDatabase) -> Type {
let resolver = self.id.resolver(db.upcast());
let krate = self.id.lookup(db.upcast()).container.module(db.upcast()).krate();
let ret_type = &db.function_data(self.id).ret_type;
let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
let ty = ctx.lower_ty(ret_type);
Type::new_with_resolver_inner(db, krate, &resolver, ty)
}
pub fn self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> {
if !db.function_data(self.id).has_self_param() {
return None;
}
Some(SelfParam { func: self.id })
}
pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec<Param> {
let resolver = self.id.resolver(db.upcast());
let krate = self.id.lookup(db.upcast()).container.module(db.upcast()).krate();
let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
let environment = db.trait_environment(self.id.into());
db.function_data(self.id)
.params
.iter()
.enumerate()
.map(|(idx, type_ref)| {
let ty = Type { krate, env: environment.clone(), ty: ctx.lower_ty(type_ref) };
Param { func: self, ty, idx }
})
.collect()
}
pub fn method_params(self, db: &dyn HirDatabase) -> Option<Vec<Param>> {
if self.self_param(db).is_none() {
return None;
}
let mut res = self.assoc_fn_params(db);
res.remove(0);
Some(res)
}
pub fn is_unsafe(self, db: &dyn HirDatabase) -> bool {
db.function_data(self.id).is_unsafe()
}
pub fn is_async(self, db: &dyn HirDatabase) -> bool {
db.function_data(self.id).is_async()
}
pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) {
let krate = self.module(db).id.krate();
let source_map = db.body_with_source_map(self.id.into()).1;
let source_map = db.body_with_source_map(self.into()).1;
for diag in source_map.diagnostics() {
match diag {
BodyDiagnostic::InactiveCode { node, cfg, opts } => acc.push(
@ -1096,8 +1067,8 @@ pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) {
}
}
let infer = db.infer(self.id.into());
let source_map = Lazy::new(|| db.body_with_source_map(self.id.into()).1);
let infer = db.infer(self.into());
let source_map = Lazy::new(|| db.body_with_source_map(self.into()).1);
for d in &infer.diagnostics {
match d {
hir_ty::InferenceDiagnostic::NoSuchField { expr } => {
@ -1113,7 +1084,7 @@ pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) {
}
}
for expr in hir_ty::diagnostics::missing_unsafe(db, self.id.into()) {
for expr in hir_ty::diagnostics::missing_unsafe(db, self.into()) {
match source_map.expr_syntax(expr) {
Ok(expr) => acc.push(MissingUnsafe { expr }.into()),
Err(SyntheticSyntax) => {
@ -1123,7 +1094,7 @@ pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) {
}
}
for diagnostic in BodyValidationDiagnostic::collect(db, self.id.into()) {
for diagnostic in BodyValidationDiagnostic::collect(db, self.into()) {
match diagnostic {
BodyValidationDiagnostic::RecordMissingFields {
record,
@ -1220,7 +1191,7 @@ pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) {
MissingOkOrSomeInTailExpr {
expr,
required,
expected: self.ret_type(db),
expected: self.body_type(db),
}
.into(),
),
@ -1260,10 +1231,80 @@ pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) {
}
}
for diag in hir_ty::diagnostics::validate_module_item(db, krate, self.id.into()) {
let def: ModuleDef = match self {
DefWithBody::Function(it) => it.into(),
DefWithBody::Static(it) => it.into(),
DefWithBody::Const(it) => it.into(),
};
for diag in hir_ty::diagnostics::validate_module_item(db, krate, def.into()) {
acc.push(diag.into())
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Function {
pub(crate) id: FunctionId,
}
impl Function {
pub fn module(self, db: &dyn HirDatabase) -> Module {
self.id.lookup(db.upcast()).module(db.upcast()).into()
}
pub fn name(self, db: &dyn HirDatabase) -> Name {
db.function_data(self.id).name.clone()
}
/// Get this function's return type
pub fn ret_type(self, db: &dyn HirDatabase) -> Type {
let resolver = self.id.resolver(db.upcast());
let krate = self.id.lookup(db.upcast()).container.module(db.upcast()).krate();
let ret_type = &db.function_data(self.id).ret_type;
let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
let ty = ctx.lower_ty(ret_type);
Type::new_with_resolver_inner(db, krate, &resolver, ty)
}
pub fn self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> {
if !db.function_data(self.id).has_self_param() {
return None;
}
Some(SelfParam { func: self.id })
}
pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec<Param> {
let resolver = self.id.resolver(db.upcast());
let krate = self.id.lookup(db.upcast()).container.module(db.upcast()).krate();
let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
let environment = db.trait_environment(self.id.into());
db.function_data(self.id)
.params
.iter()
.enumerate()
.map(|(idx, type_ref)| {
let ty = Type { krate, env: environment.clone(), ty: ctx.lower_ty(type_ref) };
Param { func: self, ty, idx }
})
.collect()
}
pub fn method_params(self, db: &dyn HirDatabase) -> Option<Vec<Param>> {
if self.self_param(db).is_none() {
return None;
}
let mut res = self.assoc_fn_params(db);
res.remove(0);
Some(res)
}
pub fn is_unsafe(self, db: &dyn HirDatabase) -> bool {
db.function_data(self.id).is_unsafe()
}
pub fn is_async(self, db: &dyn HirDatabase) -> bool {
db.function_data(self.id).is_async()
}
/// Whether this function declaration has a definition.
///

View File

@ -175,6 +175,19 @@ fn div(x: i32, y: i32) -> MyResult<i32> {
);
}
#[test]
fn test_in_const_and_static() {
check_fix(
r#"
//- minicore: option, result
static A: Option<()> = {($0)};
"#,
r#"
static A: Option<()> = {Some(())};
"#,
)
}
#[test]
fn test_wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() {
check_diagnostics(