Skip to content

Commit 28f27c3

Browse files
authored
Merge pull request #71069 from meg-gupta/lifetimedependencelangattr
Initial language support for lifetime dependence
2 parents d1d9fd1 + 1894b11 commit 28f27c3

24 files changed

+972
-63
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2168,5 +2168,19 @@ ERROR(requires_experimental_feature, none,
21682168
"%2 is enabled",
21692169
(StringRef, bool, StringRef))
21702170

2171+
ERROR(expected_lparen_after_lifetime_dependence, PointsToFirstBadToken,
2172+
"expected '(' after lifetime dependence specifier", ())
2173+
2174+
ERROR(expected_identifier_or_index_or_self_after_lifetime_dependence,
2175+
PointsToFirstBadToken,
2176+
"expected identifier or index or self in lifetime dependence specifier",
2177+
())
2178+
2179+
ERROR(expected_rparen_after_lifetime_dependence, PointsToFirstBadToken,
2180+
"expected ')' after param list in lifetime dependence specifier", ())
2181+
2182+
ERROR(expected_param_index_lifetime_dependence, PointsToFirstBadToken,
2183+
"expected unsigned parameter index in lifetime dependence specifier", ())
2184+
21712185
#define UNDEFINE_DIAGNOSTIC_MACROS
21722186
#include "DefineDiagnosticMacros.h"

include/swift/AST/DiagnosticsSema.def

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7774,5 +7774,32 @@ ERROR(result_depends_on_no_result,none,
77747774
ERROR(pack_iteration_where_clause_not_supported, none,
77757775
"'where' clause in pack iteration is not supported", ())
77767776

7777+
7778+
//------------------------------------------------------------------------------
7779+
// MARK: Lifetime Dependence Diagnostics
7780+
//------------------------------------------------------------------------------
7781+
7782+
ERROR(lifetime_dependence_invalid_param_name, none,
7783+
"invalid parameter name specified %0", (Identifier))
7784+
ERROR(lifetime_dependence_invalid_param_index, none,
7785+
"invalid parameter index specified %0", (unsigned))
7786+
ERROR(lifetime_dependence_invalid_self, none,
7787+
"invalid lifetime dependence specifier, self is valid in non-static "
7788+
"methods only", ())
7789+
ERROR(lifetime_dependence_duplicate_param_id, none,
7790+
"duplicate lifetime dependence specifier", ())
7791+
ERROR(lifetime_dependence_cannot_use_kind, none,
7792+
"invalid use of %0 lifetime dependence for %1 ownership",
7793+
(StringRef, StringRef))
7794+
ERROR(lifetime_dependence_only_on_function_method_init_result, none,
7795+
"lifetime dependence specifiers may only be used on result of "
7796+
"functions, methods, initializers",
7797+
())
7798+
ERROR(lifetime_dependence_invalid_return_type, none,
7799+
"lifetime dependence specifiers can only be specifier on ~Escapable "
7800+
"results", ())
7801+
ERROR(lifetime_dependence_missing_ownership_modifier, none,
7802+
"lifetime dependence can only be specified on parameters with ownership "
7803+
"modifiers (borrowing, consuming, inout)", ())
77777804
#define UNDEFINE_DIAGNOSTIC_MACROS
77787805
#include "DefineDiagnosticMacros.h"

include/swift/AST/ExtInfo.h

Lines changed: 80 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,27 @@ class ClangTypeInfo {
8585
void dump(llvm::raw_ostream &os, const clang::ASTContext &ctx) const;
8686
};
8787

88+
class LifetimeDependenceInfo {
89+
IndexSubset *copyLifetimeParamIndices;
90+
IndexSubset *borrowLifetimeParamIndices;
91+
92+
public:
93+
LifetimeDependenceInfo()
94+
: copyLifetimeParamIndices(nullptr), borrowLifetimeParamIndices(nullptr) {
95+
}
96+
LifetimeDependenceInfo(IndexSubset *copyLifetimeParamIndices,
97+
IndexSubset *borrowLifetimeParamIndices)
98+
: copyLifetimeParamIndices(copyLifetimeParamIndices),
99+
borrowLifetimeParamIndices(borrowLifetimeParamIndices) {}
100+
101+
operator bool() const { return empty(); }
102+
103+
bool empty() const {
104+
return copyLifetimeParamIndices == nullptr &&
105+
borrowLifetimeParamIndices == nullptr;
106+
}
107+
};
108+
88109
// MARK: - UnexpectedClangTypeError
89110
/// Potential errors when trying to store a Clang type in an ExtInfo.
90111
struct UnexpectedClangTypeError {
@@ -369,42 +390,47 @@ class ASTExtInfoBuilder {
369390
unsigned bits; // Naturally sized for speed.
370391

371392
ClangTypeInfo clangTypeInfo;
393+
372394
Type globalActor;
373395
Type thrownError;
374396

397+
LifetimeDependenceInfo lifetimeDependenceInfo;
398+
375399
using Representation = FunctionTypeRepresentation;
376400

377-
ASTExtInfoBuilder(
378-
unsigned bits, ClangTypeInfo clangTypeInfo, Type globalActor,
379-
Type thrownError
380-
) : bits(bits), clangTypeInfo(clangTypeInfo), globalActor(globalActor),
381-
thrownError(thrownError) {}
401+
ASTExtInfoBuilder(unsigned bits, ClangTypeInfo clangTypeInfo,
402+
Type globalActor, Type thrownError,
403+
LifetimeDependenceInfo lifetimeDependenceInfo)
404+
: bits(bits), clangTypeInfo(clangTypeInfo), globalActor(globalActor),
405+
thrownError(thrownError),
406+
lifetimeDependenceInfo(lifetimeDependenceInfo) {}
382407

383408
public:
384409
/// An ExtInfoBuilder for a typical Swift function: @convention(swift),
385410
/// @escaping, non-throwing, non-differentiable.
386411
ASTExtInfoBuilder()
387412
: ASTExtInfoBuilder(Representation::Swift, false, false, Type(),
388413
DifferentiabilityKind::NonDifferentiable, nullptr,
389-
Type()) {}
414+
Type(), LifetimeDependenceInfo()) {}
390415

391416
// Constructor for polymorphic type.
392417
ASTExtInfoBuilder(Representation rep, bool throws, Type thrownError)
393418
: ASTExtInfoBuilder(rep, false, throws, thrownError,
394419
DifferentiabilityKind::NonDifferentiable, nullptr,
395-
Type()) {}
420+
Type(), LifetimeDependenceInfo()) {}
396421

397422
// Constructor with no defaults.
398423
ASTExtInfoBuilder(Representation rep, bool isNoEscape, bool throws,
399-
Type thrownError,
400-
DifferentiabilityKind diffKind, const clang::Type *type,
401-
Type globalActor)
424+
Type thrownError, DifferentiabilityKind diffKind,
425+
const clang::Type *type, Type globalActor,
426+
LifetimeDependenceInfo lifetimeDependenceInfo)
402427
: ASTExtInfoBuilder(
403428
((unsigned)rep) | (isNoEscape ? NoEscapeMask : 0) |
404429
(throws ? ThrowsMask : 0) |
405430
(((unsigned)diffKind << DifferentiabilityMaskOffset) &
406431
DifferentiabilityMask),
407-
ClangTypeInfo(type), globalActor, thrownError) {}
432+
ClangTypeInfo(type), globalActor, thrownError,
433+
lifetimeDependenceInfo) {}
408434

