mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-08-04 10:50:15 +00:00
minor: Simplify impl-ty parse validation
This commit is contained in:
parent
749fde9017
commit
389323ca09
4 changed files with 75 additions and 56 deletions
|
@ -4,6 +4,7 @@
|
|||
|
||||
mod block;
|
||||
|
||||
use itertools::Itertools;
|
||||
use rowan::Direction;
|
||||
use rustc_lexer::unescape::{self, Mode, unescape_mixed, unescape_unicode};
|
||||
|
||||
|
@ -37,7 +38,8 @@ pub(crate) fn validate(root: &SyntaxNode, errors: &mut Vec<SyntaxError>) {
|
|||
ast::FnPtrType(it) => validate_trait_object_fn_ptr_ret_ty(it, errors),
|
||||
ast::MacroRules(it) => validate_macro_rules(it, errors),
|
||||
ast::LetExpr(it) => validate_let_expr(it, errors),
|
||||
ast::ImplTraitType(it) => validate_impl_object_ty(it, errors),
|
||||
ast::DynTraitType(it) => errors.extend(validate_trait_object_ty(it)),
|
||||
ast::ImplTraitType(it) => errors.extend(validate_impl_object_ty(it)),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
@ -316,87 +318,104 @@ fn validate_path_keywords(segment: ast::PathSegment, errors: &mut Vec<SyntaxErro
|
|||
}
|
||||
|
||||
fn validate_trait_object_ref_ty(ty: ast::RefType, errors: &mut Vec<SyntaxError>) {
|
||||
if let Some(ast::Type::DynTraitType(ty)) = ty.ty() {
|
||||
if let Some(err) = validate_trait_object_ty(ty) {
|
||||
errors.push(err);
|
||||
match ty.ty() {
|
||||
Some(ast::Type::DynTraitType(ty)) => {
|
||||
if let Some(err) = validate_trait_object_ty_plus(ty) {
|
||||
errors.push(err);
|
||||
}
|
||||
}
|
||||
Some(ast::Type::ImplTraitType(ty)) => {
|
||||
if let Some(err) = validate_impl_object_ty_plus(ty) {
|
||||
errors.push(err);
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_trait_object_ptr_ty(ty: ast::PtrType, errors: &mut Vec<SyntaxError>) {
|
||||
if let Some(ast::Type::DynTraitType(ty)) = ty.ty() {
|
||||
if let Some(err) = validate_trait_object_ty(ty) {
|
||||
errors.push(err);
|
||||
match ty.ty() {
|
||||
Some(ast::Type::DynTraitType(ty)) => {
|
||||
if let Some(err) = validate_trait_object_ty_plus(ty) {
|
||||
errors.push(err);
|
||||
}
|
||||
}
|
||||
Some(ast::Type::ImplTraitType(ty)) => {
|
||||
if let Some(err) = validate_impl_object_ty_plus(ty) {
|
||||
errors.push(err);
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_trait_object_fn_ptr_ret_ty(ty: ast::FnPtrType, errors: &mut Vec<SyntaxError>) {
|
||||
if let Some(ast::Type::DynTraitType(ty)) = ty.ret_type().and_then(|ty| ty.ty()) {
|
||||
if let Some(err) = validate_trait_object_ty(ty) {
|
||||
errors.push(err);
|
||||
match ty.ret_type().and_then(|ty| ty.ty()) {
|
||||
Some(ast::Type::DynTraitType(ty)) => {
|
||||
if let Some(err) = validate_trait_object_ty_plus(ty) {
|
||||
errors.push(err);
|
||||
}
|
||||
}
|
||||
Some(ast::Type::ImplTraitType(ty)) => {
|
||||
if let Some(err) = validate_impl_object_ty_plus(ty) {
|
||||
errors.push(err);
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_trait_object_ty(ty: ast::DynTraitType) -> Option<SyntaxError> {
|
||||
let tbl = ty.type_bound_list()?;
|
||||
let bounds_count = tbl.bounds().count();
|
||||
let no_bounds = tbl.bounds().filter_map(|it| it.ty()).next().is_none();
|
||||
|
||||
match bounds_count {
|
||||
0 => Some(SyntaxError::new(
|
||||
match no_bounds {
|
||||
true => Some(SyntaxError::new(
|
||||
"At least one trait is required for an object type",
|
||||
ty.syntax().text_range(),
|
||||
)),
|
||||
_ if bounds_count > 1 => {
|
||||
let dyn_token = ty.dyn_token()?;
|
||||
let preceding_token =
|
||||
algo::skip_trivia_token(dyn_token.prev_token()?, Direction::Prev)?;
|
||||
|
||||
if !matches!(preceding_token.kind(), T!['('] | T![<] | T![=]) {
|
||||
return Some(SyntaxError::new("ambiguous `+` in a type", ty.syntax().text_range()));
|
||||
}
|
||||
None
|
||||
}
|
||||
_ => None,
|
||||
false => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_impl_object_ty(ty: ast::ImplTraitType, errors: &mut Vec<SyntaxError>) {
|
||||
let Some(bound_list) = ty.type_bound_list() else {
|
||||
errors.push(SyntaxError::new(
|
||||
"At least one trait must be specified",
|
||||
fn validate_impl_object_ty(ty: ast::ImplTraitType) -> Option<SyntaxError> {
|
||||
let tbl = ty.type_bound_list()?;
|
||||
let no_bounds = tbl.bounds().filter_map(|it| it.ty()).next().is_none();
|
||||
|
||||
match no_bounds {
|
||||
true => Some(SyntaxError::new(
|
||||
"At least one trait is required for an object type",
|
||||
ty.syntax().text_range(),
|
||||
));
|
||||
return;
|
||||
};
|
||||
|
||||
let bounds: Vec<_> = bound_list.bounds().collect();
|
||||
|
||||
if !bounds.iter().any(|b| !matches!(b.kind(), ast::TypeBoundKind::Lifetime(_))) {
|
||||
errors.push(SyntaxError::new(
|
||||
"At least one trait must be specified",
|
||||
ty.syntax().text_range(),
|
||||
));
|
||||
return;
|
||||
)),
|
||||
false => None,
|
||||
}
|
||||
}
|
||||
|
||||
if bounds.len() == 1 {
|
||||
return;
|
||||
// FIXME: This is not a validation error, this is a context dependent parse error
|
||||
fn validate_trait_object_ty_plus(ty: ast::DynTraitType) -> Option<SyntaxError> {
|
||||
let dyn_token = ty.dyn_token()?;
|
||||
let preceding_token = algo::skip_trivia_token(dyn_token.prev_token()?, Direction::Prev)?;
|
||||
let tbl = ty.type_bound_list()?;
|
||||
let more_than_one_bound = tbl.bounds().next_tuple::<(_, _)>().is_some();
|
||||
|
||||
if more_than_one_bound && !matches!(preceding_token.kind(), T!['('] | T![<] | T![=]) {
|
||||
Some(SyntaxError::new("ambiguous `+` in a type", ty.syntax().text_range()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
let Some(preceding_token) = ty
|
||||
.impl_token()
|
||||
.and_then(|token| token.prev_token())
|
||||
.and_then(|prev| algo::skip_trivia_token(prev, Direction::Prev))
|
||||
else {
|
||||
return;
|
||||
};
|
||||
// FIXME: This is not a validation error, this is a context dependent parse error
|
||||
fn validate_impl_object_ty_plus(ty: ast::ImplTraitType) -> Option<SyntaxError> {
|
||||
let dyn_token = ty.impl_token()?;
|
||||
let preceding_token = algo::skip_trivia_token(dyn_token.prev_token()?, Direction::Prev)?;
|
||||
let tbl = ty.type_bound_list()?;
|
||||
let more_than_one_bound = tbl.bounds().next_tuple::<(_, _)>().is_some();
|
||||
|
||||
if !matches!(preceding_token.kind(), T!['('] | T![<] | T![=])
|
||||
&& matches!(preceding_token.kind(), T![&])
|
||||
{
|
||||
errors.push(SyntaxError::new("ambiguous `+` in a type", ty.syntax().text_range()));
|
||||
if more_than_one_bound && !matches!(preceding_token.kind(), T!['('] | T![<] | T![=]) {
|
||||
Some(SyntaxError::new("ambiguous `+` in a type", ty.syntax().text_range()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,4 +20,4 @@ SOURCE_FILE@0..16
|
|||
STMT_LIST@14..16
|
||||
L_CURLY@14..15 "{"
|
||||
R_CURLY@15..16 "}"
|
||||
error 8..12: At least one trait must be specified
|
||||
error 8..12: At least one trait is required for an object type
|
||||
|
|
|
@ -22,4 +22,4 @@ SOURCE_FILE@0..17
|
|||
STMT_LIST@15..17
|
||||
L_CURLY@15..16 "{"
|
||||
R_CURLY@16..17 "}"
|
||||
error 9..13: At least one trait must be specified
|
||||
error 9..13: At least one trait is required for an object type
|
||||
|
|
|
@ -26,4 +26,4 @@ SOURCE_FILE@0..20
|
|||
STMT_LIST@18..20
|
||||
L_CURLY@18..19 "{"
|
||||
R_CURLY@19..20 "}"
|
||||
error 9..16: At least one trait must be specified
|
||||
error 9..16: At least one trait is required for an object type
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue