Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(parser): handle empty type parameters and conditional union/intersection bugfix #9964

Merged
merged 3 commits into from
Apr 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 39 additions & 26 deletions src/js_parser.zig
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,8 @@ const TypeParameterFlag = packed struct {
/// TypeScript 5.0
allow_const_modifier: bool = false,

pub const all = TypeParameterFlag{
.allow_in_out_variance_annotations = true,
.allow_const_modifier = true,
};
/// Allow "<>" without any type parameters
allow_empty_type_parameters: bool = false,
};

const JSXImport = enum {
Expand Down Expand Up @@ -7773,8 +7771,7 @@ fn NewParser_(
}

pub inline fn skipTypescriptReturnType(p: *P) anyerror!void {
var result = TypeScript.Metadata.default;
try p.skipTypeScriptTypeWithOpts(.lowest, TypeScript.SkipTypeOptions.Bitset.initOne(.is_return_type), false, &result);
try p.skipTypeScriptTypeWithOpts(.lowest, TypeScript.SkipTypeOptions.Bitset.initOne(.is_return_type), false, {});
}

pub inline fn skipTypescriptReturnTypeWithMetadata(p: *P) anyerror!TypeScript.Metadata {
Expand Down Expand Up @@ -7808,8 +7805,7 @@ fn NewParser_(

inline fn skipTypeScriptType(p: *P, level: js_ast.Op.Level) anyerror!void {
p.markTypeScriptOnly();
var result = TypeScript.Metadata.default;
try p.skipTypeScriptTypeWithOpts(level, TypeScript.SkipTypeOptions.empty, false, &result);
try p.skipTypeScriptTypeWithOpts(level, TypeScript.SkipTypeOptions.empty, false, {});
}

inline fn skipTypeScriptTypeWithMetadata(p: *P, level: js_ast.Op.Level) anyerror!TypeScript.Metadata {
Expand Down Expand Up @@ -7961,7 +7957,11 @@ fn NewParser_(
// let x = (y: any): (y) => {return 0};
// let x = (y: any): asserts y is (y) => {};
//
fn skipTypeScriptParenOrFnType(p: *P, comptime get_metadata: bool, result: *TypeScript.Metadata) anyerror!void {
fn skipTypeScriptParenOrFnType(
p: *P,
comptime get_metadata: bool,
result: if (get_metadata) *TypeScript.Metadata else void,
) anyerror!void {
p.markTypeScriptOnly();

if (p.trySkipTypeScriptArrowArgsWithBacktracking()) {
Expand All @@ -7984,7 +7984,7 @@ fn NewParser_(
level: js_ast.Op.Level,
opts: TypeScript.SkipTypeOptions.Bitset,
comptime get_metadata: bool,
result: *TypeScript.Metadata,
result: if (get_metadata) *TypeScript.Metadata else void,
) anyerror!void {
p.markTypeScriptOnly();

Expand Down Expand Up @@ -8352,8 +8352,7 @@ fn NewParser_(
if (p.lexer.token == .t_dot_dot_dot) {
try p.lexer.next();
}
var dummy_result = TypeScript.Metadata.default;
try p.skipTypeScriptTypeWithOpts(.lowest, TypeScript.SkipTypeOptions.Bitset.initOne(.allow_tuple_labels), false, &dummy_result);
try p.skipTypeScriptTypeWithOpts(.lowest, TypeScript.SkipTypeOptions.Bitset.initOne(.allow_tuple_labels), false, {});
if (p.lexer.token == .t_question) {
try p.lexer.next();
}
Expand Down Expand Up @@ -8426,13 +8425,13 @@ fn NewParser_(
if (left.finishUnion(p)) |final| {
// finish skipping the rest of the type without collecting type metadata.
result.* = final;
try p.skipTypeScriptType(.bitwise_or);
try p.skipTypeScriptTypeWithOpts(.bitwise_or, opts, false, {});
} else {
try p.skipTypeScriptTypeWithOpts(.bitwise_or, TypeScript.SkipTypeOptions.empty, get_metadata, result);
try p.skipTypeScriptTypeWithOpts(.bitwise_or, opts, get_metadata, result);
result.mergeUnion(left);
}
} else {
try p.skipTypeScriptType(.bitwise_or);
try p.skipTypeScriptTypeWithOpts(.bitwise_or, opts, false, {});
}
},
.t_ampersand => {
Expand All @@ -8447,13 +8446,13 @@ fn NewParser_(
if (left.finishIntersection(p)) |final| {
// finish skipping the rest of the type without collecting type metadata.
result.* = final;
try p.skipTypeScriptType(.bitwise_and);
try p.skipTypeScriptTypeWithOpts(.bitwise_and, opts, false, {});
} else {
try p.skipTypeScriptTypeWithOpts(.bitwise_and, TypeScript.SkipTypeOptions.empty, get_metadata, result);
try p.skipTypeScriptTypeWithOpts(.bitwise_and, opts, get_metadata, result);
result.mergeIntersection(left);
}
} else {
try p.skipTypeScriptType(.bitwise_and);
try p.skipTypeScriptTypeWithOpts(.bitwise_and, opts, false, {});
}
},
.t_exclamation => {
Expand Down Expand Up @@ -8531,8 +8530,13 @@ fn NewParser_(
try p.lexer.next();

// The type following "extends" is not permitted to be another conditional type
var extends_type = TypeScript.Metadata.default;
try p.skipTypeScriptTypeWithOpts(.lowest, TypeScript.SkipTypeOptions.Bitset.initOne(.disallow_conditional_types), get_metadata, &extends_type);
var extends_type = if (get_metadata) TypeScript.Metadata.default else {};
try p.skipTypeScriptTypeWithOpts(
.lowest,
TypeScript.SkipTypeOptions.Bitset.initOne(.disallow_conditional_types),
get_metadata,
if (get_metadata) &extends_type else {},
);

if (comptime get_metadata) {
// intersection
Expand Down Expand Up @@ -8581,8 +8585,7 @@ fn NewParser_(
if (p.lexer.token == .t_open_bracket) {
// Index signature or computed property
try p.lexer.next();
var metadata = TypeScript.Metadata.default;
try p.skipTypeScriptTypeWithOpts(.lowest, TypeScript.SkipTypeOptions.Bitset.initOne(.is_index_signature), false, &metadata);
try p.skipTypeScriptTypeWithOpts(.lowest, TypeScript.SkipTypeOptions.Bitset.initOne(.is_index_signature), false, {});

// "{ [key: string]: number }"
// "{ readonly [K in keyof T]: T[K] }"
Expand Down Expand Up @@ -8877,6 +8880,11 @@ fn NewParser_(
var result = SkipTypeParameterResult.could_be_type_cast;
try p.lexer.next();

if (p.lexer.token == .t_greater_than and flags.allow_empty_type_parameters) {
try p.lexer.next();
return .definitely_type_parameters;
}

while (true) {
var has_in = false;
var has_out = false;
Expand Down Expand Up @@ -10524,7 +10532,10 @@ fn NewParser_(
p.local_type_names.put(p.allocator, name, true) catch unreachable;
}

_ = try p.skipTypeScriptTypeParameters(.{ .allow_in_out_variance_annotations = true });
_ = try p.skipTypeScriptTypeParameters(.{
.allow_in_out_variance_annotations = true,
.allow_empty_type_parameters = true,
});

try p.lexer.expect(.t_equals);
try p.skipTypeScriptType(.lowest);
Expand Down Expand Up @@ -10652,7 +10663,10 @@ fn NewParser_(
p.local_type_names.put(p.allocator, name, true) catch unreachable;
}

_ = try p.skipTypeScriptTypeParameters(.{ .allow_in_out_variance_annotations = true });
_ = try p.skipTypeScriptTypeParameters(.{
.allow_in_out_variance_annotations = true,
.allow_empty_type_parameters = true,
});

if (p.lexer.token == .t_extends) {
try p.lexer.next();
Expand Down Expand Up @@ -12452,8 +12466,7 @@ fn NewParser_(

pub fn skipTypeScriptConstraintOfInferTypeWithBacktracking(p: *P, flags: TypeScript.SkipTypeOptions.Bitset) anyerror!bool {
try p.lexer.expect(.t_extends);
var metadata = TypeScript.Metadata.default;
try p.skipTypeScriptTypeWithOpts(.prefix, TypeScript.SkipTypeOptions.Bitset.initOne(.disallow_conditional_types), false, &metadata);
try p.skipTypeScriptTypeWithOpts(.prefix, TypeScript.SkipTypeOptions.Bitset.initOne(.disallow_conditional_types), false, {});

if (!flags.contains(.disallow_conditional_types) and p.lexer.token == .t_question) {
return error.Backtrack;
Expand Down
Loading
Loading