409435
void checkInvariants() const;
410436

@@ -444,6 +470,10 @@ class ASTExtInfoBuilder {
444470
Type getGlobalActor() const { return globalActor; }
445471
Type getThrownError() const { return thrownError; }
446472

473+
LifetimeDependenceInfo getLifetimeDependenceInfo() const {
474+
return lifetimeDependenceInfo;
475+
}
476+
447477
constexpr bool hasSelfParam() const {
448478
switch (getSILRepresentation()) {
449479
case SILFunctionTypeRepresentation::Thick:
@@ -477,31 +507,31 @@ class ASTExtInfoBuilder {
477507
return ASTExtInfoBuilder((bits & ~RepresentationMask) | (unsigned)rep,
478508
shouldStoreClangType(rep) ? clangTypeInfo
479509
: ClangTypeInfo(),
480-
globalActor, thrownError);
510+
globalActor, thrownError, lifetimeDependenceInfo);
481511
}
482512
[[nodiscard]]
483513
ASTExtInfoBuilder withNoEscape(bool noEscape = true) const {
484-
return ASTExtInfoBuilder(noEscape ? (bits | NoEscapeMask)
485-
: (bits & ~NoEscapeMask),
486-
clangTypeInfo, globalActor, thrownError);
514+
return ASTExtInfoBuilder(
515+
noEscape ? (bits | NoEscapeMask) : (bits & ~NoEscapeMask),
516+
clangTypeInfo, globalActor, thrownError, lifetimeDependenceInfo);
487517
}
488518
[[nodiscard]]
489519
ASTExtInfoBuilder withConcurrent(bool concurrent = true) const {
490-
return ASTExtInfoBuilder(concurrent ? (bits | SendableMask)
491-
: (bits & ~SendableMask),
492-
clangTypeInfo, globalActor, thrownError);
520+
return ASTExtInfoBuilder(
521+
concurrent ? (bits | SendableMask) : (bits & ~SendableMask),
522+
clangTypeInfo, globalActor, thrownError, lifetimeDependenceInfo);
493523
}
494524
[[nodiscard]]
495525
ASTExtInfoBuilder withAsync(bool async = true) const {
496-
return ASTExtInfoBuilder(async ? (bits | AsyncMask)
497-
: (bits & ~AsyncMask),
498-
clangTypeInfo, globalActor, thrownError);
526+
return ASTExtInfoBuilder(async ? (bits | AsyncMask) : (bits & ~AsyncMask),
527+
clangTypeInfo, globalActor, thrownError,
528+
lifetimeDependenceInfo);
499529
}
500530
[[nodiscard]]
501531
ASTExtInfoBuilder withThrows(bool throws, Type thrownError) const {
502532
return ASTExtInfoBuilder(
503533
throws ? (bits | ThrowsMask) : (bits & ~ThrowsMask), clangTypeInfo,
504-
globalActor, thrownError);
534+
globalActor, thrownError, lifetimeDependenceInfo);
505535
}
506536
[[nodiscard]]
507537
ASTExtInfoBuilder withThrows() const {
@@ -513,12 +543,12 @@ class ASTExtInfoBuilder {
513543
return ASTExtInfoBuilder(
514544
(bits & ~DifferentiabilityMask) |
515545
((unsigned)differentiability << DifferentiabilityMaskOffset),
516-
clangTypeInfo, globalActor, thrownError);
546+
clangTypeInfo, globalActor, thrownError, lifetimeDependenceInfo);
517547
}
518548
[[nodiscard]]
519549
ASTExtInfoBuilder withClangFunctionType(const clang::Type *type) const {
520-
return ASTExtInfoBuilder(
521-
bits, ClangTypeInfo(type), globalActor, thrownError);
550+
return ASTExtInfoBuilder(bits, ClangTypeInfo(type), globalActor,
551+
thrownError, lifetimeDependenceInfo);
522552
}
523553

524554
/// Put a SIL representation in the ExtInfo.
@@ -532,19 +562,27 @@ class ASTExtInfoBuilder {
532562
return ASTExtInfoBuilder((bits & ~RepresentationMask) | (unsigned)rep,
533563
shouldStoreClangType(rep) ? clangTypeInfo
534564
: ClangTypeInfo(),
535-
globalActor, thrownError);
565+
globalActor, thrownError, lifetimeDependenceInfo);
536566
}
537567

