Skip to content

Add support for lifetime type specifiers #2433

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

Merged

Conversation

ahoppen
Copy link
Member

@ahoppen ahoppen commented Jan 22, 2024

Having multiple type specifiers on a type is valid in the C++ parser but not in the Swift parser. Also add support for lifetime specifiers that can have arguments, like borrow(data).

rdar://118125715


While at it, replace the manually maintained TokenSpecSet TypeSpecifier by the generated TypeSpecifierSyntax.SpecifierOptions

The two TokenSpecSets had already diverged. Instead of manually maintaining the TypeSpecifier spec set, we should allow all keywors specified in the syntax tree definition.

@ahoppen ahoppen requested a review from bnbarham as a code owner January 22, 2024 03:22
@ahoppen ahoppen force-pushed the ahoppen/allow-multiple-type-specifiers branch 3 times, most recently from 4dd7bc7 to e5c0834 Compare January 22, 2024 03:52
@ahoppen
Copy link
Member Author

ahoppen commented Jan 22, 2024

@swift-ci Please test

@ahoppen
Copy link
Member Author

ahoppen commented Jan 22, 2024

@swift-ci Please test Windows

@bnbarham bnbarham requested a review from rintaro January 22, 2024 22:38
@ahoppen ahoppen force-pushed the ahoppen/allow-multiple-type-specifiers branch from e5c0834 to 366fa95 Compare January 22, 2024 23:23
@ahoppen
Copy link
Member Author

ahoppen commented Jan 22, 2024

@swift-ci Please test

@ahoppen
Copy link
Member Author

ahoppen commented Jan 23, 2024

@swift-ci Please test Windows

@ahoppen
Copy link
Member Author

ahoppen commented Feb 6, 2024

swiftlang/swift#71408

@swift-ci Please test

@ahoppen ahoppen force-pushed the ahoppen/allow-multiple-type-specifiers branch from b627323 to 685768d Compare February 6, 2024 17:49
@ahoppen
Copy link
Member Author

ahoppen commented Feb 6, 2024

swiftlang/swift#71408

@swift-ci Please test macOS

@ahoppen ahoppen force-pushed the ahoppen/allow-multiple-type-specifiers branch 3 times, most recently from 5a0ecc9 to 4a1ba3b Compare March 1, 2024 03:47
@ahoppen ahoppen changed the title Allow multiple type specifiers on a type Add support for lifetime type specifiers Mar 1, 2024
@ahoppen
Copy link
Member Author

ahoppen commented Mar 1, 2024

@swift-ci Please test macOS

@ahoppen ahoppen requested a review from meg-gupta March 1, 2024 03:49
@ahoppen ahoppen force-pushed the ahoppen/allow-multiple-type-specifiers branch from 4a1ba3b to 81bf075 Compare March 1, 2024 07:50
@ahoppen
Copy link
Member Author

ahoppen commented Mar 1, 2024

@swift-ci Please test

Copy link
Contributor

@meg-gupta meg-gupta left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lifetime dependence changes lgtm. I added some minor comments about tests. That + changes for initializers can be done as a follow up.

Thanks for this PR! With this we are almost close to get rid of -disable-experimental-parser-round-trip in our lifetime dependence tests!

experimentalFeatures: [.nonescapableTypes]
)

assertParse("func foo() -> _borrow(0) X", diagnostics: [], experimentalFeatures: [.nonescapableTypes])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add a failure test with a -ve integer ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a test case for _borrow(-1)

@@ -325,4 +325,59 @@ final class TypeTests: ParserTestCase {
assertParse("func foo1(_ a: _const borrowing String) {}")
assertParse("func foo2(_ a: borrowing _const String) {}")
}

