Skip to content

Lower lifetime dependence info into SIL and infer when absent #71206

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
merged 9 commits into from
Jan 30, 2024
Merged
16 changes: 14 additions & 2 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -7807,10 +7807,22 @@ ERROR(pack_iteration_where_clause_not_supported, none,
"functions, methods, initializers",
())
ERROR(lifetime_dependence_invalid_return_type, none,
"lifetime dependence specifiers can only be specifier on ~Escapable "
"results", ())
"lifetime dependence can only be specified on ~Escapable results", ())
ERROR(lifetime_dependence_missing_ownership_modifier, none,
"lifetime dependence can only be specified on parameters with ownership "
"modifiers (borrowing, consuming, inout)", ())
ERROR(lifetime_dependence_cannot_infer_wo_ownership_modifier_on_method, none,
"cannot infer lifetime dependence, specify ownership modifier for the "
"method",
())
ERROR(lifetime_dependence_cannot_infer_wo_ambiguous_candidate, none,
"cannot infer lifetime dependence, multiple ~Escapable or ~Copyable "
"parameters with ownership modifiers, specify explicit lifetime "
"dependence",
())
ERROR(lifetime_dependence_cannot_infer_no_candidates, none,
"cannot infer lifetime dependence, no ~Escapable or ~Copyable "
"parameters with ownership modifiers present",
())
#define UNDEFINE_DIAGNOSTIC_MACROS
#include "DefineDiagnosticMacros.h"
122 changes: 60 additions & 62 deletions include/swift/AST/ExtInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#define SWIFT_EXTINFO_H

#include "swift/AST/AutoDiff.h"
#include "swift/AST/LifetimeDependence.h"

#include "llvm/ADT/None.h"
#include "llvm/ADT/Optional.h"
Expand Down Expand Up @@ -157,27 +158,6 @@ class ClangTypeInfo {
void dump(llvm::raw_ostream &os, const clang::ASTContext &ctx) const;
};

class LifetimeDependenceInfo {
IndexSubset *copyLifetimeParamIndices;
IndexSubset *borrowLifetimeParamIndices;

public:
LifetimeDependenceInfo()
: copyLifetimeParamIndices(nullptr), borrowLifetimeParamIndices(nullptr) {
}
LifetimeDependenceInfo(IndexSubset *copyLifetimeParamIndices,
IndexSubset *borrowLifetimeParamIndices)
: copyLifetimeParamIndices(copyLifetimeParamIndices),
borrowLifetimeParamIndices(borrowLifetimeParamIndices) {}

operator bool() const { return empty(); }

bool empty() const {
return copyLifetimeParamIndices == nullptr &&
borrowLifetimeParamIndices == nullptr;
}
};

// MARK: - UnexpectedClangTypeError
/// Potential errors when trying to store a Clang type in an ExtInfo.
struct UnexpectedClangTypeError {
Expand Down Expand Up @@ -684,20 +664,21 @@ class ASTExtInfoBuilder {
lifetimeDependenceInfo);
}

void Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddInteger(bits);
ID.AddPointer(clangTypeInfo.getType());
ID.AddPointer(globalActor.getPointer());
ID.AddPointer(thrownError.getPointer());
lifetimeDependenceInfo.Profile(ID);
}

bool isEqualTo(ASTExtInfoBuilder other, bool useClangTypes) const {
return bits == other.bits &&
(useClangTypes ? (clangTypeInfo == other.clangTypeInfo) : true) &&
globalActor.getPointer() == other.globalActor.getPointer() &&
thrownError.getPointer() == other.thrownError.getPointer() &&
lifetimeDependenceInfo == other.lifetimeDependenceInfo;
}

constexpr std::tuple<unsigned, const void *, const void *, const void *>
getFuncAttrKey() const {
return std::make_tuple(
bits, clangTypeInfo.getType(), globalActor.getPointer(),
thrownError.getPointer());
}
}; // end ASTExtInfoBuilder

// MARK: - ASTExtInfo
Expand Down Expand Up @@ -844,14 +825,11 @@ class ASTExtInfo {
return builder.withLifetimeDependenceInfo(lifetimeDependenceInfo).build();
}

void Profile(llvm::FoldingSetNodeID &ID) const { builder.Profile(ID); }

