diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 72d5dbc781d..a968b59bfea 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -347,12 +347,36 @@ pub fn diagnostics(self, db: &dyn HirDatabase) -> Vec { }; let mut acc = Vec::new(); - for diag in hir_ty::diagnostics::validate_module_item(db, module.id.krate(), id) { - acc.push(diag.into()) + + 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 { + 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 { Some(match self { ModuleDef::Module(it) => it.attrs(db), @@ -624,7 +648,6 @@ pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec) { } 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) { 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 { DefWithBody::Const(c) => c.name(db), } } -} -#[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 { - if !db.function_data(self.id).has_self_param() { - return None; + /// 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), } - Some(SelfParam { func: self.id }) - } - - pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec { - 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> { - 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) { 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) { } } - 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) { } } - 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) { } } - 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) { 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) { } } - 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 { + 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 { + 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> { + 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. /// diff --git a/crates/ide_diagnostics/src/handlers/missing_ok_or_some_in_tail_expr.rs b/crates/ide_diagnostics/src/handlers/missing_ok_or_some_in_tail_expr.rs index 2e9bd2d3ddd..6d8e74b6fd5 100644 --- a/crates/ide_diagnostics/src/handlers/missing_ok_or_some_in_tail_expr.rs +++ b/crates/ide_diagnostics/src/handlers/missing_ok_or_some_in_tail_expr.rs @@ -175,6 +175,19 @@ fn div(x: i32, y: i32) -> MyResult { ); } + #[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(