Skip to content

Commit 75ba7a8

Browse files
authored
Merge pull request #80064 from atrick/lifetime-inference
LifetimeDependence: implement strict type checking
2 parents befc15e + d41c4d4 commit 75ba7a8

File tree

70 files changed

+1966
-745
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+1966
-745
lines changed

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceInsertion.swift

+11-8
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,9 @@ private func insertParameterDependencies(apply: LifetimeDependentApply, target:
272272

273273
sources.initializeBases(context)
274274

275+
assert(target.value.type.isAddress,
276+
"lifetime-dependent parameter must be 'inout'")
277+
275278
Builder.insert(after: apply.applySite, context) {
276279
insertMarkDependencies(value: target.value, initializer: nil, bases: sources.bases, builder: $0, context)
277280
}
@@ -285,14 +288,14 @@ private func insertMarkDependencies(value: Value, initializer: Instruction?,
285288
let markDep = builder.createMarkDependence(
286289
value: currentValue, base: base, kind: .Unresolved)
287290

288-
// Address dependencies cannot be represented as SSA values, so it does not make sense to replace any uses of the
289-
// dependent address.
290-
//
291-
// TODO: either (1) insert a separate mark_dependence_addr instruction with no return value, or (2) perform data
292-
// flow to replace all reachable address uses, and if any aren't dominated by base, then insert an extra
293-
// escaping mark_dependence at this apply site that directly uses the mark_dependence [nonescaping] to force
294-
// diagnostics to fail.
295-
if !value.type.isAddress {
291+
if value.type.isAddress {
292+
// Address dependencies cannot be represented as SSA values, so it does not make sense to replace any uses of the
293+
// dependent address.
294+
//
295+
// TODO: insert a separate mark_dependence_addr instruction with no return value and do not update currentValue.
296+
} else {
297+
// TODO: implement non-inout parameter dependencies. This assumes that currentValue is the apply immediately
298+
// preceeding the mark_dependence.
296299
let uses = currentValue.uses.lazy.filter {
297300
if $0.isScopeEndingUse {
298301
return false

include/swift/AST/DiagnosticsSema.def

+69-31
Original file line numberDiff line numberDiff line change
@@ -8089,7 +8089,7 @@ ERROR(pack_iteration_where_clause_not_supported, none,
80898089

80908090

80918091
//------------------------------------------------------------------------------
8092-
// MARK: Lifetime Dependence Diagnostics
8092+
// MARK: Lifetime Dependence Syntax
80938093
//------------------------------------------------------------------------------
80948094

80958095
ERROR(lifetime_dependence_invalid_param_name, none,
@@ -8108,34 +8108,15 @@ ERROR(lifetime_dependence_cannot_use_kind, none,
81088108
ERROR(lifetime_dependence_cannot_use_parsed_scoped_consuming, none,
81098109
"invalid use of scoped lifetime dependence with consuming ownership",
81108110
())
8111-
ERROR(lifetime_dependence_cannot_use_inferred_scoped_consuming, none,
8112-
"invalid use of lifetime dependence on an Escapable parameter with "
8113-
"consuming ownership",
8114-
())
8115-
ERROR(lifetime_dependence_invalid_self_ownership, none,
8116-
"invalid scoped lifetime dependence on an Escapable self with consuming "
8117-
"ownership",
8118-
())
81198111
ERROR(lifetime_dependence_only_on_function_method_init_result, none,
81208112
"lifetime dependence specifiers may only be used on result of "
81218113
"functions, methods, initializers", ())
8122-
ERROR(lifetime_dependence_invalid_type, none,
8123-
"lifetime dependence can only be specified on ~Escapable types", ())
8124-
ERROR(lifetime_dependence_cannot_infer_ambiguous_candidate, none,
8125-
"cannot infer lifetime dependence %0, multiple parameters qualifiy as a candidate", (StringRef))
8126-
ERROR(lifetime_dependence_cannot_infer_no_candidates, none,
8127-
"cannot infer lifetime dependence%0, no parameters found that are either "
8128-
"~Escapable or Escapable with a borrowing ownership", (StringRef))
8129-
ERROR(lifetime_dependence_ctor_non_self_or_nil_return, none,
8130-
"expected nil or self as return values in an initializer with "
8131-
"lifetime dependent specifiers",
8132-
())
8133-
ERROR(lifetime_dependence_cannot_be_applied_to_tuple_elt, none,
8134-
"lifetime dependence specifiers cannot be applied to tuple elements", ())
8135-
ERROR(lifetime_dependence_method_escapable_bitwisecopyable_self, none,
8136-
"cannot infer lifetime dependence on a self which is BitwiseCopyable & "
8137-
"Escapable",
8114+
ERROR(lifetime_dependence_ctor_non_self_or_nil_return, none,
8115+
"expected 'nil' or 'self' as return values in an initializer with "
8116+
"lifetime dependent specifiers",
81388117
())
8118+
ERROR(lifetime_dependence_cannot_be_applied_to_tuple_elt, none,
8119+
"lifetime dependence specifiers cannot be applied to tuple elements", ())
81398120
ERROR(lifetime_dependence_immortal_conflict_name, none,
81408121
"conflict between the parameter name and 'immortal' contextual keyword", ())
81418122
ERROR(lifetime_dependence_function_type, none,
@@ -8144,18 +8125,75 @@ ERROR(lifetime_dependence_function_type, none,
81448125
ERROR(lifetime_dependence_immortal_alone, none,
81458126
"cannot specify any other dependence source along with immortal", ())
81468127
ERROR(lifetime_dependence_invalid_inherit_escapable_type, none,
8147-
"invalid lifetime dependence on a source of Escapable type, use borrow "
8148-
"dependence instead",
8149-
())
8128+
"cannot copy the lifetime of an Escapable type, use "
8129+
"'@lifetime(borrow %0)' instead",
8130+
(StringRef))
81508131
ERROR(lifetime_dependence_cannot_use_parsed_borrow_consuming, none,
81518132
"invalid use of borrow dependence with consuming ownership",
81528133
())
8134+
ERROR(lifetime_dependence_cannot_use_parsed_borrow_inout, none,
8135+
"invalid use of borrow dependence on the same inout parameter",
8136+
())
81538137
ERROR(lifetime_dependence_duplicate_target, none,
81548138
"invalid duplicate target lifetime dependencies on function", ())
8139+
ERROR(lifetime_parameter_requires_inout, none,
8140+
"lifetime-dependent parameter must be 'inout'", (Identifier))
8141+
8142+
//------------------------------------------------------------------------------
8143+
// MARK: Lifetime Dependence Requirements
8144+
//------------------------------------------------------------------------------
8145+
8146+
ERROR(lifetime_dependence_feature_required_return, none,
8147+
"%0 with a ~Escapable result requires "
8148+
"'-enable-experimental-feature LifetimeDependence'", (StringRef))
8149+
ERROR(lifetime_dependence_feature_required_mutating, none,
8150+
"%0 with ~Escapable 'self' requires "
8151+
"'-enable-experimental-feature LifetimeDependence'", (StringRef))
8152+
ERROR(lifetime_dependence_feature_required_inout, none,
8153+
"%0 with a ~Escapable 'inout' parameter requires "
8154+
"'-enable-experimental-feature LifetimeDependence'",
8155+
// arg list is interchangable with lifetime_dependence_cannot_infer_inout
8156+
(StringRef, Identifier))
8157+
8158+
ERROR(lifetime_dependence_cannot_infer_return, none,
8159+
"%0 with a ~Escapable result requires '@lifetime(...)'", (StringRef))
8160+
ERROR(lifetime_dependence_cannot_infer_mutating, none,
8161+
"%0 with a ~Escapable 'self' requires '@lifetime(self: ...)'", (StringRef))
8162+
ERROR(lifetime_dependence_cannot_infer_inout, none,
8163+
"%0 with a ~Escapable 'inout' parameter requires '@lifetime(%1: ...)'",
8164+
(StringRef, Identifier))
8165+
8166+
//------------------------------------------------------------------------------
8167+
// MARK: Lifetime Dependence Inference - refinements to the requirements above
8168+
//------------------------------------------------------------------------------
81558169

8156-
ERROR(lifetime_dependence_feature_required, none,
8157-
"returning ~Escapable type requires '-enable-experimental-feature "
8158-
"LifetimeDependence'", ())
8170+
ERROR(lifetime_dependence_cannot_infer_return_no_param, none,
8171+
"%0 with a ~Escapable result needs a parameter to depend on",
8172+
(StringRef))
8173+
NOTE(lifetime_dependence_cannot_infer_return_immortal, none,
8174+
"'@lifetime(immortal)' can be used to indicate that values produced by "
8175+
"this initializer have no lifetime dependencies", ())
8176+
ERROR(lifetime_dependence_cannot_infer_bitwisecopyable, none,
8177+
"cannot infer lifetime dependence on %0 because '%1' is BitwiseCopyable, "
8178+
"specify '@lifetime(borrow self)'",
8179+
(StringRef, StringRef))
8180+
ERROR(lifetime_dependence_cannot_infer_kind, none,
8181+
"cannot infer the lifetime dependence scope on %0 with a ~Escapable "
8182+
"parameter, specify '@lifetime(borrow %1)' or '@lifetime(copy %1)'",
8183+
(StringRef, StringRef))
8184+
ERROR(lifetime_dependence_cannot_infer_scope_ownership, none,
8185+
"cannot borrow the lifetime of '%0', which has consuming ownership on %1",
8186+
(StringRef, StringRef))
8187+
8188+
//------------------------------------------------------------------------------
8189+
// MARK: Lifetime Dependence Experimental Inference
8190+
//------------------------------------------------------------------------------
8191+
8192+
ERROR(lifetime_dependence_cannot_infer_no_candidates, none,
8193+
"cannot infer lifetime dependence%0, no parameters found that are either "
8194+
"~Escapable or Escapable with a borrowing ownership", (StringRef))
8195+
ERROR(lifetime_dependence_cannot_infer_ambiguous_candidate, none,
8196+
"cannot infer lifetime dependence%0, multiple parameters qualify as a candidate", (StringRef))
81598197

81608198
//===----------------------------------------------------------------------===//
81618199
// MARK: Sending

include/swift/AST/LifetimeDependence.h

+10-30
Original file line numberDiff line numberDiff line change
@@ -206,9 +206,15 @@ class LifetimeEntry final
206206
if (!firstElem) {
207207
result += ", ";
208208
}
209-
if (source.getParsedLifetimeDependenceKind() ==
210-
ParsedLifetimeDependenceKind::Scope) {
209+
switch (source.getParsedLifetimeDependenceKind()) {
210+
case ParsedLifetimeDependenceKind::Scope:
211211
result += "borrow ";
212+
break;
213+
case ParsedLifetimeDependenceKind::Inherit:
214+
result += "copy ";
215+
break;
216+
default:
217+
break;
212218
}
213219
result += source.getString();
214220
firstElem = false;
@@ -227,32 +233,6 @@ class LifetimeDependenceInfo {
227233

228234
unsigned targetIndex;
229235

230-
static LifetimeDependenceInfo getForIndex(AbstractFunctionDecl *afd,
231-
unsigned targetIndex,
232-
unsigned sourceIndex,
233-
LifetimeDependenceKind kind);
234-
235-
/// Builds LifetimeDependenceInfo from @lifetime attribute
236-
static std::optional<ArrayRef<LifetimeDependenceInfo>>
237-
fromLifetimeAttribute(AbstractFunctionDecl *afd);
238-
239-
/// Infer LifetimeDependenceInfo on result
240-
static std::optional<LifetimeDependenceInfo> infer(AbstractFunctionDecl *afd);
241-
242-
/// Infer LifetimeDependenceInfo on setter
243-
static std::optional<LifetimeDependenceInfo>
244-
inferSetter(AbstractFunctionDecl *afd);
245-
246-
/// Infer LifetimeDependenceInfo on mutating self
247-
static std::optional<LifetimeDependenceInfo>
248-
inferMutatingSelf(AbstractFunctionDecl *afd);
249-
250-
/// Builds LifetimeDependenceInfo from SIL function type
251-
static std::optional<LifetimeDependenceInfo>
252-
fromDependsOn(LifetimeDependentTypeRepr *lifetimeDependentRepr,
253-
unsigned targetIndex, ArrayRef<SILParameterInfo> params,
254-
DeclContext *dc);
255-
256236
public:
257237
LifetimeDependenceInfo(IndexSubset *inheritLifetimeParamIndices,
258238
IndexSubset *scopeLifetimeParamIndices,
@@ -350,8 +330,8 @@ class LifetimeDependenceInfo {
350330

351331
/// Builds LifetimeDependenceInfo from SIL
352332
static std::optional<llvm::ArrayRef<LifetimeDependenceInfo>>
353-
get(FunctionTypeRepr *funcRepr, ArrayRef<SILParameterInfo> params,
354-
ArrayRef<SILResultInfo> results, DeclContext *dc);
333+
getFromSIL(FunctionTypeRepr *funcRepr, ArrayRef<SILParameterInfo> params,
334+
ArrayRef<SILResultInfo> results, DeclContext *dc);
355335

356336
bool operator==(const LifetimeDependenceInfo &other) const {
357337
return this->isImmortal() == other.isImmortal() &&

include/swift/AST/Types.h

+2
Original file line numberDiff line numberDiff line change
@@ -5574,6 +5574,8 @@ class SILFunctionType final
55745574
return NumLifetimeDependencies != 0;
55755575
}
55765576

5577+
// Return lowered lifetime dependencies, which has remapped parameter indices
5578+
// relative to the original FunctionType.
55775579
ArrayRef<LifetimeDependenceInfo> getLifetimeDependencies() const {
55785580
if (!hasLifetimeDependencies())
55795581
return std::nullopt;

include/swift/Basic/LangOptions.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -598,7 +598,7 @@ namespace swift {
598598
bool EnableRequirementMachineOpaqueArchetypes = false;
599599

600600
/// Enable implicit lifetime dependence for ~Escapable return types.
601-
bool EnableExperimentalLifetimeDependenceInference = true;
601+
bool EnableExperimentalLifetimeDependenceInference = false;
602602

603603
/// Skips decls that cannot be referenced externally.
604604
bool SkipNonExportableDecls = false;

0 commit comments

Comments
 (0)