Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions crates/hir-def/src/expr_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,15 @@ struct FormatTemplate {
implicit_capture_to_source: FxHashMap<ExprId, InFile<(ExprPtr, TextRange)>>,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub enum MissingBodyItemKind {
AssocConst,
AssocType,
Const,
Static,
TypeAlias,
}

#[derive(Debug, Eq, PartialEq)]
pub enum ExpressionStoreDiagnostics {
InactiveCode { node: InFile<SyntaxNodePtr>, cfg: CfgExpr, opts: CfgOptions },
Expand All @@ -330,6 +339,7 @@ pub enum ExpressionStoreDiagnostics {
UndeclaredLabel { node: InFile<AstPtr<ast::Lifetime>>, name: Name },
PatternArgInExternFn { node: InFile<AstPtr<ast::Pat>> },
FruInDestructuringAssignment { node: InFile<AstPtr<ast::Expr>> },
MissingBody { node: InFile<SyntaxNodePtr>, kind: MissingBodyItemKind },
}

impl ExpressionStoreBuilder {
Expand Down
18 changes: 11 additions & 7 deletions crates/hir-def/src/expr_store/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::ops;
use base_db::SourceDatabase;
use hir_expand::{InFile, Lookup};
use span::Edition;
use syntax::ast;
use syntax::{SyntaxNodePtr, ast};
use triomphe::Arc;

use crate::{
Expand Down Expand Up @@ -96,36 +96,40 @@ impl Body {

let mut is_async_fn = false;
let mut is_gen_fn = false;
let InFile { file_id, value: body } = {
let (InFile { file_id, value: body }, syntax_node) = {
match def {
DefWithBodyId::FunctionId(f) => {
let f = f.lookup(db);
let src = f.source(db);
params = src.value.param_list();
is_async_fn = src.value.async_token().is_some();
is_gen_fn = src.value.gen_token().is_some();
src.map(|it| it.body().map(ast::Expr::from))
let syntax_node = SyntaxNodePtr::new(src.syntax().value);
(src.map(|it| it.body().map(ast::Expr::from)), syntax_node)
Comment thread
BenjaminBrienen marked this conversation as resolved.
}
DefWithBodyId::ConstId(c) => {
let c = c.lookup(db);
let src = c.source(db);
src.map(|it| it.body())
let syntax_node = SyntaxNodePtr::new(src.syntax().value);
(src.map(|it| it.body()), syntax_node)
}
DefWithBodyId::StaticId(s) => {
let s = s.lookup(db);
let src = s.source(db);
src.map(|it| it.body())
let syntax_node = SyntaxNodePtr::new(src.syntax().value);
(src.map(|it| it.body()), syntax_node)
}
DefWithBodyId::VariantId(v) => {
let s = v.lookup(db);
let src = s.source(db);
src.map(|it| it.const_arg()?.expr())
let syntax_node = SyntaxNodePtr::new(src.syntax().value);
(src.map(|it| it.const_arg()?.expr()), syntax_node)
}
}
};
let module = def.module(db);
let (body, source_map) =
lower_body(db, def, file_id, module, params, body, is_async_fn, is_gen_fn);
lower_body(db, def, syntax_node, file_id, module, params, body, is_async_fn, is_gen_fn);

(Arc::new(body), source_map)
}
Expand Down
61 changes: 56 additions & 5 deletions crates/hir-def/src/expr_store/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ use thin_vec::ThinVec;
use tt::TextRange;

use crate::{
AdtId, BlockId, BlockIdLt, ConstId, DefWithBodyId, FunctionId, GenericDefId, ImplId,
AdtId, BlockId, BlockIdLt, ConstId, DefWithBodyId, FunctionId, GenericDefId, HasModule, ImplId,
ItemContainerId, LoweringMode, MacroId, ModuleDefId, ModuleId, TraitId, TypeAliasId,
UnresolvedMacro,
attrs::AttrFlags,
expr_store::{
Body, BodySourceMap, ExprPtr, ExprRoot, ExpressionStore, ExpressionStoreBuilder,
ExpressionStoreDiagnostics, ExpressionStoreSourceMap, HygieneId, LabelPtr, LifetimePtr,
PatPtr, StoreVisitor, TypePtr,
MissingBodyItemKind, PatPtr, StoreVisitor, TypePtr,
body::Param,
expander::Expander,
lower::generics::ImplTraitLowerFn,
Expand Down Expand Up @@ -70,6 +70,7 @@ pub use self::path::hir_segment_to_ast_segment;
pub(super) fn lower_body(
db: &dyn SourceDatabase,
owner: DefWithBodyId,
syntax_node: SyntaxNodePtr,
current_file_id: HirFileId,
module: ModuleId,
parameters: Option<ast::ParamList>,
Expand Down Expand Up @@ -133,7 +134,7 @@ pub(super) fn lower_body(
BodySourceMap { self_param: source_map_self_param, store: source_map },
);
}

validate_required_body(db, owner, current_file_id, syntax_node, body.as_ref(), &mut collector);
collector.with_expr_root(|collector| {
if let DefWithBodyId::FunctionId(func) = owner
&& let Some(param_list) = parameters
Expand Down Expand Up @@ -206,6 +207,40 @@ pub(super) fn lower_body(
)
}

fn validate_required_body(
db: &(dyn SourceDatabase + 'static),
owner: DefWithBodyId,
current_file_id: HirFileId,
syntax_node: SyntaxNodePtr,
body: Option<&ast::Expr>,
collector: &mut ExprCollector<'_>,
) {
if body.is_some() {
return;
}
let diagnostic_kind = match owner {
// FIXME: add diagnostic for missing body
// rustc says: if body.is_none() && !is_intrinsic && !self.is_sdylib_interface
DefWithBodyId::FunctionId(_function_id) => None,
DefWithBodyId::StaticId(id) => match id.loc(db).container {
ItemContainerId::ModuleId(_) => Some(MissingBodyItemKind::Static),
ItemContainerId::ExternBlockId(_)
| ItemContainerId::ImplId(_)
| ItemContainerId::TraitId(_) => None,
},
DefWithBodyId::ConstId(id) => match id.loc(db).container {
ItemContainerId::ModuleId(_) => Some(MissingBodyItemKind::Const),
ItemContainerId::ImplId(_) => Some(MissingBodyItemKind::AssocConst),
ItemContainerId::ExternBlockId(_) | ItemContainerId::TraitId(_) => None,
},
DefWithBodyId::VariantId(_) => None,
};
if let Some(kind) = diagnostic_kind {
let node = InFile::new(current_file_id, syntax_node);
collector.store.diagnostics.push(ExpressionStoreDiagnostics::MissingBody { node, kind });
}
}

pub(crate) fn lower_type_ref(
db: &dyn SourceDatabase,
module: ModuleId,
Expand Down Expand Up @@ -290,12 +325,13 @@ pub(crate) fn lower_trait(

pub(crate) fn lower_type_alias(
db: &dyn SourceDatabase,
module: ModuleId,
container: ItemContainerId,
alias: InFile<ast::TypeAlias>,
type_alias_id: TypeAliasId,
) -> (ExpressionStore, ExpressionStoreSourceMap, GenericParams, Box<[TypeBound]>, Option<TypeRefId>)
{
let mut expr_collector = ExprCollector::new(db, module, alias.file_id, LoweringMode::Analysis);
let mut expr_collector =
ExprCollector::new(db, container.module(db), alias.file_id, LoweringMode::Analysis);
let bounds = alias
.value
.type_bound_list()
Expand All @@ -319,6 +355,21 @@ pub(crate) fn lower_type_alias(
.value
.ty()
.map(|ty| expr_collector.lower_type_ref(ty, &mut ExprCollector::impl_trait_allocator));
if alias.value.ty().is_none() {
let diagnostic_kind = match container {
ItemContainerId::ModuleId(_) => Some(MissingBodyItemKind::TypeAlias),
ItemContainerId::ImplId(_) => Some(MissingBodyItemKind::AssocType),
ItemContainerId::ExternBlockId(_) => None,
ItemContainerId::TraitId(_) => None,
};
if let Some(kind) = diagnostic_kind {
let node = InFile::new(alias.file_id, SyntaxNodePtr::new(alias.value.syntax()));
expr_collector
.store
.diagnostics
.push(ExpressionStoreDiagnostics::MissingBody { node, kind });
}
};
let (store, source_map) = expr_collector.store.finish();
(store, source_map, params, bounds, type_ref)
}
Expand Down
10 changes: 1 addition & 9 deletions crates/hir-def/src/signatures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -834,7 +834,7 @@ impl TypeAliasSignature {
let source = loc.source(db);
let name = as_name_opt(source.value.name());
let (store, source_map, generic_params, bounds, ty) =
lower_type_alias(db, loc.container.module(db), source, id);
lower_type_alias(db, loc.container, source, id);

(
Arc::new(TypeAliasSignature { store, generic_params, flags, bounds, name, ty }),
Expand All @@ -849,14 +849,6 @@ pub struct FunctionBody {
pub parameters: Box<[PatId]>,
}

#[derive(Debug, PartialEq, Eq)]
pub struct SimpleBody {
pub store: ExpressionStore,
}
pub type StaticBody = SimpleBody;
pub type ConstBody = SimpleBody;
pub type EnumVariantBody = SimpleBody;

#[derive(Debug, PartialEq, Eq)]
pub struct VariantFieldsBody {
pub store: ExpressionStore,
Expand Down
12 changes: 11 additions & 1 deletion crates/hir/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ use crate::{
struct_tail_raw,
};

pub use hir_def::VariantId;
pub use hir_def::{VariantId, expr_store::MissingBodyItemKind};
pub use hir_ty::{
GenericArgsProhibitedReason, IncorrectGenericsLenKind, ReturnKind,
diagnostics::{CaseType, IncorrectCase},
Expand Down Expand Up @@ -141,6 +141,7 @@ diagnostics![AnyDiagnostic<'db> ->
ExpectedFunction<'db>,
ExplicitDropMethodUse,
FruInDestructuringAssignment,
MissingBody,
FunctionalRecordUpdateOnNonStruct,
GenericDefaultRefersToSelf,
InactiveCode,
Expand Down Expand Up @@ -401,6 +402,12 @@ pub struct FruInDestructuringAssignment {
pub node: InFile<AstPtr<ast::Expr>>,
}

#[derive(Debug)]
pub struct MissingBody {
pub node: InFile<SyntaxNodePtr>,
pub kind: MissingBodyItemKind,
}

#[derive(Debug)]
pub struct FunctionalRecordUpdateOnNonStruct {
pub base_expr: InFile<ExprOrPatPtr>,
Expand Down Expand Up @@ -1392,6 +1399,9 @@ impl<'a, 'db> DiagnosticsCollector<'a, 'db> {
ExpressionStoreDiagnostics::FruInDestructuringAssignment { node } => {
FruInDestructuringAssignment { node: *node }.into()
}
ExpressionStoreDiagnostics::MissingBody { node, kind } => {
MissingBody { node: *node, kind: *kind }.into()
}
});
}

Expand Down
72 changes: 72 additions & 0 deletions crates/ide-diagnostics/src/handlers/missing_body.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};

// Diagnostic: missing-body
//
// This diagnostic is triggered when a body is missing.
pub(crate) fn missing_body(ctx: &DiagnosticsContext<'_, '_>, d: &hir::MissingBody) -> Diagnostic {
let message = match d.kind {
hir::MissingBodyItemKind::AssocConst => "associated constant in `impl` without body",
hir::MissingBodyItemKind::AssocType => "associated type in `impl` without body",
hir::MissingBodyItemKind::Const => "free constant item without body",
hir::MissingBodyItemKind::Static => "free static item without body",
hir::MissingBodyItemKind::TypeAlias => "free type alias without body",
};
Diagnostic::new_with_syntax_node_ptr(ctx, DiagnosticCode::SyntaxError, message, d.node).stable()
}

#[cfg(test)]
mod tests {
use crate::tests::check_diagnostics;

#[test]
fn associated_const() {
check_diagnostics(
r#"
trait Foo { const BAR: u32; }
impl Foo for () { const BAR: u32; }
//^^^^^^^^^^^^^^^ error: associated constant in `impl` without body
"#,
);
}

#[test]
fn associated_type_impl() {
check_diagnostics(
r#"
trait Foo { type Bar; }
impl Foo for () { type Bar; }
//^^^^^^^^^ error: associated type in `impl` without body
"#,
);
}

#[test]
fn free_const() {
check_diagnostics(
r#"
const FOO: u32;
//^^^^^^^^^^^^^^^ error: free constant item without body
"#,
);
}

#[test]
fn free_static() {
check_diagnostics(
r#"
static FOO: u32;
//^^^^^^^^^^^^^^^^ error: free static item without body
"#,
);
}

#[test]
fn type_alias_module() {
check_diagnostics(
r#"
type Foo;
//^^^^^^^^^ error: free type alias without body
"#,
);
}
}
2 changes: 2 additions & 0 deletions crates/ide-diagnostics/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ mod handlers {
pub(crate) mod method_call_illegal_sized_bound;
pub(crate) mod mismatched_arg_count;
pub(crate) mod mismatched_array_pat_len;
pub(crate) mod missing_body;
pub(crate) mod missing_fields;
pub(crate) mod missing_lifetime;
pub(crate) mod missing_match_arms;
Expand Down Expand Up @@ -545,6 +546,7 @@ pub fn semantic_diagnostics(
}
AnyDiagnostic::UnimplementedTrait(d) => handlers::unimplemented_trait::unimplemented_trait(&ctx, &d),
AnyDiagnostic::FruInDestructuringAssignment(d) => handlers::fru_in_destructuring_assignment::fru_in_destructuring_assignment(&ctx, &d),
AnyDiagnostic::MissingBody(d) => handlers::missing_body::missing_body(&ctx, &d),
AnyDiagnostic::ExplicitDropMethodUse(d) => handlers::explicit_drop_method_use::explicit_drop_method_use(&ctx, &d),
AnyDiagnostic::YieldOutsideCoroutine(d) => handlers::yield_outside_coroutine::yield_outside_coroutine(&ctx, &d),
AnyDiagnostic::ReturnOutsideFunction(d) => handlers::return_outside_function::return_outside_function(&ctx, &d),
Expand Down