Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #19450 from Veykril/push-vwrmzqmnvlxk
minor: Simplify impl-ty parse validation
Lukas Wirth 2025-03-25
parent 749fde9 · parent 389323c · commit b057d82
-rw-r--r--crates/syntax/src/validation.rs123
-rw-r--r--crates/syntax/test_data/parser/validation/dangling_impl.rast2
-rw-r--r--crates/syntax/test_data/parser/validation/dangling_impl_reference.rast2
-rw-r--r--crates/syntax/test_data/parser/validation/impl_trait_lifetime_only.rast2
4 files changed, 74 insertions, 55 deletions
diff --git a/crates/syntax/src/validation.rs b/crates/syntax/src/validation.rs
index 12894a2bda..6397b04481 100644
--- a/crates/syntax/src/validation.rs
+++ b/crates/syntax/src/validation.rs
@@ -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",
- ty.syntax().text_range(),
- ));
- return;
- };
-
- let bounds: Vec<_> = bound_list.bounds().collect();
+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();
- if !bounds.iter().any(|b| !matches!(b.kind(), ast::TypeBoundKind::Lifetime(_))) {
- errors.push(SyntaxError::new(
- "At least one trait must be specified",
+ match no_bounds {
+ true => Some(SyntaxError::new(
+ "At least one trait is required for an object type",
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
}
}
diff --git a/crates/syntax/test_data/parser/validation/dangling_impl.rast b/crates/syntax/test_data/parser/validation/dangling_impl.rast
index 2db07ae12a..c337ee8bbf 100644
--- a/crates/syntax/test_data/parser/validation/dangling_impl.rast
+++ b/crates/syntax/test_data/parser/validation/dangling_impl.rast
@@ -20,4 +20,4 @@ [email protected]
-error 8..12: At least one trait must be specified
+error 8..12: At least one trait is required for an object type
diff --git a/crates/syntax/test_data/parser/validation/dangling_impl_reference.rast b/crates/syntax/test_data/parser/validation/dangling_impl_reference.rast
index dbe6535ac6..cb73cb4e05 100644
--- a/crates/syntax/test_data/parser/validation/dangling_impl_reference.rast
+++ b/crates/syntax/test_data/parser/validation/dangling_impl_reference.rast
@@ -22,4 +22,4 @@ [email protected]
-error 9..13: At least one trait must be specified
+error 9..13: At least one trait is required for an object type
diff --git a/crates/syntax/test_data/parser/validation/impl_trait_lifetime_only.rast b/crates/syntax/test_data/parser/validation/impl_trait_lifetime_only.rast
index 98aa862bc8..ed938d63db 100644
--- a/crates/syntax/test_data/parser/validation/impl_trait_lifetime_only.rast
+++ b/crates/syntax/test_data/parser/validation/impl_trait_lifetime_only.rast
@@ -26,4 +26,4 @@ [email protected]
-error 9..16: At least one trait must be specified
+error 9..16: At least one trait is required for an object type