|
4 | 4 |
|
5 | 5 | mod block; |
6 | 6 |
|
| 7 | +use itertools::Itertools; |
7 | 8 | use rowan::Direction; |
8 | 9 | use rustc_lexer::unescape::{self, Mode, unescape_mixed, unescape_unicode}; |
9 | 10 |
|
@@ -37,7 +38,8 @@ pub(crate) fn validate(root: &SyntaxNode, errors: &mut Vec<SyntaxError>) { |
37 | 38 | ast::FnPtrType(it) => validate_trait_object_fn_ptr_ret_ty(it, errors), |
38 | 39 | ast::MacroRules(it) => validate_macro_rules(it, errors), |
39 | 40 | ast::LetExpr(it) => validate_let_expr(it, errors), |
40 | | - ast::ImplTraitType(it) => validate_impl_object_ty(it, errors), |
| 41 | + ast::DynTraitType(it) => errors.extend(validate_trait_object_ty(it)), |
| 42 | + ast::ImplTraitType(it) => errors.extend(validate_impl_object_ty(it)), |
41 | 43 | _ => (), |
42 | 44 | } |
43 | 45 | } |
@@ -316,87 +318,104 @@ fn validate_path_keywords(segment: ast::PathSegment, errors: &mut Vec<SyntaxErro |
316 | 318 | } |
317 | 319 |
|
318 | 320 | fn validate_trait_object_ref_ty(ty: ast::RefType, errors: &mut Vec<SyntaxError>) { |
319 | | - if let Some(ast::Type::DynTraitType(ty)) = ty.ty() { |
320 | | - if let Some(err) = validate_trait_object_ty(ty) { |
321 | | - errors.push(err); |
| 321 | + match ty.ty() { |
| 322 | + Some(ast::Type::DynTraitType(ty)) => { |
| 323 | + if let Some(err) = validate_trait_object_ty_plus(ty) { |
| 324 | + errors.push(err); |
| 325 | + } |
| 326 | + } |
| 327 | + Some(ast::Type::ImplTraitType(ty)) => { |
| 328 | + if let Some(err) = validate_impl_object_ty_plus(ty) { |
| 329 | + errors.push(err); |
| 330 | + } |
322 | 331 | } |
| 332 | + _ => (), |
323 | 333 | } |
324 | 334 | } |
325 | 335 |
|
326 | 336 | fn validate_trait_object_ptr_ty(ty: ast::PtrType, errors: &mut Vec<SyntaxError>) { |
327 | | - if let Some(ast::Type::DynTraitType(ty)) = ty.ty() { |
328 | | - if let Some(err) = validate_trait_object_ty(ty) { |
329 | | - errors.push(err); |
| 337 | + match ty.ty() { |
| 338 | + Some(ast::Type::DynTraitType(ty)) => { |
| 339 | + if let Some(err) = validate_trait_object_ty_plus(ty) { |
| 340 | + errors.push(err); |
| 341 | + } |
330 | 342 | } |
| 343 | + Some(ast::Type::ImplTraitType(ty)) => { |
| 344 | + if let Some(err) = validate_impl_object_ty_plus(ty) { |
| 345 | + errors.push(err); |
| 346 | + } |
| 347 | + } |
| 348 | + _ => (), |
331 | 349 | } |
332 | 350 | } |
333 | 351 |
|
334 | 352 | fn validate_trait_object_fn_ptr_ret_ty(ty: ast::FnPtrType, errors: &mut Vec<SyntaxError>) { |
335 | | - if let Some(ast::Type::DynTraitType(ty)) = ty.ret_type().and_then(|ty| ty.ty()) { |
336 | | - if let Some(err) = validate_trait_object_ty(ty) { |
337 | | - errors.push(err); |
| 353 | + match ty.ret_type().and_then(|ty| ty.ty()) { |
| 354 | + Some(ast::Type::DynTraitType(ty)) => { |
| 355 | + if let Some(err) = validate_trait_object_ty_plus(ty) { |
| 356 | + errors.push(err); |
| 357 | + } |
| 358 | + } |
| 359 | + Some(ast::Type::ImplTraitType(ty)) => { |
| 360 | + if let Some(err) = validate_impl_object_ty_plus(ty) { |
| 361 | + errors.push(err); |
| 362 | + } |
338 | 363 | } |
| 364 | + _ => (), |
339 | 365 | } |
340 | 366 | } |
341 | 367 |
|
342 | 368 | fn validate_trait_object_ty(ty: ast::DynTraitType) -> Option<SyntaxError> { |
343 | 369 | let tbl = ty.type_bound_list()?; |
344 | | - let bounds_count = tbl.bounds().count(); |
| 370 | + let no_bounds = tbl.bounds().filter_map(|it| it.ty()).next().is_none(); |
345 | 371 |
|
346 | | - match bounds_count { |
347 | | - 0 => Some(SyntaxError::new( |
| 372 | + match no_bounds { |
| 373 | + true => Some(SyntaxError::new( |
348 | 374 | "At least one trait is required for an object type", |
349 | 375 | ty.syntax().text_range(), |
350 | 376 | )), |
351 | | - _ if bounds_count > 1 => { |
352 | | - let dyn_token = ty.dyn_token()?; |
353 | | - let preceding_token = |
354 | | - algo::skip_trivia_token(dyn_token.prev_token()?, Direction::Prev)?; |
355 | | - |
356 | | - if !matches!(preceding_token.kind(), T!['('] | T![<] | T![=]) { |
357 | | - return Some(SyntaxError::new("ambiguous `+` in a type", ty.syntax().text_range())); |
358 | | - } |
359 | | - None |
360 | | - } |
361 | | - _ => None, |
| 377 | + false => None, |
362 | 378 | } |
363 | 379 | } |
364 | 380 |
|
365 | | -fn validate_impl_object_ty(ty: ast::ImplTraitType, errors: &mut Vec<SyntaxError>) { |
366 | | - let Some(bound_list) = ty.type_bound_list() else { |
367 | | - errors.push(SyntaxError::new( |
368 | | - "At least one trait must be specified", |
369 | | - ty.syntax().text_range(), |
370 | | - )); |
371 | | - return; |
372 | | - }; |
373 | | - |
374 | | - let bounds: Vec<_> = bound_list.bounds().collect(); |
| 381 | +fn validate_impl_object_ty(ty: ast::ImplTraitType) -> Option<SyntaxError> { |
| 382 | + let tbl = ty.type_bound_list()?; |
| 383 | + let no_bounds = tbl.bounds().filter_map(|it| it.ty()).next().is_none(); |
375 | 384 |
|
376 | | - if !bounds.iter().any(|b| !matches!(b.kind(), ast::TypeBoundKind::Lifetime(_))) { |
377 | | - errors.push(SyntaxError::new( |
378 | | - "At least one trait must be specified", |
| 385 | + match no_bounds { |
| 386 | + true => Some(SyntaxError::new( |
| 387 | + "At least one trait is required for an object type", |
379 | 388 | ty.syntax().text_range(), |
380 | | - )); |
381 | | - return; |
| 389 | + )), |
| 390 | + false => None, |
382 | 391 | } |
| 392 | +} |
383 | 393 |
|
384 | | - if bounds.len() == 1 { |
385 | | - return; |
| 394 | +// FIXME: This is not a validation error, this is a context dependent parse error |
| 395 | +fn validate_trait_object_ty_plus(ty: ast::DynTraitType) -> Option<SyntaxError> { |
| 396 | + let dyn_token = ty.dyn_token()?; |
| 397 | + let preceding_token = algo::skip_trivia_token(dyn_token.prev_token()?, Direction::Prev)?; |
| 398 | + let tbl = ty.type_bound_list()?; |
| 399 | + let more_than_one_bound = tbl.bounds().next_tuple::<(_, _)>().is_some(); |
| 400 | + |
| 401 | + if more_than_one_bound && !matches!(preceding_token.kind(), T!['('] | T![<] | T![=]) { |
| 402 | + Some(SyntaxError::new("ambiguous `+` in a type", ty.syntax().text_range())) |
| 403 | + } else { |
| 404 | + None |
386 | 405 | } |
| 406 | +} |
387 | 407 |
|
388 | | - let Some(preceding_token) = ty |
389 | | - .impl_token() |
390 | | - .and_then(|token| token.prev_token()) |
391 | | - .and_then(|prev| algo::skip_trivia_token(prev, Direction::Prev)) |
392 | | - else { |
393 | | - return; |
394 | | - }; |
| 408 | +// FIXME: This is not a validation error, this is a context dependent parse error |
| 409 | +fn validate_impl_object_ty_plus(ty: ast::ImplTraitType) -> Option<SyntaxError> { |
| 410 | + let dyn_token = ty.impl_token()?; |
| 411 | + let preceding_token = algo::skip_trivia_token(dyn_token.prev_token()?, Direction::Prev)?; |
| 412 | + let tbl = ty.type_bound_list()?; |
| 413 | + let more_than_one_bound = tbl.bounds().next_tuple::<(_, _)>().is_some(); |
395 | 414 |
|
396 | | - if !matches!(preceding_token.kind(), T!['('] | T![<] | T![=]) |
397 | | - && matches!(preceding_token.kind(), T![&]) |
398 | | - { |
399 | | - errors.push(SyntaxError::new("ambiguous `+` in a type", ty.syntax().text_range())); |
| 415 | + if more_than_one_bound && !matches!(preceding_token.kind(), T!['('] | T![<] | T![=]) { |
| 416 | + Some(SyntaxError::new("ambiguous `+` in a type", ty.syntax().text_range())) |
| 417 | + } else { |
| 418 | + None |
400 | 419 | } |
401 | 420 | } |
402 | 421 |
|
|
0 commit comments