@@ -843,17 +843,26 @@ ParserResult<TupleTypeRepr> Parser::parseTypeTupleBody() {
843
843
[&] () -> ParserStatus {
844
844
TupleTypeReprElement element;
845
845
846
- // If this is a deprecated use of the inout marker in an argument list,
847
- // consume the inout.
848
- SourceLoc SpecifierLoc;
849
- consumeIf (tok::kw_inout, SpecifierLoc);
846
+ // 'inout' here can be a obsoleted use of the marker in an argument list,
847
+ // consume it in backtracking context so we can determine it's really a
848
+ // deprecated use of it.
849
+ llvm::Optional<BacktrackingScope> Backtracking;
850
+ SourceLoc ObsoletedInOutLoc;
851
+ if (Tok.is (tok::kw_inout)) {
852
+ Backtracking.emplace (*this );
853
+ ObsoletedInOutLoc = consumeToken (tok::kw_inout);
854
+ }
850
855
851
856
// If the tuple element starts with a potential argument label followed by a
852
857
// ':' or another potential argument label, then the identifier is an
853
858
// element tag, and it is followed by a type annotation.
854
859
if (Tok.canBeArgumentLabel () &&
855
860
(peekToken ().is (tok::colon) || peekToken ().canBeArgumentLabel ())) {
856
- // Consume the name
861
+ if (Backtracking)
862
+ // Found obsoleted 'inout' use.
863
+ Backtracking->cancelBacktrack ();
864
+
865
+ // Consume a name.
857
866
if (!Tok.is (tok::kw__))
858
867
element.Name = Context.getIdentifier (Tok.getText ());
859
868
element.NameLoc = consumeToken ();
@@ -866,50 +875,52 @@ ParserResult<TupleTypeRepr> Parser::parseTypeTupleBody() {
866
875
}
867
876
868
877
// Consume the ':'.
869
- SourceLoc colonLoc;
870
- if (Tok.is (tok::colon)) {
871
- colonLoc = consumeToken ();
872
- } else {
878
+ if (!consumeIf (tok::colon, element.ColonLoc ))
873
879
diagnose (Tok, diag::expected_parameter_colon);
874
- }
875
-
876
- SourceLoc postColonLoc = Tok.getLoc ();
877
-
878
- // Parse the type annotation.
879
- auto type = parseType (diag::expected_type);
880
- if (type.hasCodeCompletion ())
881
- return makeParserCodeCompletionStatus ();
882
- if (type.isNull ())
883
- return makeParserError ();
884
- element.Type = type.get ();
885
-
886
- // Complain obsoleted 'inout' position; (inout name: Ty)
887
- if (SpecifierLoc.isValid () && !isa<InOutTypeRepr>(element.Type ))
888
- diagnose (Tok.getLoc (), diag::inout_as_attr_disallowed, " 'inout'" )
889
- .fixItRemove (SpecifierLoc)
890
- .fixItInsert (postColonLoc, " inout " );
891
- } else {
892
- // Otherwise, this has to be a type.
893
- auto type = parseType ();
894
- if (type.hasCodeCompletion ())
895
- return makeParserCodeCompletionStatus ();
896
- if (type.isNull ())
897
- return makeParserError ();
898
- element.Type = type.get ();
880
+ } else if (Backtracking) {
881
+ // If we don't have labels, 'inout' is not a deprecated use.
882
+ ObsoletedInOutLoc = SourceLoc ();
899
883
}
884
+ Backtracking.reset ();
885
+
886
+ // Parse the type annotation.
887
+ auto type = parseType (diag::expected_type);
888
+ if (type.hasCodeCompletion ())
889
+ return makeParserCodeCompletionStatus ();
890
+ if (type.isNull ())
891
+ return makeParserError ();
892
+ element.Type = type.get ();
900
893
901
- // If an 'inout' marker was specified, build inout type.
902
- // Note that we bury the inout locator within the named locator.
903
- // This is weird but required by Sema apparently.
904
- if (SpecifierLoc. isValid ( )) {
905
- if (isa<InOutTypeRepr>(element. Type ) || isa<SharedTypeRepr>(element. Type ))
894
+ // Complain obsoleted 'inout' position; ( inout name: Ty)
895
+ if (ObsoletedInOutLoc. isValid ()) {
896
+ if (isa<InOutTypeRepr>(element. Type ) ||
897
+ isa<SharedTypeRepr>(element. Type )) {
898
+ // If the parsed type is already a inout type et al, just remove it.
906
899
diagnose (Tok, diag::parameter_specifier_repeated)
907
- .fixItRemove (SpecifierLoc);
908
- else
909
- element.Type = new (Context) InOutTypeRepr (element.Type , SpecifierLoc);
900
+ .fixItRemove (ObsoletedInOutLoc);
901
+ } else {
902
+ diagnose (ObsoletedInOutLoc, diag::inout_as_attr_disallowed, " 'inout'" )
903
+ .fixItRemove (ObsoletedInOutLoc)
904
+ .fixItInsert (element.Type ->getStartLoc (), " inout " );
905
+ // Build inout type. Note that we bury the inout locator within the
906
+ // named locator. This is weird but required by Sema apparently.
907
+ element.Type =
908
+ new (Context) InOutTypeRepr (element.Type , ObsoletedInOutLoc);
909
+ }
910
910
}
911
911
912
- ElementsR.push_back (element);
912
+ // Parse optional '...'.
913
+ if (Tok.isEllipsis ()) {
914
+ auto ElementEllipsisLoc = consumeToken ();
915
+ if (EllipsisLoc.isInvalid ()) {
916
+ EllipsisLoc = ElementEllipsisLoc;
917
+ EllipsisIdx = ElementsR.size ();
918
+ } else {
919
+ diagnose (ElementEllipsisLoc, diag::multiple_ellipsis_in_tuple)
920
+ .highlight (EllipsisLoc)
921
+ .fixItRemove (ElementEllipsisLoc);
922
+ }
923
+ }
913
924
914
925
// Parse '= expr' here so we can complain about it directly, rather
915
926
// than dying when we see it.
@@ -921,27 +932,14 @@ ParserResult<TupleTypeRepr> Parser::parseTypeTupleBody() {
921
932
inFlight.fixItRemove (SourceRange (equalLoc, init.get ()->getEndLoc ()));
922
933
}
923
934
924
- if (Tok.isEllipsis ()) {
925
- if (EllipsisLoc.isValid ()) {
926
- diagnose (Tok, diag::multiple_ellipsis_in_tuple)
927
- .highlight (EllipsisLoc)
928
- .fixItRemove (Tok.getLoc ());
929
- (void )consumeToken ();
930
- } else {
931
- EllipsisLoc = consumeToken ();
932
- EllipsisIdx = ElementsR.size () - 1 ;
933
- }
934
- }
935
- if (Tok.is (tok::comma)) {
935
+ // Record the ',' location.
936
+ if (Tok.is (tok::comma))
936
937
element.TrailingCommaLoc = Tok.getLoc ();
937
- }
938
+
939
+ ElementsR.push_back (element);
938
940
return makeParserSuccess ();
939
941
});
940
942
941
- if (EllipsisLoc.isValid () && ElementsR.empty ()) {
942
- EllipsisLoc = SourceLoc ();
943
- }
944
-
945
943
if (EllipsisLoc.isInvalid ())
946
944
EllipsisIdx = ElementsR.size ();
947
945
0 commit comments