bool isEqualTo(ASTExtInfo other, bool useClangTypes) const {
return builder.isEqualTo(other.builder, useClangTypes);
}

constexpr std::tuple<unsigned, const void *, const void *, const void *>
getFuncAttrKey() const {
return builder.getFuncAttrKey();
}
}; // end ASTExtInfo

// MARK: - SILFunctionLanguage
Expand Down Expand Up @@ -922,11 +900,15 @@ class SILExtInfoBuilder {

ClangTypeInfo clangTypeInfo;

LifetimeDependenceInfo lifetimeDependenceInfo;

using Language = SILFunctionLanguage;
using Representation = SILFunctionTypeRepresentation;

SILExtInfoBuilder(unsigned bits, ClangTypeInfo clangTypeInfo)
: bits(bits), clangTypeInfo(clangTypeInfo.getCanonical()) {}
SILExtInfoBuilder(unsigned bits, ClangTypeInfo clangTypeInfo,
LifetimeDependenceInfo lifetimeDependenceInfo)
: bits(bits), clangTypeInfo(clangTypeInfo.getCanonical()),
lifetimeDependenceInfo(lifetimeDependenceInfo) {}

static constexpr unsigned makeBits(Representation rep, bool isPseudogeneric,
bool isNoEscape, bool isSendable,
Expand All @@ -948,23 +930,24 @@ class SILExtInfoBuilder {
: SILExtInfoBuilder(makeBits(SILFunctionTypeRepresentation::Thick, false,
false, false, false, false,
DifferentiabilityKind::NonDifferentiable),
ClangTypeInfo(nullptr)) {}
ClangTypeInfo(nullptr), LifetimeDependenceInfo()) {}

SILExtInfoBuilder(Representation rep, bool isPseudogeneric, bool isNoEscape,
bool isSendable, bool isAsync, bool isUnimplementable,
DifferentiabilityKind diffKind, const clang::Type *type)
: SILExtInfoBuilder(makeBits(rep, isPseudogeneric, isNoEscape,
isSendable, isAsync, isUnimplementable,
diffKind),
ClangTypeInfo(type)) {}
DifferentiabilityKind diffKind, const clang::Type *type,
LifetimeDependenceInfo lifetimeDependenceInfo)
: SILExtInfoBuilder(makeBits(rep, isPseudogeneric, isNoEscape, isSendable,
isAsync, isUnimplementable, diffKind),
ClangTypeInfo(type), lifetimeDependenceInfo) {}

// Constructor for polymorphic type.
SILExtInfoBuilder(ASTExtInfoBuilder info, bool isPseudogeneric)
: SILExtInfoBuilder(makeBits(info.getSILRepresentation(), isPseudogeneric,
info.isNoEscape(), info.isSendable(),
info.isAsync(), /*unimplementable*/ false,
info.getDifferentiabilityKind()),
info.getClangTypeInfo()) {}
info.getClangTypeInfo(),
info.getLifetimeDependenceInfo()) {}

void checkInvariants() const;

Expand Down Expand Up @@ -1008,6 +991,10 @@ class SILExtInfoBuilder {
/// Get the underlying ClangTypeInfo value.
ClangTypeInfo getClangTypeInfo() const { return clangTypeInfo; }

LifetimeDependenceInfo getLifetimeDependenceInfo() const {
return lifetimeDependenceInfo;
}

constexpr bool hasSelfParam() const {
switch (getRepresentation()) {
case Representation::Thick:
Expand Down Expand Up @@ -1057,59 +1044,66 @@ class SILExtInfoBuilder {
SILExtInfoBuilder withRepresentation(Representation rep) const {
return SILExtInfoBuilder((bits & ~RepresentationMask) | (unsigned)rep,
shouldStoreClangType(rep) ? clangTypeInfo
: ClangTypeInfo());
: ClangTypeInfo(),
lifetimeDependenceInfo);
}
[[nodiscard]]
SILExtInfoBuilder withIsPseudogeneric(bool isPseudogeneric = true) const {
return SILExtInfoBuilder(isPseudogeneric ? (bits | PseudogenericMask)
: (bits & ~PseudogenericMask),
clangTypeInfo);
clangTypeInfo, lifetimeDependenceInfo);
}
[[nodiscard]]
SILExtInfoBuilder withNoEscape(bool noEscape = true) const {
return SILExtInfoBuilder(noEscape ? (bits | NoEscapeMask)
: (bits & ~NoEscapeMask),
clangTypeInfo);
clangTypeInfo, lifetimeDependenceInfo);
}
[[nodiscard]]
SILExtInfoBuilder withConcurrent(bool isSendable = true) const {
return SILExtInfoBuilder(isSendable ? (bits | SendableMask)
: (bits & ~SendableMask),
clangTypeInfo);
: (bits & ~SendableMask),
clangTypeInfo, lifetimeDependenceInfo);
}
[[nodiscard]]
SILExtInfoBuilder withAsync(bool isAsync = true) const {
return SILExtInfoBuilder(isAsync ? (bits | AsyncMask) : (bits & ~AsyncMask),
clangTypeInfo);
clangTypeInfo, lifetimeDependenceInfo);
}
[[nodiscard]]
SILExtInfoBuilder withUnimplementable(bool isUnimplementable = true) const {
return SILExtInfoBuilder(isUnimplementable ? (bits | UnimplementableMask)
: (bits & ~UnimplementableMask),
clangTypeInfo);
clangTypeInfo, lifetimeDependenceInfo);
}
[[nodiscard]]
SILExtInfoBuilder
withDifferentiabilityKind(DifferentiabilityKind differentiability) const {
return SILExtInfoBuilder(
(bits & ~DifferentiabilityMask) |
((unsigned)differentiability << DifferentiabilityMaskOffset),
clangTypeInfo);
clangTypeInfo, lifetimeDependenceInfo);
}
[[nodiscard]]
SILExtInfoBuilder withClangFunctionType(const clang::Type *type) const {
return SILExtInfoBuilder(bits, ClangTypeInfo(type).getCanonical());
return SILExtInfoBuilder(bits, ClangTypeInfo(type).getCanonical(),
lifetimeDependenceInfo);
}
[[nodiscard]] SILExtInfoBuilder withLifetimeDependenceInfo(
LifetimeDependenceInfo lifetimeDependenceInfo) const {
return SILExtInfoBuilder(bits, clangTypeInfo, lifetimeDependenceInfo);
}

void Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddInteger(bits);
ID.AddPointer(clangTypeInfo.getType());
lifetimeDependenceInfo.Profile(ID);
}

bool isEqualTo(SILExtInfoBuilder other, bool useClangTypes) const {
return bits == other.bits &&
(useClangTypes ? (clangTypeInfo == other.clangTypeInfo) : true);
}

constexpr std::pair<unsigned, const void *> getFuncAttrKey() const {
return std::make_pair(bits, clangTypeInfo.getType());
}
}; // end SILExtInfoBuilder

// MARK: - SILExtInfo
Expand All @@ -1129,8 +1123,9 @@ class SILExtInfo {
// Only for use by SILExtInfoBuilder::build. Don't use it elsewhere!
SILExtInfo(SILExtInfoBuilder builder) : builder(builder) {}

SILExtInfo(unsigned bits, ClangTypeInfo clangTypeInfo)
: builder(bits, clangTypeInfo) {
SILExtInfo(unsigned bits, ClangTypeInfo clangTypeInfo,
LifetimeDependenceInfo lifetimeDependenceInfo)
: builder(bits, clangTypeInfo, lifetimeDependenceInfo) {
builder.checkInvariants();
};

Expand All @@ -1148,7 +1143,8 @@ class SILExtInfo {
static SILExtInfo getThin() {
return SILExtInfoBuilder(SILExtInfoBuilder::Representation::Thin, false,
false, false, false, false,
DifferentiabilityKind::NonDifferentiable, nullptr)
DifferentiabilityKind::NonDifferentiable, nullptr,
LifetimeDependenceInfo())
.build();
}

Expand Down Expand Up @@ -1187,6 +1183,10 @@ class SILExtInfo {

ClangTypeInfo getClangTypeInfo() const { return builder.getClangTypeInfo(); }

LifetimeDependenceInfo getLifetimeDependenceInfo() const {
return builder.getLifetimeDependenceInfo();
}

constexpr bool hasSelfParam() const { return builder.hasSelfParam(); }

constexpr bool hasContext() const { return builder.hasContext(); }
Expand Down Expand Up @@ -1217,14 +1217,12 @@ class SILExtInfo {
return builder.withUnimplementable(isUnimplementable).build();
}

void Profile(llvm::FoldingSetNodeID &ID) const { builder.Profile(ID); }

bool isEqualTo(SILExtInfo other, bool useClangTypes) const {
return builder.isEqualTo(other.builder, useClangTypes);
}

constexpr std::pair<unsigned, const void *> getFuncAttrKey() const {
return builder.getFuncAttrKey();
}

llvm::Optional<UnexpectedClangTypeError> checkClangType() const;
};

Expand Down
70 changes: 68 additions & 2 deletions include/swift/AST/LifetimeDependence.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,20 @@
#ifndef SWIFT_AST_LIFETIMEDEPENDENCE_H
#define SWIFT_AST_LIFETIMEDEPENDENCE_H

#include "swift/AST/Decl.h"
#include "swift/AST/Identifier.h"
#include "swift/AST/IndexSubset.h"
#include "swift/AST/Ownership.h"
#include "swift/Basic/Debug.h"
#include "swift/Basic/OptionSet.h"
#include "llvm/Support/TrailingObjects.h"
#include "swift/Basic/SourceLoc.h"

#include "llvm/ADT/ArrayRef.h"

namespace swift {

class AbstractFunctionDecl;
class LifetimeDependentReturnTypeRepr;

enum class LifetimeDependenceKind : uint8_t {
Copy = 0,
Consume,
Expand Down Expand Up @@ -93,6 +100,7 @@ class LifetimeDependenceSpecifier {
assert(specifierKind == SpecifierKind::Ordered);
return value.Ordered.index;
}

std::string getParamString() const {
switch (specifierKind) {
case SpecifierKind::Named:
Expand All @@ -104,7 +112,65 @@ class LifetimeDependenceSpecifier {
}
llvm_unreachable("Invalid LifetimeDependenceSpecifier::SpecifierKind");
}

StringRef getLifetimeDependenceKindString() const {
switch (lifetimeDependenceKind) {
case LifetimeDependenceKind::Borrow:
return "_borrow";
case LifetimeDependenceKind::Consume:
return "_consume";
case LifetimeDependenceKind::Copy:
return "_copy";
case LifetimeDependenceKind::Mutate:
return "_mutate";
}
llvm_unreachable(
"Invalid LifetimeDependenceSpecifier::LifetimeDependenceKind");
}
};

class LifetimeDependenceInfo {
IndexSubset *inheritLifetimeParamIndices;
IndexSubset *borrowLifetimeParamIndices;
IndexSubset *mutateLifetimeParamIndices;

static LifetimeDependenceInfo getForParamIndex(AbstractFunctionDecl *afd,
unsigned index,
ValueOwnership ownership);

static llvm::Optional<LifetimeDependenceInfo>
fromTypeRepr(AbstractFunctionDecl *afd, Type resultType, bool allowIndex);

static llvm::Optional<LifetimeDependenceInfo> infer(AbstractFunctionDecl *afd,
Type resultType);

public:
LifetimeDependenceInfo()
: inheritLifetimeParamIndices(nullptr),
borrowLifetimeParamIndices(nullptr),
mutateLifetimeParamIndices(nullptr) {}
LifetimeDependenceInfo(IndexSubset *inheritLifetimeParamIndices,
IndexSubset *borrowLifetimeParamIndices,
IndexSubset *mutateLifetimeParamIndices)
: inheritLifetimeParamIndices(inheritLifetimeParamIndices),
borrowLifetimeParamIndices(borrowLifetimeParamIndices),
mutateLifetimeParamIndices(mutateLifetimeParamIndices) {}

operator bool() const { return !empty(); }

bool empty() const {
return inheritLifetimeParamIndices == nullptr &&
borrowLifetimeParamIndices == nullptr &&
mutateLifetimeParamIndices == nullptr;
}

std::string getString() const;
void Profile(llvm::FoldingSetNodeID &ID) const;

static llvm::Optional<LifetimeDependenceInfo>
get(AbstractFunctionDecl *decl, Type resultType, bool allowIndex = false);
};

} // namespace swift

#endif
Loading