|
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