@@ -401,6 +401,25 @@ final class DeclarationTests: XCTestCase {
401401 func withParameters() {}
402402 }
403403 """ ,
404+ substructure: Syntax ( FunctionDeclSyntax (
405+ attributes: nil ,
406+ modifiers: nil ,
407+ funcKeyword: . funcKeyword( ) ,
408+ identifier: . identifier( " withoutParameters " ) ,
409+ genericParameterClause: nil ,
410+ signature: FunctionSignatureSyntax (
411+ input: ParameterClauseSyntax (
412+ leftParen: . leftParenToken( presence: . missing) ,
413+ parameterList: FunctionParameterListSyntax ( [ ] ) ,
414+ rightParen: . rightParenToken( presence: . missing)
415+ ) ,
416+ asyncOrReasyncKeyword: nil ,
417+ throwsOrRethrowsKeyword: nil ,
418+ output: nil
419+ ) ,
420+ genericWhereClause: nil ,
421+ body: nil
422+ ) ) ,
404423 diagnostics: [
405424 DiagnosticSpec ( message: " Expected argument list in function declaration " )
406425 ]
@@ -516,6 +535,146 @@ final class DeclarationTests: XCTestCase {
516535 ]
517536 )
518537 }
538+
539+ func testRecoverOneExtraLabel( ) {
540+ AssertParse (
541+ " (first second #^DIAG^#third: Int) " ,
542+ { $0. parseFunctionSignature ( ) } ,
543+ substructure: Syntax ( FunctionParameterSyntax (
544+ attributes: nil ,
545+ firstName: TokenSyntax . identifier ( " first " ) ,
546+ secondName: TokenSyntax . identifier ( " second " ) ,
547+ UnexpectedNodesSyntax ( [ Syntax ( TokenSyntax . identifier ( " third " ) ) ] ) ,
548+ colon: TokenSyntax . colonToken ( ) ,
549+ type: TypeSyntax ( SimpleTypeIdentifierSyntax ( name: TokenSyntax . identifier ( " Int " ) , genericArgumentClause: nil ) ) ,
550+ ellipsis: nil ,
551+ defaultArgument: nil ,
552+ trailingComma: nil
553+ ) ) ,
554+ diagnostics: [
555+ DiagnosticSpec ( message: " Unexpected text 'third' found in function parameter " )
556+ ]
557+ )
558+ }
559+
560+ func testRecoverTwoExtraLabels( ) {
561+ AssertParse (
562+ " (first second #^DIAG^#third fourth: Int) " ,
563+ { $0. parseFunctionSignature ( ) } ,
564+ substructure: Syntax ( FunctionParameterSyntax (
565+ attributes: nil ,
566+ firstName: TokenSyntax . identifier ( " first " ) ,
567+ secondName: TokenSyntax . identifier ( " second " ) ,
568+ UnexpectedNodesSyntax ( [ Syntax ( TokenSyntax . identifier ( " third " ) ) , Syntax ( TokenSyntax . identifier ( " fourth " ) ) ] ) ,
569+ colon: TokenSyntax . colonToken ( ) ,
570+ type: TypeSyntax ( SimpleTypeIdentifierSyntax ( name: TokenSyntax . identifier ( " Int " ) , genericArgumentClause: nil ) ) ,
571+ ellipsis: nil ,
572+ defaultArgument: nil ,
573+ trailingComma: nil
574+ ) ) ,
575+ diagnostics: [
576+ DiagnosticSpec ( message: " Unexpected text 'third fourth' found in function parameter " )
577+ ]
578+ )
579+ }
580+
581+ func testDontRecoverFromDeclKeyword( ) {
582+ AssertParse (
583+ " func foo(first second #^MISSING_COLON^#third #^MISSING_RPAREN^#struct#^MISSING_IDENTIFIER^##^BRACES^#: Int) {} " ,
584+ substructure: Syntax ( FunctionParameterSyntax (
585+ attributes: nil ,
586+ firstName: . identifier( " first " ) ,
587+ secondName: . identifier( " second " ) ,
588+ colon: . colonToken( presence: . missing) ,
589+ type: TypeSyntax ( SimpleTypeIdentifierSyntax ( name: . identifier( " third " ) , genericArgumentClause: nil ) ) ,
590+ ellipsis: nil ,
591+ defaultArgument: nil ,
592+ trailingComma: nil
593+ ) ) ,
594+ diagnostics: [
595+ DiagnosticSpec ( locationMarker: " MISSING_COLON " , message: " Expected ':' in function parameter " ) ,
596+ DiagnosticSpec ( locationMarker: " MISSING_RPAREN " , message: " Expected ')' to end parameter clause " ) ,
597+ // FIXME: We should issues something like "Expected identifier in declaration"
598+ DiagnosticSpec ( locationMarker: " MISSING_IDENTIFIER " , message: " Expected '' in declaration " ) ,
599+ DiagnosticSpec ( locationMarker: " BRACES " , message: " Expected '{' " ) ,
600+ DiagnosticSpec ( locationMarker: " BRACES " , message: " Expected '}' " ) ,
601+ ]
602+ )
603+ }
604+
605+ func testRecoverFromParens( ) {
606+ AssertParse (
607+ " (first second #^DIAG^#[third fourth]: Int) " ,
608+ { $0. parseFunctionSignature ( ) } ,
609+ substructure: Syntax ( FunctionParameterSyntax (
610+ attributes: nil ,
611+ firstName: TokenSyntax . identifier ( " first " ) ,
612+ secondName: TokenSyntax . identifier ( " second " ) ,
613+ UnexpectedNodesSyntax ( [
614+ Syntax ( TokenSyntax . leftSquareBracketToken ( ) ) ,
615+ Syntax ( TokenSyntax . identifier ( " third " ) ) ,
616+ Syntax ( TokenSyntax . identifier ( " fourth " ) ) ,
617+ Syntax ( TokenSyntax . rightSquareBracketToken ( ) )
618+ ] ) ,
619+ colon: TokenSyntax . colonToken ( ) ,
620+ type: TypeSyntax ( SimpleTypeIdentifierSyntax ( name: TokenSyntax . identifier ( " Int " ) , genericArgumentClause: nil ) ) ,
621+ ellipsis: nil ,
622+ defaultArgument: nil ,
623+ trailingComma: nil
624+ ) ) ,
625+ diagnostics: [
626+ DiagnosticSpec ( message: " Unexpected text '[third fourth]' found in function parameter " )
627+ ]
628+ )
629+ }
630+
631+ func testDontRecoverFromUnbalancedParens( ) {
632+ AssertParse (
633+ " func foo(first second #^COLON^#[third #^RSQUARE_COLON^#fourth: Int) {} " ,
634+ substructure: Syntax ( FunctionParameterSyntax (
635+ attributes: nil ,
636+ firstName: TokenSyntax . identifier ( " first " ) ,
637+ secondName: TokenSyntax . identifier ( " second " ) ,
638+ colon: TokenSyntax ( . colon, presence: . missing) ,
639+ type: TypeSyntax ( ArrayTypeSyntax (
640+ leftSquareBracket: TokenSyntax . leftSquareBracketToken ( ) ,
641+ elementType: TypeSyntax ( SimpleTypeIdentifierSyntax ( name: TokenSyntax . identifier ( " third " ) , genericArgumentClause: nil ) ) ,
642+ rightSquareBracket: TokenSyntax ( . rightSquareBracket, presence: . missing)
643+ ) ) ,
644+ ellipsis: nil ,
645+ defaultArgument: nil ,
646+ trailingComma: nil
647+ ) ) ,
648+ diagnostics: [
649+ DiagnosticSpec ( locationMarker: " COLON " , message: " Expected ':' in function parameter " ) ,
650+ DiagnosticSpec ( locationMarker: " RSQUARE_COLON " , message: " Expected ']' to end type " ) ,
651+ DiagnosticSpec ( locationMarker: " RSQUARE_COLON " , message: " Expected ')' to end parameter clause " ) ,
652+ ]
653+ )
654+ }
655+
656+ func testDontRecoverIfNewlineIsBeforeColon( ) {
657+ AssertParse (
658+ """
659+ func foo(first second #^COLON^#third#^RPAREN^#
660+ : Int) {}
661+ """ ,
662+ substructure: Syntax ( FunctionParameterSyntax (
663+ attributes: nil ,
664+ firstName: TokenSyntax . identifier ( " first " ) ,
665+ secondName: TokenSyntax . identifier ( " second " ) ,
666+ colon: TokenSyntax ( . colon, presence: . missing) ,
667+ type: TypeSyntax ( SimpleTypeIdentifierSyntax ( name: TokenSyntax . identifier ( " third " ) , genericArgumentClause: nil ) ) ,
668+ ellipsis: nil ,
669+ defaultArgument: nil ,
670+ trailingComma: nil
671+ ) ) ,
672+ diagnostics: [
673+ DiagnosticSpec ( locationMarker: " COLON " , message: " Expected ':' in function parameter " ) ,
674+ DiagnosticSpec ( locationMarker: " RPAREN " , message: " Expected ')' to end parameter clause " ) ,
675+ ]
676+ )
677+ }
519678}
520679
521680extension Parser . DeclAttributes {
0 commit comments