Skip to content

Commit d6d7b03

Browse files
committed
[NFC] Refactor out common utilities to be used by lifetime attribute
1 parent 7b8665b commit d6d7b03

File tree

2 files changed

+132
-117
lines changed

2 files changed

+132
-117
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7943,6 +7943,9 @@ ERROR(lifetime_dependence_function_type, none,
79437943
"lifetime dependencies on function types are not supported",
79447944
())
79457945

7946+
ERROR(lifetime_dependence_immortal_alone, none,
7947+
"cannot specify any other dependence source along with immortal", ())
7948+
79467949
//===----------------------------------------------------------------------===//
79477950
// MARK: Sending
79487951
//===----------------------------------------------------------------------===//

lib/AST/LifetimeDependence.cpp

Lines changed: 129 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,112 @@ getLifetimeDependenceKind(LifetimeEntry specifier, AbstractFunctionDecl *afd,
240240
return lifetimeKind;
241241
}
242242

243+
static bool populateLifetimeDependence(AbstractFunctionDecl *afd,
244+
LifetimeEntry entry,
245+
SmallBitVector &inheritIndices,
246+
SmallBitVector &scopeIndices,
247+
bool &isImmortal) {
248+
auto updateLifetimeIndices =
249+
[&](LifetimeEntry entry, unsigned paramIndexToSet,
250+
std::optional<LifetimeDependenceKind> lifetimeKind) {
251+
auto loc = entry.getLoc();
252+
if (!lifetimeKind.has_value()) {
253+
return true;
254+
}
255+
if (inheritIndices.test(paramIndexToSet) ||
256+
scopeIndices.test(paramIndexToSet)) {
257+
diags.diagnose(loc, diag::lifetime_dependence_duplicate_param_id);
258+
return true;
259+
}
260+
if (lifetimeKind == LifetimeDependenceKind::Inherit) {
261+
inheritIndices.set(paramIndexToSet);
262+
} else {
263+
assert(lifetimeKind == LifetimeDependenceKind::Scope);
264+
scopeIndices.set(paramIndexToSet);
265+
}
266+
return false;
267+
};
268+
269+
switch (entry.getLifetimeEntryKind()) {
270+
case LifetimeEntryKind::Immortal: {
271+
auto immortalParam =
272+
std::find_if(afd->getParameters()->begin(), afd->getParameters()->end(),
273+
[](ParamDecl *param) {
274+
return strcmp(param->getName().get(), "immortal") == 0;
275+
});
276+
if (immortalParam != afd->getParameters()->end()) {
277+
diags.diagnose(*immortalParam,
278+
diag::lifetime_dependence_immortal_conflict_name);
279+
return true;
280+
}
281+
if (inheritIndicies.any() || scopeIndices.any()) {
282+
diags.diagnose(entry.getLoc(), diag::lifetime_dependence_immortal_alone);
283+
return true;
284+
}
285+
isImmortal = true;
286+
return false;
287+
}
288+
case LifetimeEntryKind::Named: {
289+
unsigned paramIndex = 0;
290+
ParamDecl *candidateParam = nullptr;
291+
for (auto *param : *afd->getParameters()) {
292+
if (param->getParameterName() == entry.getName()) {
293+
candidateParam = param;
294+
break;
295+
}
296+
paramIndex++;
297+
}
298+
if (!candidateParam) {
299+
diags.diagnose(entry.getLoc(),
300+
diag::lifetime_dependence_invalid_param_name,
301+
entry.getName());
302+
return true;
303+
}
304+
if (isImmortal) {
305+
diags.diagnose(entry.getLoc(), diag::lifetime_dependence_immortal_alone);
306+
return true;
307+
}
308+
auto lifetimeKind = getLifetimeDependenceKind(entry, afd, candidateParam);
309+
return updateLifetimeIndices(entry, paramIndex, lifetimeKind);
310+
}
311+
case LifetimeEntryKind::Ordered: {
312+
auto index = entry.getIndex();
313+
if (index >= afd->getParameters()->size()) {
314+
diags.diagnose(entry.getLoc(),
315+
diag::lifetime_dependence_invalid_param_index, index);
316+
return true;
317+
}
318+
if (isImmortal) {
319+
diags.diagnose(entry.getLoc(), diag::lifetime_dependence_immortal_alone);
320+
return true;
321+
}
322+
auto candidateParam = afd->getParameters()->get(index);
323+
auto lifetimeKind = getLifetimeDependenceKind(entry, afd, candidateParam);
324+
return updateLifetimeIndices(entry, index, lifetimeKind);
325+
}
326+
case LifetimeEntryKind::Self: {
327+
if (!afd->hasImplicitSelfDecl()) {
328+
diags.diagnose(entry.getLoc(),
329+
diag::lifetime_dependence_invalid_self_in_static);
330+
return true;
331+
}
332+
if (isa<ConstructorDecl>(afd)) {
333+
diags.diagnose(entry.getLoc(),
334+
diag::lifetime_dependence_invalid_self_in_init);
335+
return true;
336+
}
337+
if (isImmortal) {
338+
diags.diagnose(entry.getLoc(), diag::lifetime_dependence_immortal_alone);
339+
return true;
340+
}
341+
auto *selfDecl = afd->getImplicitSelfDecl();
342+
auto lifetimeKind = getLifetimeDependenceKind(entry, afd, selfDecl);
343+
return updateLifetimeIndices(
344+
entry, /* selfIndex */ afd->getParameters()->size(), lifetimeKind);
345+
}
346+
}
347+
}
348+
243349
std::optional<LifetimeDependenceInfo>
244350
LifetimeDependenceInfo::fromDependsOn(AbstractFunctionDecl *afd,
245351
TypeRepr *targetTypeRepr, Type targetType,
@@ -264,122 +370,28 @@ LifetimeDependenceInfo::fromDependsOn(AbstractFunctionDecl *afd,
264370
? (afd->getParameters()->size() + 1)
265371
: afd->getParameters()->size();
266372

267-
SmallBitVector inheritLifetimeParamIndices(capacity);
268-
SmallBitVector scopeLifetimeParamIndices(capacity);
373+
SmallBitVector inheritIndices(capacity);
374+
SmallBitVector scopeIndices(capacity);
375+
bool isImmortal = false;
376+
bool hasError = false;
269377

270-
auto updateLifetimeDependenceInfo =
271-
[&](LifetimeEntry specifier, unsigned paramIndexToSet,
272-
std::optional<LifetimeDependenceKind> lifetimeKind) {
273-
auto loc = specifier.getLoc();
274-
if (!lifetimeKind.has_value()) {
275-
return true;
276-
}
277-
if (inheritLifetimeParamIndices.test(paramIndexToSet) ||
278-
scopeLifetimeParamIndices.test(paramIndexToSet)) {
279-
diags.diagnose(loc, diag::lifetime_dependence_duplicate_param_id);
280-
return true;
281-
}
282-
if (lifetimeKind == LifetimeDependenceKind::Inherit) {
283-
inheritLifetimeParamIndices.set(paramIndexToSet);
284-
} else {
285-
assert(lifetimeKind == LifetimeDependenceKind::Scope);
286-
scopeLifetimeParamIndices.set(paramIndexToSet);
287-
}
288-
return false;
289-
};
290-
291-
for (auto specifier : lifetimeDependentRepr->getLifetimeDependencies()) {
292-
switch (specifier.getLifetimeEntryKind()) {
293-
case LifetimeEntryKind::Immortal: {
294-
auto immortalParam =
295-
std::find_if(afd->getParameters()->begin(),
296-
afd->getParameters()->end(), [](ParamDecl *param) {
297-
return strcmp(param->getName().get(), "immortal") == 0;
298-
});
299-
if (immortalParam != afd->getParameters()->end()) {
300-
diags.diagnose(*immortalParam,
301-
diag::lifetime_dependence_immortal_conflict_name);
302-
}
303-
304-
return LifetimeDependenceInfo(nullptr, nullptr, targetIndex,
305-
/*isImmortal*/ true);
306-
}
307-
case LifetimeEntryKind::Named: {
308-
unsigned paramIndex = 0;
309-
ParamDecl *candidateParam = nullptr;
310-
for (auto *param : *afd->getParameters()) {
311-
if (param->getParameterName() == specifier.getName()) {
312-
candidateParam = param;
313-
break;
314-
}
315-
paramIndex++;
316-
}
317-
if (!candidateParam) {
318-
diags.diagnose(specifier.getLoc(),
319-
diag::lifetime_dependence_invalid_param_name,
320-
specifier.getName());
321-
return std::nullopt;
322-
}
323-
auto lifetimeKind =
324-
getLifetimeDependenceKind(specifier, afd, candidateParam);
325-
if (updateLifetimeDependenceInfo(specifier, paramIndex, lifetimeKind)) {
326-
return std::nullopt;
327-
}
328-
329-
break;
330-
}
331-
case LifetimeEntryKind::Ordered: {
332-
auto index = specifier.getIndex();
333-
if (index >= afd->getParameters()->size()) {
334-
diags.diagnose(specifier.getLoc(),
335-
diag::lifetime_dependence_invalid_param_index, index);
336-
return std::nullopt;
337-
}
338-
auto candidateParam = afd->getParameters()->get(index);
339-
auto lifetimeKind =
340-
getLifetimeDependenceKind(specifier, afd, candidateParam);
341-
if (updateLifetimeDependenceInfo(specifier, index, lifetimeKind)) {
342-
return std::nullopt;
343-
}
344-
break;
345-
}
346-
case LifetimeEntryKind::Self: {
347-
if (!afd->hasImplicitSelfDecl()) {
348-
diags.diagnose(specifier.getLoc(),
349-
diag::lifetime_dependence_invalid_self_in_static);
350-
return std::nullopt;
351-
}
352-
if (isa<ConstructorDecl>(afd)) {
353-
diags.diagnose(specifier.getLoc(),
354-
diag::lifetime_dependence_invalid_self_in_init);
355-
return std::nullopt;
356-
}
357-
auto *selfDecl = afd->getImplicitSelfDecl();
358-
auto lifetimeKind = getLifetimeDependenceKind(specifier, afd, selfDecl);
359-
if (updateLifetimeDependenceInfo(
360-
specifier, /* selfIndex */ afd->getParameters()->size(),
361-
lifetimeKind)) {
362-
return std::nullopt;
363-
}
364-
break;
365-
}
366-
}
378+
for (auto entry : lifetimeDependentRepr->getLifetimeDependencies()) {
379+
hasError |= populateLifetimeDependence(afd, entry, inheritIndices,
380+
scopeIndices, isImmortal);
367381
}
368382

383+
if (hasError) {
384+
return std::nullopt;
385+
}
369386
return LifetimeDependenceInfo(
370-
inheritLifetimeParamIndices.any()
371-
? IndexSubset::get(ctx, inheritLifetimeParamIndices)
372-
: nullptr,
373-
scopeLifetimeParamIndices.any()
374-
? IndexSubset::get(ctx, scopeLifetimeParamIndices)
375-
: nullptr,
376-
targetIndex,
377-
/*isImmortal*/ false);
387+
inheritIndices.any() ? IndexSubset::get(ctx, inheritIndices) : nullptr,
388+
scopeIndices.any() ? IndexSubset::get(ctx, scopeIndices) : nullptr,
389+
targetIndex, isImmortal);
378390
}
379391

380392
// This utility is similar to its overloaded version that builds the
381-
// LifetimeDependenceInfo from the swift decl. Reason for duplicated code is the
382-
// apis on type and ownership is different in SIL compared to Sema.
393+
// LifetimeDependenceInfo from the swift decl. Reason for duplicated code is
394+
// the apis on type and ownership is different in SIL compared to Sema.
383395
std::optional<LifetimeDependenceInfo> LifetimeDependenceInfo::fromDependsOn(
384396
LifetimeDependentTypeRepr *lifetimeDependentRepr, unsigned targetIndex,
385397
ArrayRef<SILParameterInfo> params, DeclContext *dc) {
@@ -476,10 +488,10 @@ LifetimeDependenceInfo::infer(AbstractFunctionDecl *afd) {
476488
// Infer self dependence for a mutating function with no result.
477489
//
478490
// FIXME: temporary hack until we have dependsOn(self: param) syntax.
479-
// Do not apply this to accessors (_modify). _modify is handled below like a
480-
// mutating method.
481-
if (fd->isMutating() && fd->getResultInterfaceType()->isVoid()
482-
&& !dc->getSelfTypeInContext()->isEscapable()) {
491+
// Do not apply this to accessors (_modify). _modify is handled below like
492+
// a mutating method.
493+
if (fd->isMutating() && fd->getResultInterfaceType()->isVoid() &&
494+
!dc->getSelfTypeInContext()->isEscapable()) {
483495
return inferMutatingSelf(afd);
484496
}
485497
}
@@ -510,10 +522,10 @@ LifetimeDependenceInfo::infer(AbstractFunctionDecl *afd) {
510522
Type selfTypeInContext = dc->getSelfTypeInContext();
511523
if (selfTypeInContext->isEscapable()) {
512524
if (isBitwiseCopyable(selfTypeInContext, ctx)) {
513-
diags.diagnose(
514-
returnLoc,
515-
diag::lifetime_dependence_method_escapable_bitwisecopyable_self);
516-
return std::nullopt;
525+
diags.diagnose(
526+
returnLoc,
527+
diag::lifetime_dependence_method_escapable_bitwisecopyable_self);
528+
return std::nullopt;
517529
}
518530
}
519531
auto kind = getLifetimeDependenceKindFromType(selfTypeInContext);

0 commit comments

Comments
 (0)