538568
[[nodiscard]]
539569
ASTExtInfoBuilder withGlobalActor(Type globalActor) const {
540-
return ASTExtInfoBuilder(bits, clangTypeInfo, globalActor, thrownError);
570+
return ASTExtInfoBuilder(bits, clangTypeInfo, globalActor, thrownError,
571+
lifetimeDependenceInfo);
572+
}
573+
574+
[[nodiscard]] ASTExtInfoBuilder withLifetimeDependenceInfo(
575+
LifetimeDependenceInfo lifetimeDependenceInfo) const {
576+
return ASTExtInfoBuilder(bits, clangTypeInfo, globalActor, thrownError,
577+
lifetimeDependenceInfo);
541578
}
542579

543580
bool isEqualTo(ASTExtInfoBuilder other, bool useClangTypes) const {
544581
return bits == other.bits &&
545-
(useClangTypes ? (clangTypeInfo == other.clangTypeInfo) : true) &&
546-
globalActor.getPointer() == other.globalActor.getPointer() &&
547-
thrownError.getPointer() == other.thrownError.getPointer();
582+
(useClangTypes ? (clangTypeInfo == other.clangTypeInfo) : true) &&
583+
globalActor.getPointer() == other.globalActor.getPointer() &&
584+
thrownError.getPointer() == other.thrownError.getPointer() &&
585+
lifetimeDependenceInfo == other.lifetimeDependenceInfo;
548586
}
549587