func testLifetimeSpecifier() {
assertParse("func foo() -> _borrow(x) X", experimentalFeatures: [.nonescapableTypes])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add a failure test without the experimental feature?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a test case

@ahoppen ahoppen force-pushed the ahoppen/allow-multiple-type-specifiers branch from 81bf075 to 6c36cec Compare March 1, 2024 20:54
@ahoppen
Copy link
Member Author

ahoppen commented Mar 1, 2024

@swift-ci Please test

@ahoppen
Copy link
Member Author

ahoppen commented Mar 8, 2024

@swift-ci Please test Windows

@ahoppen ahoppen requested review from jckarter and rjmccall March 8, 2024 00:49
@ahoppen
Copy link
Member Author

ahoppen commented Mar 8, 2024

@jckarter @rjmccall Could you take a look at the representation of the lifetime specifiers in the syntax tree and if that makes sense to you?

@ahoppen
Copy link
Member Author

ahoppen commented Mar 8, 2024

Here’s an abbreviated summary of the new nodes.

public struct AttributedTypeSyntax {
  /// A list of specifiers that can be attached to the type, such as `inout`, `isolated`, or `consuming`.
  public var specifiers: TypeSpecifierListSyntax
  
  /// A list of attributes that can be attached to the type, such as `@escaping`.
  public var attributes: AttributeListSyntax
  
  /// The type to with the specifiers and attributes are applied.
  public var baseType: TypeSyntax
}

/// ### Children
/// 
/// (``SimpleTypeSpecifierSyntax`` | ``LifetimeTypeSpecifierSyntax``) `*`
///
/// ### Contained in
/// 
///  - ``AttributedTypeSyntax``.``AttributedTypeSyntax/specifiers``
public struct TypeSpecifierListSyntax {
  public enum Element: SyntaxChildChoices {
    case `simpleTypeSpecifier`(SimpleTypeSpecifierSyntax)
    case `lifetimeTypeSpecifier`(LifetimeTypeSpecifierSyntax)
  }
}

/// A specifier that can be attached to a type to eg. mark a parameter as `inout` or `consuming`
///
/// ### Children
/// 
///  - `specifier`: (`inout` | `__shared` | `__owned` | `isolated` | `_const` | `borrowing` | `consuming` | `transferring` | `_resultDependsOn`)
///
/// ### Contained in
/// 
///  - ``TypeSpecifierListSyntax``
public struct SimpleTypeSpecifierSyntax {
  /// The specifier token that's attached to the type.
  ///
  /// ### Tokens
  /// 
  /// For syntax trees generated by the parser, this is guaranteed to be one of the following kinds:
  ///  - `inout`
  ///  - `__shared`
  ///  - `__owned`
  ///  - `isolated`
  ///  - `_const`
  ///  - `borrowing`
  ///  - `consuming`
  ///  - `transferring`
  ///  - `_resultDependsOn`
  public var specifier: TokenSyntax
}

/// A specifier that specifies function parameter on whose lifetime a type depends
///
/// ### Children
/// 
///  - `specifier`: (`_copy` | `_consume` | `_borrow` | `_mutate`)
///  - `arguments`: ``LifetimeSpecifierArgumentsSyntax``
///
/// ### Contained in
/// 
///  - ``TypeSpecifierListSyntax``
public struct LifetimeTypeSpecifierSyntax {
  /// The specifier token that's attached to the type.
  ///
  /// ### Tokens
  /// 
  /// For syntax trees generated by the parser, this is guaranteed to be one of the following kinds:
  ///  - `_copy`
  ///  - `_consume`
  ///  - `_borrow`
  ///  - `_mutate`
  public var specifier: TokenSyntax

  public var arguments: LifetimeSpecifierArgumentsSyntax
}



/// ### Children
/// 
/// ``LifetimeSpecifierArgumentSyntax`` `*`
///
/// ### Contained in
/// 
///  - ``LifetimeSpecifierArgumentsSyntax``.``LifetimeSpecifierArgumentsSyntax/arguments``
public struct LifetimeSpecifierArgumentListSyntax {
  public typealias Element = LifetimeSpecifierArgumentSyntax
}


/// An optional argument passed to a type parameter.
/// 
/// ### Example
/// `borrow(data)` in `func foo(data: Array<Item>) -> borrow(data) ComplexReferenceType`
///
/// ### Children
/// 
///  - `leftParen`: `(`
///  - `arguments`: ``LifetimeSpecifierArgumentListSyntax``
///  - `rightParen`: `)`
///
/// ### Contained in
/// 
///  - ``LifetimeTypeSpecifierSyntax``.``LifetimeTypeSpecifierSyntax/arguments``
public struct LifetimeSpecifierArgumentsSyntax {
  /// ### Tokens
  /// 
  /// For syntax trees generated by the parser, this is guaranteed to be `(`.
  public var leftParen: TokenSyntax

  /// The function parameters that the lifetime of the annotated type depends on.
  public var arguments: LifetimeSpecifierArgumentListSyntax

  /// ### Tokens
  /// 
  /// For syntax trees generated by the parser, this is guaranteed to be `)`.
  public var rightParen: TokenSyntax
}

/// A single argument that can be added to a lifetime specifier like `borrow`, `mutate`, `consume` or `copy`.
/// 
/// ### Example
/// `data` in `func foo(data: Array<Item>) -> borrow(data) ComplexReferenceType`
///
/// ### Children
/// 
///  - `parameter`: (`<identifier>` | `self` | `<integerLiteral>`)
///  - `trailingComma`: `,`?
///
/// ### Contained in
/// 
///  - ``LifetimeSpecifierArgumentListSyntax``
public struct LifetimeSpecifierArgumentSyntax {
  /// The parameter on which the lifetime of this type depends. 
  /// 
  /// This can be an identifier referring to an external parameter name, an integer literal to refer to an unnamed
  /// parameter or `self` if the type's lifetime depends on the object the method is called on.
  ///
  /// ### Tokens
  /// 
  /// For syntax trees generated by the parser, this is guaranteed to be one of the following kinds:
  ///  - `<identifier>`
  ///  - `self`
  ///  - `<integerLiteral>`
  public var parameter: TokenSyntax

  /// ### Tokens
  /// 
  /// For syntax trees generated by the parser, this is guaranteed to be `,`.
  public var trailingComma: TokenSyntax?
}

Copy link
Contributor

@hamishknight hamishknight left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, just one question

Comment on lines 498 to 502
Node(
kind: .lifetimeSpecifierArgument,
base: .syntax,
nameForDiagnostics: nil,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the lifetime specifier nodes be marked experimental and therefore SPI?

@rjmccall
Copy link
Contributor

rjmccall commented Mar 8, 2024

Yeah, that representation looks fine to me.

@ahoppen ahoppen force-pushed the ahoppen/allow-multiple-type-specifiers branch 2 times, most recently from 9c33644 to 8da6dba Compare March 9, 2024 01:11
@ahoppen
Copy link
Member Author

ahoppen commented Mar 9, 2024

@swift-ci Please test

@ahoppen ahoppen enabled auto-merge March 9, 2024 01:11
ahoppen added 4 commits March 12, 2024 12:39
Having multiple type specifiers on a type is valid in the C++ parser but not in the Swift parser.

rdar://118125715
… generated `TypeSpecifierSyntax.SpecifierOptions`

The two `TokenSpecSet`s had already diverged. Instead of manually maintaining the `TypeSpecifier` spec set, we should allow all keywors specified in the syntax tree definition.
…f as docc links

Docc doesn’t like references to SPI types because they are not part of the public API.
@ahoppen ahoppen force-pushed the ahoppen/allow-multiple-type-specifiers branch from 8da6dba to 3df63e8 Compare March 12, 2024 20:02
@ahoppen
Copy link
Member Author

ahoppen commented Mar 12, 2024

@swift-ci Please test

@ahoppen
Copy link
Member Author

ahoppen commented Mar 12, 2024

@swift-ci Please test Windows

@ahoppen ahoppen merged commit e154573 into swiftlang:main Mar 13, 2024
@ahoppen ahoppen deleted the ahoppen/allow-multiple-type-specifiers branch March 16, 2024 16:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants