Skip to content
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed `document_range_formatting_provider` capability missing from `ServerCapabilities` in language server mode
- Fixed current working directory incorrectly used as config search root in language server mode -- now, the root of the opened workspace is used instead ([#1032](https://github.com/JohnnyMorganz/StyLua/issues/1032))
- Language server mode now correctly respects `.styluaignore` files ([#1035](https://github.com/JohnnyMorganz/StyLua/issues/1035))
- Luau: Fixed parentheses incorrectly removed on a single type that is the default for a variadic generic parameter ([#1038](https://github.com/JohnnyMorganz/StyLua/issues/1038))

## [2.2.0] - 2025-09-14

Expand Down
33 changes: 22 additions & 11 deletions src/formatters/luau.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1097,6 +1097,7 @@ fn attempt_assigned_type_tactics(
ctx: &Context,
equal_token: TokenReference,
type_info: &TypeInfo,
context: TypeInfoContext,
shape: Shape,
) -> (TokenReference, TypeInfo) {
const EQUAL_TOKEN_LENGTH: usize = " = ".len();
Expand All @@ -1109,11 +1110,11 @@ fn attempt_assigned_type_tactics(

// Format declaration, hanging if it contains comments (ignoring leading and trailing comments, as they won't affect anything)
let declaration = if contains_comments(strip_trivia(type_info)) {
hang_type_info(ctx, type_info, TypeInfoContext::new(), shape, 0)
hang_type_info(ctx, type_info, context, shape, 0)
} else {
let proper_declaration = format_type_info(ctx, type_info, shape);
let proper_declaration = format_type_info_internal(ctx, type_info, context, shape);
if shape.test_over_budget(&proper_declaration) {
hang_type_info(ctx, type_info, TypeInfoContext::new(), shape, 0)
hang_type_info(ctx, type_info, context, shape, 0)
} else {
proper_declaration
}
Expand Down Expand Up @@ -1141,8 +1142,9 @@ fn attempt_assigned_type_tactics(
let mut equal_token = equal_token;
let type_definition;
let singleline_type_definition =
format_type_info(ctx, type_info, shape.with_infinite_width());
let proper_type_definition = format_type_info(ctx, type_info, shape + EQUAL_TOKEN_LENGTH);
format_type_info_internal(ctx, type_info, context, shape.with_infinite_width());
let proper_type_definition =
format_type_info_internal(ctx, type_info, context, shape + EQUAL_TOKEN_LENGTH);

// Test to see whether the type definition must be hung due to comments
let must_hang = should_hang_type(type_info, CommentSearch::All);
Expand All @@ -1165,8 +1167,7 @@ fn attempt_assigned_type_tactics(
equal_token = hang_equal_token(ctx, &equal_token, shape, true);

let shape = shape.reset().increment_additional_indent();
let hanging_type_definition =
hang_type_info(ctx, type_info, TypeInfoContext::new(), shape, 0);
let hanging_type_definition = hang_type_info(ctx, type_info, context, shape, 0);
type_definition = hanging_type_definition;
}
} else {
Expand All @@ -1178,7 +1179,7 @@ fn attempt_assigned_type_tactics(

// Add the expression list into the indent range, as it will be indented by one
let shape = shape.reset().increment_additional_indent();
type_definition = format_type_info(ctx, type_info, shape);
type_definition = format_type_info_internal(ctx, type_info, context, shape);
} else {
// Use the proper formatting
type_definition = proper_type_definition;
Expand Down Expand Up @@ -1232,8 +1233,13 @@ fn format_type_declaration(
};

let equal_token = fmt_symbol!(ctx, type_declaration.equal_token(), " = ", shape);
let (equal_token, type_definition) =
attempt_assigned_type_tactics(ctx, equal_token, type_declaration.type_definition(), shape);
let (equal_token, type_definition) = attempt_assigned_type_tactics(
ctx,
equal_token,
type_declaration.type_definition(),
TypeInfoContext::new(),
shape,
);

// Handle comments in between the type name and generics + generics and equal token
// (or just type name and equal token if generics not present)
Expand Down Expand Up @@ -1413,11 +1419,16 @@ fn format_generic_parameter(
other => panic!("unknown node {:?}", other),
};

let context = match generic_parameter.parameter() {
GenericParameterInfo::Variadic { .. } => TypeInfoContext::new().mark_within_generic(),
_ => TypeInfoContext::new(),
};

let default_type = match (generic_parameter.equals(), generic_parameter.default_type()) {
(Some(equals), Some(default_type)) => {
let equals = fmt_symbol!(ctx, equals, " = ", shape);
let (equals, default_type) =
attempt_assigned_type_tactics(ctx, equals, default_type, shape);
attempt_assigned_type_tactics(ctx, equals, default_type, context, shape);
Some((equals, default_type))
}
(None, None) => None,
Expand Down
10 changes: 10 additions & 0 deletions tests/inputs-luau/excess-parentheses-type-pack-default.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-- https://github.com/JohnnyMorganz/StyLua/issues/1038

type Object1<T = (nil)> = {
method: (T) -> (),
}

type Object2<T... = (nil)> = {
method: (T...) -> (),
}

14 changes: 14 additions & 0 deletions tests/snapshots/[email protected]
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
source: tests/tests.rs
expression: "format(&contents, LuaVersion::Luau)"
input_file: tests/inputs-luau/excess-parentheses-type-pack-default.lua
---
-- https://github.com/JohnnyMorganz/StyLua/issues/1038

type Object1<T = nil> = {
method: (T) -> (),
}

type Object2<T... = (nil)> = {
method: (T...) -> (),
}
Loading