mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 06:11:35 +00:00
Lay the foundation for diagnostics in ty lowering, and implement a first diagnostic
The diagnostic implemented is a simple one (E0109). It serves as a test for the new foundation. This commit only implements diagnostics for type in bodies and body-carrying signatures; the next commit will include diagnostics in the rest of the things. Also fix one weird bug that was detected when implementing this that caused `Fn::(A, B) -> C` (which is a valid, if bizarre, alternative syntax to `Fn(A, B) -> C` to lower incorrectly. And also fix a maybe-bug where parentheses were sneaked into a code string needlessly; this was not detected until now because the parentheses were removed (by the make-AST family API), but with a change in this commit they are now inserted. So fix that too.
This commit is contained in:
parent
4e475a3245
commit
5f25ae3d1b
19 changed files with 811 additions and 80 deletions
|
@ -33,6 +33,14 @@ syntax.workspace = true
|
|||
tt.workspace = true
|
||||
span.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
expect-test.workspace = true
|
||||
|
||||
# local deps
|
||||
test-utils.workspace = true
|
||||
test-fixture.workspace = true
|
||||
syntax-bridge.workspace = true
|
||||
|
||||
[features]
|
||||
in-rust-tree = ["hir-expand/in-rust-tree"]
|
||||
|
||||
|
|
|
@ -3,23 +3,34 @@
|
|||
//!
|
||||
//! This probably isn't the best way to do this -- ideally, diagnostics should
|
||||
//! be expressed in terms of hir types themselves.
|
||||
pub use hir_ty::diagnostics::{CaseType, IncorrectCase};
|
||||
use cfg::{CfgExpr, CfgOptions};
|
||||
use either::Either;
|
||||
use hir_def::{
|
||||
hir::ExprOrPatId,
|
||||
path::{hir_segment_to_ast_segment, ModPath},
|
||||
type_ref::TypesSourceMap,
|
||||
AssocItemId, DefWithBodyId, SyntheticSyntax,
|
||||
};
|
||||
use hir_expand::{name::Name, HirFileId, InFile};
|
||||
use hir_ty::{
|
||||
db::HirDatabase,
|
||||
diagnostics::{BodyValidationDiagnostic, UnsafetyReason},
|
||||
CastError, InferenceDiagnostic,
|
||||
CastError, InferenceDiagnostic, InferenceTyDiagnosticSource, TyLoweringDiagnosticKind,
|
||||
};
|
||||
use syntax::{
|
||||
ast::{self, HasGenericArgs},
|
||||
AstPtr, SyntaxError, SyntaxNodePtr, TextRange,
|
||||
};
|
||||
|
||||
use cfg::{CfgExpr, CfgOptions};
|
||||
use either::Either;
|
||||
pub use hir_def::VariantId;
|
||||
use hir_def::{hir::ExprOrPatId, path::ModPath, AssocItemId, DefWithBodyId, SyntheticSyntax};
|
||||
use hir_expand::{name::Name, HirFileId, InFile};
|
||||
use syntax::{ast, AstPtr, SyntaxError, SyntaxNodePtr, TextRange};
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{AssocItem, Field, Local, Trait, Type};
|
||||
|
||||
pub use hir_def::VariantId;
|
||||
pub use hir_ty::{
|
||||
diagnostics::{CaseType, IncorrectCase},
|
||||
GenericArgsProhibitedReason,
|
||||
};
|
||||
|
||||
macro_rules! diagnostics {
|
||||
($($diag:ident,)*) => {
|
||||
#[derive(Debug)]
|
||||
|
@ -98,6 +109,7 @@ diagnostics![
|
|||
UnresolvedIdent,
|
||||
UnusedMut,
|
||||
UnusedVariable,
|
||||
GenericArgsProhibited,
|
||||
];
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -388,6 +400,12 @@ pub struct InvalidCast {
|
|||
pub cast_ty: Type,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GenericArgsProhibited {
|
||||
pub args: InFile<AstPtr<Either<ast::GenericArgList, ast::ParamList>>>,
|
||||
pub reason: GenericArgsProhibitedReason,
|
||||
}
|
||||
|
||||
impl AnyDiagnostic {
|
||||
pub(crate) fn body_validation_diagnostic(
|
||||
db: &dyn HirDatabase,
|
||||
|
@ -527,6 +545,7 @@ impl AnyDiagnostic {
|
|||
db: &dyn HirDatabase,
|
||||
def: DefWithBodyId,
|
||||
d: &InferenceDiagnostic,
|
||||
outer_types_source_map: &TypesSourceMap,
|
||||
source_map: &hir_def::body::BodySourceMap,
|
||||
) -> Option<AnyDiagnostic> {
|
||||
let expr_syntax = |expr| {
|
||||
|
@ -640,6 +659,36 @@ impl AnyDiagnostic {
|
|||
let cast_ty = Type::new(db, def, cast_ty.clone());
|
||||
InvalidCast { expr, error: *error, expr_ty, cast_ty }.into()
|
||||
}
|
||||
InferenceDiagnostic::TyDiagnostic { source, diag } => {
|
||||
let source_map = match source {
|
||||
InferenceTyDiagnosticSource::Body => &source_map.types,
|
||||
InferenceTyDiagnosticSource::Signature => outer_types_source_map,
|
||||
};
|
||||
let source = match diag.source {
|
||||
Either::Left(type_ref_id) => {
|
||||
let Ok(source) = source_map.type_syntax(type_ref_id) else {
|
||||
stdx::never!("error on synthetic type syntax");
|
||||
return None;
|
||||
};
|
||||
source
|
||||
}
|
||||
Either::Right(source) => source,
|
||||
};
|
||||
let syntax = || source.value.to_node(&db.parse_or_expand(source.file_id));
|
||||
match diag.kind {
|
||||
TyLoweringDiagnosticKind::GenericArgsProhibited { segment, reason } => {
|
||||
let ast::Type::PathType(syntax) = syntax() else { return None };
|
||||
let segment = hir_segment_to_ast_segment(&syntax.path()?, segment)?;
|
||||
let args = if let Some(generics) = segment.generic_arg_list() {
|
||||
AstPtr::new(&generics).wrap_left()
|
||||
} else {
|
||||
AstPtr::new(&segment.param_list()?).wrap_right()
|
||||
};
|
||||
let args = source.with_value(args);
|
||||
GenericArgsProhibited { args, reason }.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,12 +20,11 @@
|
|||
#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
|
||||
#![recursion_limit = "512"]
|
||||
|
||||
mod semantics;
|
||||
mod source_analyzer;
|
||||
|
||||
mod attrs;
|
||||
mod from_id;
|
||||
mod has_source;
|
||||
mod semantics;
|
||||
mod source_analyzer;
|
||||
|
||||
pub mod db;
|
||||
pub mod diagnostics;
|
||||
|
@ -54,6 +53,7 @@ use hir_def::{
|
|||
path::ImportAlias,
|
||||
per_ns::PerNs,
|
||||
resolver::{HasResolver, Resolver},
|
||||
type_ref::TypesSourceMap,
|
||||
AssocItemId, AssocItemLoc, AttrDefId, CallableDefId, ConstId, ConstParamId, CrateRootModuleId,
|
||||
DefWithBodyId, EnumId, EnumVariantId, ExternCrateId, FunctionId, GenericDefId, GenericParamId,
|
||||
HasModule, ImplId, InTypeConstId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup,
|
||||
|
@ -1802,6 +1802,25 @@ impl DefWithBody {
|
|||
let krate = self.module(db).id.krate();
|
||||
|
||||
let (body, source_map) = db.body_with_source_map(self.into());
|
||||
let item_tree_source_maps;
|
||||
let outer_types_source_map = match self {
|
||||
DefWithBody::Function(function) => {
|
||||
let function = function.id.lookup(db.upcast()).id;
|
||||
item_tree_source_maps = function.item_tree_with_source_map(db.upcast()).1;
|
||||
item_tree_source_maps.function(function.value).item()
|
||||
}
|
||||
DefWithBody::Static(statik) => {
|
||||
let statik = statik.id.lookup(db.upcast()).id;
|
||||
item_tree_source_maps = statik.item_tree_with_source_map(db.upcast()).1;
|
||||
item_tree_source_maps.statik(statik.value)
|
||||
}
|
||||
DefWithBody::Const(konst) => {
|
||||
let konst = konst.id.lookup(db.upcast()).id;
|
||||
item_tree_source_maps = konst.item_tree_with_source_map(db.upcast()).1;
|
||||
item_tree_source_maps.konst(konst.value)
|
||||
}
|
||||
DefWithBody::Variant(_) | DefWithBody::InTypeConst(_) => &TypesSourceMap::EMPTY,
|
||||
};
|
||||
|
||||
for (_, def_map) in body.blocks(db.upcast()) {
|
||||
Module { id: def_map.module_id(DefMap::ROOT) }.diagnostics(db, acc, style_lints);
|
||||
|
@ -1861,7 +1880,13 @@ impl DefWithBody {
|
|||
|
||||
let infer = db.infer(self.into());
|
||||
for d in &infer.diagnostics {
|
||||
acc.extend(AnyDiagnostic::inference_diagnostic(db, self.into(), d, &source_map));
|
||||
acc.extend(AnyDiagnostic::inference_diagnostic(
|
||||
db,
|
||||
self.into(),
|
||||
d,
|
||||
outer_types_source_map,
|
||||
&source_map,
|
||||
));
|
||||
}
|
||||
|
||||
for (pat_or_expr, mismatch) in infer.type_mismatches() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue