@@ -513,7 +513,7 @@ ParserResult<Expr> Parser::parseExprUnary(Diag<> Message, bool isExprBasic) {
513513 UnresolvedDeclRefExpr *Operator;
514514
515515 // First check to see if we have the start of a regex literal `/.../`.
516- tryLexRegexLiteral (/* mustBeRegex */ true );
516+ tryLexRegexLiteral (/* forUnappliedOperator */ false );
517517
518518 switch (Tok.getKind ()) {
519519 default :
@@ -880,56 +880,64 @@ UnresolvedDeclRefExpr *Parser::parseExprOperator() {
880880 return new (Context) UnresolvedDeclRefExpr (name, refKind, DeclNameLoc (loc));
881881}
882882
883- void Parser::tryLexRegexLiteral (bool mustBeRegex ) {
883+ void Parser::tryLexRegexLiteral (bool forUnappliedOperator ) {
884884 if (!Context.LangOpts .EnableBareSlashRegexLiterals )
885885 return ;
886886
887887 // Check to see if we have a regex literal `/.../`, optionally with a prefix
888888 // operator e.g `!/.../`.
889+ bool mustBeRegex = false ;
889890 switch (Tok.getKind ()) {
890891 case tok::oper_prefix:
892+ // Prefix operators may contain `/` characters, so this may not be a regex,
893+ // and as such need to make sure we have a closing `/`.
894+ break ;
891895 case tok::oper_binary_spaced:
892- case tok::oper_binary_unspaced: {
893- // Check to see if we have an operator containing '/'.
894- auto slashIdx = Tok.getText ().find (" /" );
895- if (slashIdx == StringRef::npos)
896- break ;
896+ case tok::oper_binary_unspaced:
897+ // When re-lexing for a unary expression, binary operators are always
898+ // invalid, so we can be confident in always lexing a regex literal.
899+ mustBeRegex = !forUnappliedOperator;
900+ break ;
901+ default :
902+ // We only re-lex regex literals for operator tokens.
903+ return ;
904+ }
897905
898- CancellableBacktrackingScope backtrack (*this );
899- {
900- Optional<Lexer::ForwardSlashRegexRAII> regexScope;
901- regexScope.emplace (*L, mustBeRegex);
902-
903- // Try re-lex as a `/.../` regex literal, this will split an operator if
904- // necessary.
905- L->restoreState (getParserPosition ().LS , /* enableDiagnostics*/ true );
906-
907- // If we didn't split a prefix operator, reset the regex lexing scope.
908- // Otherwise, we want to keep it in place for the next token.
909- auto didSplit = L->peekNextToken ().getLength () == slashIdx;
910- if (!didSplit)
911- regexScope.reset ();
912-
913- // Discard the current token, which will be replaced by the re-lexed
914- // token, which will either be a regex literal token, a prefix operator,
915- // or the original unchanged token.
916- discardToken ();
917-
918- // If we split a prefix operator from the regex literal, and are not sure
919- // whether this should be a regex, backtrack if we didn't end up lexing a
920- // regex literal.
921- if (didSplit && !mustBeRegex &&
922- !L->peekNextToken ().is (tok::regex_literal)) {
923- return ;
924- }
906+ // Check to see if we have an operator containing '/'.
907+ auto slashIdx = Tok.getText ().find (" /" );
908+ if (slashIdx == StringRef::npos)
909+ return ;
910+
911+ CancellableBacktrackingScope backtrack (*this );
912+ {
913+ Optional<Lexer::ForwardSlashRegexRAII> regexScope;
914+ regexScope.emplace (*L, mustBeRegex);
925915
926- // Otherwise, accept the result.
927- backtrack.cancelBacktrack ();
916+ // Try re-lex as a `/.../` regex literal, this will split an operator if
917+ // necessary.
918+ L->restoreState (getParserPosition ().LS , /* enableDiagnostics*/ true );
919+
920+ // If we didn't split a prefix operator, reset the regex lexing scope.
921+ // Otherwise, we want to keep it in place for the next token.
922+ auto didSplit = L->peekNextToken ().getLength () == slashIdx;
923+ if (!didSplit)
924+ regexScope.reset ();
925+
926+ // Discard the current token, which will be replaced by the re-lexed
927+ // token, which will either be a regex literal token, a prefix operator,
928+ // or the original unchanged token.
929+ discardToken ();
930+
931+ // If we split a prefix operator from the regex literal, and are not sure
932+ // whether this should be a regex, backtrack if we didn't end up lexing a
933+ // regex literal.
934+ if (didSplit && !mustBeRegex &&
935+ !L->peekNextToken ().is (tok::regex_literal)) {
936+ return ;
928937 }
929- break ;
930- }
931- default :
932- break ;
938+
939+ // Otherwise, accept the result.
940+ backtrack.cancelBacktrack ();
933941 }
934942}
935943
@@ -3223,17 +3231,23 @@ ParserStatus Parser::parseExprList(tok leftTok, tok rightTok,
32233231 SourceLoc FieldNameLoc;
32243232 parseOptionalArgumentLabel (FieldName, FieldNameLoc);
32253233
3226- // First check to see if we have the start of a regex literal `/.../`. We
3227- // need to do this before handling unapplied operator references, as e.g
3228- // `(/, /)` might be a regex literal.
3229- tryLexRegexLiteral (/* mustBeRegex*/ false );
3230-
32313234 // See if we have an operator decl ref '(<op>)'. The operator token in
32323235 // this case lexes as a binary operator because it neither leads nor
32333236 // follows a proper subexpression.
3237+ auto isUnappliedOperator = [&]() {
3238+ return Tok.isBinaryOperator () && peekToken ().isAny (rightTok, tok::comma);
3239+ };
3240+
3241+ if (isUnappliedOperator ()) {
3242+ // Check to see if we have the start of a regex literal `/.../`. We need
3243+ // to do this for an unapplied operator reference, as e.g `(/, /)` might
3244+ // be a regex literal.
3245+ tryLexRegexLiteral (/* forUnappliedOperator*/ true );
3246+ }
3247+
32343248 ParserStatus Status;
32353249 Expr *SubExpr = nullptr ;
3236- if (Tok. isBinaryOperator () && peekToken (). isAny (rightTok, tok::comma )) {
3250+ if (isUnappliedOperator ( )) {
32373251 SyntaxParsingContext operatorContext (SyntaxContext,
32383252 SyntaxKind::IdentifierExpr);
32393253 DeclNameLoc Loc;
0 commit comments