diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/type_info.dart b/pkg/_fe_analyzer_shared/lib/src/parser/type_info.dart index c07256117d3..af5e93e2c5a 100644 --- a/pkg/_fe_analyzer_shared/lib/src/parser/type_info.dart +++ b/pkg/_fe_analyzer_shared/lib/src/parser/type_info.dart @@ -470,7 +470,8 @@ TypeParamOrArgInfo computeTypeParamOrArg( /// possible other constructs will pass (e.g., 'a < C, D > 3'). TypeParamOrArgInfo computeMethodTypeArguments(Token token) { TypeParamOrArgInfo typeArg = computeTypeParamOrArg(token); - return mayFollowTypeArgs(typeArg.skip(token).next!) && !typeArg.recovered + return _mayFollowTypeArgs(typeArg.skip(token).next!.typeIndex) && + !typeArg.recovered ? typeArg : noTypeParamOrArg; } @@ -480,8 +481,10 @@ TypeParamOrArgInfo computeMethodTypeArguments(Token token) { /// pattern. const Set illegalPatternIdentifiers = {'when', 'as'}; -/// Indicates whether the given [token] is allowed to follow a list of type -/// arguments used as a selector after an expression. +/// Indicates whether the given [tokenTypeIndex] is allowed to follow a list of +/// type arguments used as a selector after an expression. +/// +/// Get the index from a token via `Token.typeIndex`. /// /// This is used for disambiguating constructs like `f(a(d))` and /// `f(a-d)`. In the case of `f(a(d))`, `true` will be returned, @@ -490,19 +493,71 @@ const Set illegalPatternIdentifiers = {'when', 'as'}; /// function `a`). In the case of `f(a-d)`, `false` will be returned, /// indicating that the `<` and `>` should be interpreted as operators (so two /// arguments are being passed to `f`: `a < b` and `c > -d`). -bool mayFollowTypeArgs(Token token) { - const Set continuationTokens = {'(', '.', '==', '!='}; - const Set stopTokens = {')', ']', '}', ';', ':', ','}; - const Set tokensThatMayFollowTypeArg = { - ...continuationTokens, - ...stopTokens, - }; - if (token.isA(TokenType.EOF)) { - // The spec doesn't have anything to say about this case, since an - // expression can't occur at the end of a file, but for testing it's to our - // advantage to allow EOF after type arguments, so that an isolated `f` - // can be parsed as an expression. - return true; - } - return tokensThatMayFollowTypeArg.contains(token.lexeme); +/// +// DartDocTest(() { +// for (int i = 0; i < 256; i++) { +// if (_mayFollowTypeArgs(i) != +// _mayFollowTypeArgs_helper_for_testing(i)) { +// return false; +// } +// } +// return true; +// }(), true); +@pragma("vm:prefer-inline") +bool _mayFollowTypeArgs(int tokenTypeIndex) { + // Table has size 256 to avoid bounds checks as this is called with + // `Token.typeIndex` which is know to be in [0-255]. + const List table = [ + // format hack. + true, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, true, false, false, false, false, false, + true, true, false, false, true, true, true, false, + true, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, true, false, false, false, + true, false, false, false, false, false, false, false, + false, true, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + // format hack. + ]; + + return table[tokenTypeIndex]; +} + +// ignore: unused_element +bool _mayFollowTypeArgs_helper_for_testing(int tokenTypeIndex) { + return tokenTypeIndex == TokenType.OPEN_PAREN.index || + tokenTypeIndex == TokenType.PERIOD.index || + tokenTypeIndex == TokenType.EQ_EQ.index || + tokenTypeIndex == TokenType.BANG_EQ.index || + tokenTypeIndex == TokenType.CLOSE_PAREN.index || + tokenTypeIndex == TokenType.CLOSE_SQUARE_BRACKET.index || + tokenTypeIndex == TokenType.CLOSE_CURLY_BRACKET.index || + tokenTypeIndex == TokenType.SEMICOLON.index || + tokenTypeIndex == TokenType.COLON.index || + tokenTypeIndex == TokenType.COMMA.index || + tokenTypeIndex == TokenType.EOF.index; }