550588
constexpr std::tuple<unsigned, const void *, const void *, const void *>
@@ -573,8 +611,9 @@ class ASTExtInfo {
573611
ASTExtInfo(ASTExtInfoBuilder builder) : builder(builder) {}
574612

575613
ASTExtInfo(unsigned bits, ClangTypeInfo clangTypeInfo, Type globalActor,
576-
Type thrownError)
577-
: builder(bits, clangTypeInfo, globalActor, thrownError) {
614+
Type thrownError, LifetimeDependenceInfo lifetimeDependenceInfo)
615+
: builder(bits, clangTypeInfo, globalActor, thrownError,
616+
lifetimeDependenceInfo) {
578617
builder.checkInvariants();
579618
};
580619

@@ -621,6 +660,10 @@ class ASTExtInfo {
621660
Type getGlobalActor() const { return builder.getGlobalActor(); }
622661
Type getThrownError() const { return builder.getThrownError(); }
623662

663+
LifetimeDependenceInfo getLifetimeDependenceInfo() const {
664+
return builder.getLifetimeDependenceInfo();
665+
}
666+
624667
/// Helper method for changing the representation.
625668
///
626669
/// Prefer using \c ASTExtInfoBuilder::withRepresentation for chaining.
@@ -674,6 +717,11 @@ class ASTExtInfo {
674717
return builder.withGlobalActor(globalActor).build();
675718
}
676719

720+
[[nodiscard]] ASTExtInfo withLifetimeDependenceInfo(
721+
LifetimeDependenceInfo lifetimeDependenceInfo) const {
722+
return builder.withLifetimeDependenceInfo(lifetimeDependenceInfo).build();
723+
}
724+
677725
bool isEqualTo(ASTExtInfo other, bool useClangTypes) const {
678726
return builder.isEqualTo(other.builder, useClangTypes);
679727
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
//===--- LifetimeDependenceSpecifiers.h ------------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file defines types and utilities related to Lifetime Dependence
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_AST_LIFETIMEDEPENDENCE_H
18+
#define SWIFT_AST_LIFETIMEDEPENDENCE_H
19+
20+
#include "swift/AST/Decl.h"
21+
#include "swift/Basic/Debug.h"
22+
#include "swift/Basic/OptionSet.h"
23+
#include "llvm/Support/TrailingObjects.h"
24+
25+
namespace swift {
26+
27+
enum class LifetimeDependenceKind : uint8_t {
28+
Copy = 0,
29+
Consume,
30+
Borrow,
31+
Mutate
32+
};
33+
34+
class LifetimeDependenceSpecifier {
35+
public:
36+
enum class SpecifierKind { Named, Ordered, Self };
37+
38+
private:
39+
SourceLoc loc;
40+
SpecifierKind specifierKind;
41+
LifetimeDependenceKind lifetimeDependenceKind;
42+
union Value {
43+
struct {
44+
Identifier name;
45+
} Named;
46+
struct {
47+
unsigned index;
48+
} Ordered;
49+
struct {
50+
} self;
51+
Value(Identifier name) : Named({name}) {}
52+
Value(unsigned index) : Ordered({index}) {}
53+
Value() {}
54+
} value;
55+
56+
LifetimeDependenceSpecifier(SourceLoc loc, SpecifierKind specifierKind,
57+
LifetimeDependenceKind lifetimeDependenceKind,
58+
Value value)
59+
: loc(loc), specifierKind(specifierKind),
60+
lifetimeDependenceKind(lifetimeDependenceKind), value(value) {}
61+
62+
public:
63+
static LifetimeDependenceSpecifier getNamedLifetimeDependenceSpecifier(
64+
SourceLoc loc, LifetimeDependenceKind kind, Identifier name) {
65+
return {loc, SpecifierKind::Named, kind, name};
66+
}
67+
68+
static LifetimeDependenceSpecifier getOrderedLifetimeDependenceSpecifier(
69+
SourceLoc loc, LifetimeDependenceKind kind, unsigned index) {
70+
return {loc, SpecifierKind::Ordered, kind, index};
71+
}
72+
73+
static LifetimeDependenceSpecifier
74+
getSelfLifetimeDependenceSpecifier(SourceLoc loc,
75+
LifetimeDependenceKind kind) {
76+
return {loc, SpecifierKind::Self, kind, {}};
77+
}
78+
79+
SourceLoc getLoc() const { return loc; }
80+
81+
SpecifierKind getSpecifierKind() const { return specifierKind; }
82+
83+
LifetimeDependenceKind getLifetimeDependenceKind() const {
84+
return lifetimeDependenceKind;
85+
}
86+
87+
Identifier getName() const {
88+
assert(specifierKind == SpecifierKind::Named);
89+
return value.Named.name;
90+
}
91+
92+
unsigned getIndex() const {
93+
assert(specifierKind == SpecifierKind::Ordered);
94+
return value.Ordered.index;
95+
}
96+
std::string getParamString() const {
97+
switch (specifierKind) {
98+
case SpecifierKind::Named:
99+
return value.Named.name.str().str();
100+
case SpecifierKind::Self:
101+
return "self";
102+
case SpecifierKind::Ordered:
103+
return std::to_string(value.Ordered.index);
104+
}
105+
llvm_unreachable("Invalid LifetimeDependenceSpecifier::SpecifierKind");
106+
}
107+
};
108+
} // namespace swift
109+
110+
#endif

0 commit comments

Comments
 (0)