diff options
| author | Lukas Wirth <lukastw97@gmail.com> | 2025-03-25 09:31:34 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-03-25 09:31:34 +0000 |
| commit | e142e4e9c9b8d6f2437e22c84741ec787eb4d101 (patch) | |
| tree | a112919c67abc040f82c7430474d2aaed485788f /src | |
| parent | 69471d6f0f18fa584607566a38aa6c4666863931 (diff) | |
| parent | a0f47f070efe585642e2f72eae03aba7e7e004ac (diff) | |
| download | rust-e142e4e9c9b8d6f2437e22c84741ec787eb4d101.tar.gz rust-e142e4e9c9b8d6f2437e22c84741ec787eb4d101.zip | |
Merge pull request #19450 from Veykril/push-vwrmzqmnvlxk
minor: Simplify impl-ty parse validation
Diffstat (limited to 'src')
4 files changed, 74 insertions, 55 deletions
diff --git a/src/tools/rust-analyzer/crates/syntax/src/validation.rs b/src/tools/rust-analyzer/crates/syntax/src/validation.rs index 12894a2bda8..6397b04481f 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/validation.rs +++ b/src/tools/rust-analyzer/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/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/dangling_impl.rast b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/dangling_impl.rast index 2db07ae12a9..c337ee8bbf4 100644 --- a/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/dangling_impl.rast +++ b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/dangling_impl.rast @@ -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 diff --git a/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/dangling_impl_reference.rast b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/dangling_impl_reference.rast index dbe6535ac66..cb73cb4e058 100644 --- a/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/dangling_impl_reference.rast +++ b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/dangling_impl_reference.rast @@ -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 diff --git a/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/impl_trait_lifetime_only.rast b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/impl_trait_lifetime_only.rast index 98aa862bc88..ed938d63db4 100644 --- a/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/impl_trait_lifetime_only.rast +++ b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/impl_trait_lifetime_only.rast @@ -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 |
