@@ -236,20 +236,16 @@ public final class UseShorthandTypeNames: SyntaxFormatRule {
236
236
) -> TypeSyntax {
237
237
var wrappedType = wrappedType
238
238
239
- if let functionType = wrappedType. as ( FunctionTypeSyntax . self) {
240
- // Function types must be wrapped as a tuple before using shorthand optional syntax,
241
- // otherwise the "?" applies to the return type instead of the function type. Attach the
242
- // leading trivia to the left-paren that we're adding in this case.
243
- let tupleTypeElement = TupleTypeElementSyntax (
244
- inoutKeyword: nil , firstName: nil , secondName: nil , colon: nil , type: TypeSyntax ( functionType) ,
245
- ellipsis: nil , trailingComma: nil )
246
- let tupleTypeElementList = TupleTypeElementListSyntax ( [ tupleTypeElement] )
247
- let tupleType = TupleTypeSyntax (
248
- leftParen: TokenSyntax . leftParenToken ( leadingTrivia: leadingTrivia) ,
249
- elements: tupleTypeElementList,
250
- rightParen: TokenSyntax . rightParenToken ( ) )
251
- wrappedType = TypeSyntax ( tupleType)
252
- } else {
239
+ // Function types and some-or-any types must be wrapped in parentheses before using shorthand
240
+ // optional syntax, otherwise the "?" will bind incorrectly (in the function case it binds to
241
+ // only the result, and in the some-or-any case it only binds to the child protocol). Attach the
242
+ // leading trivia to the left-paren that we're adding in these cases.
243
+ switch Syntax ( wrappedType) . as ( SyntaxEnum . self) {
244
+ case . functionType( let functionType) :
245
+ wrappedType = parenthesizedType ( functionType, leadingTrivia: leadingTrivia)
246
+ case . someOrAnyType( let someOrAnyType) :
247
+ wrappedType = parenthesizedType ( someOrAnyType, leadingTrivia: leadingTrivia)
248
+ default :
253
249
// Otherwise, the argument type can safely become an optional by simply appending a "?", but
254
250
// we need to transfer the leading trivia from the original `Optional` token over to it.
255
251
// By doing so, something like `/* comment */ Optional<Foo>` will become `/* comment */ Foo?`
@@ -316,38 +312,58 @@ public final class UseShorthandTypeNames: SyntaxFormatRule {
316
312
/// key type or value type does not have a valid expression representation.
317
313
private func makeOptionalTypeExpression(
318
314
wrapping wrappedType: TypeSyntax ,
319
- leadingTrivia: Trivia ? = nil ,
315
+ leadingTrivia: Trivia = [ ] ,
320
316
questionMark: TokenSyntax
321
317
) -> OptionalChainingExprSyntax ? {
322
318
guard var wrappedTypeExpr = expressionRepresentation ( of: wrappedType) else { return nil }
323
319
324
- if wrappedType. is ( FunctionTypeSyntax . self) {
325
- // Function types must be wrapped as a tuple before using shorthand optional syntax,
326
- // otherwise the "?" applies to the return type instead of the function type. Attach the
327
- // leading trivia to the left-paren that we're adding in this case.
328
- let tupleExprElement =
329
- LabeledExprSyntax (
330
- label: nil , colon: nil , expression: wrappedTypeExpr, trailingComma: nil )
331
- let tupleExprElementList = LabeledExprListSyntax ( [ tupleExprElement] )
332
- let tupleExpr = TupleExprSyntax (
333
- leftParen: TokenSyntax . leftParenToken ( leadingTrivia: leadingTrivia ?? [ ] ) ,
334
- elements: tupleExprElementList,
335
- rightParen: TokenSyntax . rightParenToken ( ) )
336
- wrappedTypeExpr = ExprSyntax ( tupleExpr)
337
- } else {
320
+ // Function types and some-or-any types must be wrapped in parentheses before using shorthand
321
+ // optional syntax, otherwise the "?" will bind incorrectly (in the function case it binds to
322
+ // only the result, and in the some-or-any case it only binds to the child protocol). Attach the
323
+ // leading trivia to the left-paren that we're adding in these cases.
324
+ switch Syntax ( wrappedType) . as ( SyntaxEnum . self) {
325
+ case . functionType, . someOrAnyType:
326
+ wrappedTypeExpr = parenthesizedExpr ( wrappedTypeExpr, leadingTrivia: leadingTrivia)
327
+ default :
338
328
// Otherwise, the argument type can safely become an optional by simply appending a "?". If
339
329
// we were given leading trivia from another node (for example, from `Optional` when
340
330
// converting a long-form to short-form), we need to transfer it over. By doing so, something
341
331
// like `/* comment */ Optional<Foo>` will become `/* comment */ Foo?` instead of discarding
342
332
// the comment.
343
- wrappedTypeExpr. leadingTrivia = leadingTrivia ?? [ ]
333
+ wrappedTypeExpr. leadingTrivia = leadingTrivia
344
334
}
345
335
346
336
return OptionalChainingExprSyntax (
347
337
expression: wrappedTypeExpr,
348
338
questionMark: questionMark)
349
339
}
350
340
341
+ /// Returns the given type wrapped in parentheses.
342
+ private func parenthesizedType< TypeNode: TypeSyntaxProtocol > (
343
+ _ typeToWrap: TypeNode ,
344
+ leadingTrivia: Trivia
345
+ ) -> TypeSyntax {
346
+ let tupleTypeElement = TupleTypeElementSyntax ( type: TypeSyntax ( typeToWrap) )
347
+ let tupleType = TupleTypeSyntax (
348
+ leftParen: . leftParenToken( leadingTrivia: leadingTrivia) ,
349
+ elements: TupleTypeElementListSyntax ( [ tupleTypeElement] ) ,
350
+ rightParen: . rightParenToken( ) )
351
+ return TypeSyntax ( tupleType)
352
+ }
353
+
354
+ /// Returns the given expression wrapped in parentheses.
355
+ private func parenthesizedExpr< ExprNode: ExprSyntaxProtocol > (
356
+ _ exprToWrap: ExprNode ,
357
+ leadingTrivia: Trivia
358
+ ) -> ExprSyntax {
359
+ let tupleExprElement = LabeledExprSyntax ( expression: exprToWrap)
360
+ let tupleExpr = TupleExprSyntax (
361
+ leftParen: . leftParenToken( leadingTrivia: leadingTrivia) ,
362
+ elements: LabeledExprListSyntax ( [ tupleExprElement] ) ,
363
+ rightParen: . rightParenToken( ) )
364
+ return ExprSyntax ( tupleExpr)
365
+ }
366
+
351
367
/// Returns an `ExprSyntax` that is syntactically equivalent to the given `TypeSyntax`, or nil if
352
368
/// it wouldn't be valid.
353
369
///
@@ -404,7 +420,7 @@ public final class UseShorthandTypeNames: SyntaxFormatRule {
404
420
case . optionalType( let optionalType) :
405
421
let result = makeOptionalTypeExpression (
406
422
wrapping: optionalType. wrappedType,
407
- leadingTrivia: optionalType. firstToken ( viewMode: . sourceAccurate) ? . leadingTrivia,
423
+ leadingTrivia: optionalType. firstToken ( viewMode: . sourceAccurate) ? . leadingTrivia ?? [ ] ,
408
424
questionMark: optionalType. questionMark)
409
425
return ExprSyntax ( result)
410
426
@@ -427,6 +443,9 @@ public final class UseShorthandTypeNames: SyntaxFormatRule {
427
443
rightParen: tupleType. rightParen)
428
444
return ExprSyntax ( result)
429
445
446
+ case . someOrAnyType( let someOrAnyType) :
447
+ return ExprSyntax ( TypeExprSyntax ( type: someOrAnyType) )
448
+
430
449
default :
431
450
return nil
432
451
}
0 commit comments