Skip to content

Commit 7b63bbd

Browse files
committed
Merge remote-tracking branch 'origin/main' into rebranch
2 parents 92050c1 + cee2aea commit 7b63bbd

13 files changed

+362
-67
lines changed

include/swift/AST/Concurrency.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@
1919

2020
namespace swift {
2121

22+
/// Find the imported module that treats the given nominal type as "preconcurrency", or return `nullptr`
23+
/// if there is no such module.
24+
ModuleDecl *moduleImportForPreconcurrency(NominalTypeDecl *nominal,
25+
const DeclContext *fromDC);
26+
2227
/// Determinate the appropriate diagnostic behavior to used when emitting
2328
/// concurrency diagnostics when referencing the given nominal type from the
2429
/// given declaration context.

include/swift/AST/DiagnosticEngine.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,12 @@ namespace swift {
401401
/// until the next major language version.
402402
InFlightDiagnostic &warnUntilFutureSwiftVersion();
403403

404+
InFlightDiagnostic &warnUntilFutureSwiftVersionIf(bool shouldLimit) {
405+
if (!shouldLimit)
406+
return *this;
407+
return warnUntilFutureSwiftVersion();
408+
}
409+
404410
/// Limit the diagnostic behavior to warning until the specified version.
405411
///
406412
/// This helps stage in fixes for stricter diagnostics as warnings

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8685,9 +8685,9 @@ GROUPED_ERROR(isolated_conformance_wrong_domain,IsolatedConformances,none,
86858685
GROUPED_WARNING(isolated_conformance_will_become_nonisolated,IsolatedConformances,none,
86868686
"conformance of %0 to %1 should be marked 'nonisolated' to retain its behavior with upcoming feature 'InferIsolatedConformances'",
86878687
(const ValueDecl *, const ValueDecl *))
8688-
GROUPED_WARNING(isolated_conformance_to_sendable_metatype,IsolatedConformances,none,
8689-
"%0 conformance of %1 to SendableMetatype-inheriting %kind2 can never "
8690-
"be used with generic code", (ActorIsolation, Type, const ValueDecl *))
8688+
GROUPED_ERROR(isolated_conformance_to_sendable_metatype,IsolatedConformances,none,
8689+
"cannot form %0 conformance of %1 to SendableMetatype-inheriting %kind2",
8690+
(ActorIsolation, Type, const ValueDecl *))
86918691
86928692
//===----------------------------------------------------------------------===//
86938693
// MARK: @_inheritActorContext

lib/AST/Concurrency.cpp

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,29 +19,35 @@
1919

2020
using namespace swift;
2121

22-
std::optional<DiagnosticBehavior>
23-
swift::getConcurrencyDiagnosticBehaviorLimit(NominalTypeDecl *nominal,
24-
const DeclContext *fromDC,
25-
bool ignoreExplicitConformance) {
26-
ModuleDecl *importedModule = nullptr;
22+
ModuleDecl *swift::moduleImportForPreconcurrency(
23+
NominalTypeDecl *nominal, const DeclContext *fromDC) {
24+
// If the declaration itself has the @preconcurrency attribute,
25+
// respect it.
2726
if (nominal->getAttrs().hasAttribute<PreconcurrencyAttr>()) {
28-
// If the declaration itself has the @preconcurrency attribute,
29-
// respect it.
30-
importedModule = nominal->getParentModule();
31-
} else {
32-
// Determine whether this nominal type is visible via a @preconcurrency
33-
// import.
34-
auto import = nominal->findImport(fromDC);
35-
auto sourceFile = fromDC->getParentSourceFile();
27+
return nominal->getParentModule();
28+
}
3629

37-
if (!import || !import->options.contains(ImportFlags::Preconcurrency))
38-
return std::nullopt;
30+
// Determine whether this nominal type is visible via a @preconcurrency
31+
// import.
32+
auto import = nominal->findImport(fromDC);
33+
auto sourceFile = fromDC->getParentSourceFile();
3934

40-
if (sourceFile)
41-
sourceFile->setImportUsedPreconcurrency(*import);
35+
if (!import || !import->options.contains(ImportFlags::Preconcurrency))
36+
return nullptr;
4237

43-
importedModule = import->module.importedModule;
44-
}
38+
if (sourceFile)
39+
sourceFile->setImportUsedPreconcurrency(*import);
40+
41+
return import->module.importedModule;
42+
}
43+
44+
std::optional<DiagnosticBehavior>
45+
swift::getConcurrencyDiagnosticBehaviorLimit(NominalTypeDecl *nominal,
46+
const DeclContext *fromDC,
47+
bool ignoreExplicitConformance) {
48+
ModuleDecl *importedModule = moduleImportForPreconcurrency(nominal, fromDC);
49+
if (!importedModule)
50+
return std::nullopt;
4551

4652
// When the type is explicitly non-Sendable, @preconcurrency imports
4753
// downgrade the diagnostic to a warning in Swift 6.

lib/SILGen/SILGenExpr.cpp

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7295,19 +7295,34 @@ RValue RValueEmitter::visitMacroExpansionExpr(MacroExpansionExpr *E,
72957295

72967296
RValue RValueEmitter::visitCurrentContextIsolationExpr(
72977297
CurrentContextIsolationExpr *E, SGFContext C) {
7298-
// If we are in an actor initializer that is isolated to self, the
7299-
// current isolation is flow-sensitive; use that instead of the
7300-
// synthesized expression.
7301-
if (auto ctor = dyn_cast_or_null<ConstructorDecl>(
7302-
SGF.F.getDeclRef().getDecl())) {
7303-
auto isolation = getActorIsolation(ctor);
7304-
if (ctor->isDesignatedInit() &&
7298+
auto afd =
7299+
dyn_cast_or_null<AbstractFunctionDecl>(SGF.F.getDeclRef().getDecl());
7300+
if (afd) {
7301+
auto isolation = getActorIsolation(afd);
7302+
auto ctor = dyn_cast_or_null<ConstructorDecl>(afd);
7303+
if (ctor && ctor->isDesignatedInit() &&
73057304
isolation == ActorIsolation::ActorInstance &&
73067305
isolation.getActorInstance() == ctor->getImplicitSelfDecl()) {
7306+
// If we are in an actor initializer that is isolated to self, the
7307+
// current isolation is flow-sensitive; use that instead of the
7308+
// synthesized expression.
73077309
auto isolationValue =
73087310
SGF.emitFlowSensitiveSelfIsolation(E, isolation);
73097311
return RValue(SGF, E, isolationValue);
73107312
}
7313+
7314+
if (isolation == ActorIsolation::CallerIsolationInheriting) {
7315+
auto *isolatedArg = SGF.F.maybeGetIsolatedArgument();
7316+
assert(isolatedArg &&
7317+
"Caller Isolation Inheriting without isolated parameter");
7318+
ManagedValue isolatedMV;
7319+
if (isolatedArg->getOwnershipKind() == OwnershipKind::Guaranteed) {
7320+
isolatedMV = ManagedValue::forBorrowedRValue(isolatedArg);
7321+
} else {
7322+
isolatedMV = ManagedValue::forUnmanagedOwnedValue(isolatedArg);
7323+
}
7324+
return RValue(SGF, E, isolatedMV);
7325+
}
73117326
}
73127327

73137328
return visit(E->getActor(), C);

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4391,10 +4391,15 @@ namespace {
43914391

43924392
case ActorIsolation::Unspecified:
43934393
case ActorIsolation::Nonisolated:
4394-
case ActorIsolation::CallerIsolationInheriting:
43954394
case ActorIsolation::NonisolatedUnsafe:
43964395
actorExpr = new (ctx) NilLiteralExpr(loc, /*implicit=*/false);
43974396
break;
4397+
case ActorIsolation::CallerIsolationInheriting:
4398+
// For caller isolation this expression will be replaced in SILGen
4399+
// because we're adding an implicit isolated parameter that #isolated
4400+
// must resolve to, but cannot do so during AST expansion quite yet.
4401+
actorExpr = new (ctx) NilLiteralExpr(loc, /*implicit=*/false);
4402+
break;
43984403
}
43994404

44004405

@@ -8303,18 +8308,20 @@ RawConformanceIsolationRequest::evaluate(
83038308
globalActorTypeExpr->setType(MetatypeType::get(globalActorType));
83048309
}
83058310

8306-
// Isolated conformance to a SendableMetatype-inheriting protocol can
8307-
// never be used generically. Warn about it.
8311+
// Cannot form an isolated conformance to a SendableMetatype-inheriting
8312+
// protocol. Diagnose it.
83088313
if (auto sendableMetatype =
83098314
ctx.getProtocol(KnownProtocolKind::SendableMetatype)) {
8310-
if (proto->inheritsFrom(sendableMetatype) &&
8311-
!getActorIsolation(proto).preconcurrency()) {
8315+
if (proto->inheritsFrom(sendableMetatype)) {
8316+
bool isPreconcurrency = moduleImportForPreconcurrency(
8317+
proto, conformance->getDeclContext()) != nullptr;
83128318
ctx.Diags.diagnose(
83138319
conformance->getLoc(),
83148320
diag::isolated_conformance_to_sendable_metatype,
83158321
ActorIsolation::forGlobalActor(globalActorType),
83168322
conformance->getType(),
8317-
proto);
8323+
proto)
8324+
.limitBehaviorIf(isPreconcurrency, DiagnosticBehavior::Warning);
83188325
}
83198326
}
83208327

lib/Sema/TypeCheckGeneric.cpp

Lines changed: 138 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -267,49 +267,157 @@ OpaqueResultTypeRequest::evaluate(Evaluator &evaluator,
267267
return opaqueDecl;
268268
}
269269

270-
/// Determine whether the given type is \c Self, an associated type of \c Self,
271-
/// or a concrete type.
272-
static bool isSelfDerivedOrConcrete(Type protoSelf, Type type) {
273-
// Check for a concrete type.
274-
if (!type->hasTypeParameter())
275-
return true;
270+
static bool checkProtocolSelfRequirementsImpl(
271+
ASTContext &ctx, ProtocolDecl *proto, ValueDecl *decl,
272+
GenericSignature originalSig,
273+
GenericSignature effectiveSig,
274+
bool downgrade,
275+
bool *hasSameTypeRequirement) {
276+
if (hasSameTypeRequirement)
277+
*hasSameTypeRequirement = false;
278+
279+
for (auto req : effectiveSig.getRequirements()) {
280+
if (req.getKind() == RequirementKind::SameType)
281+
if (hasSameTypeRequirement)
282+
*hasSameTypeRequirement = true;
283+
284+
// The conformance of 'Self' to the protocol is okay.
285+
if (req.getKind() == RequirementKind::Conformance &&
286+
req.getProtocolDecl() == proto &&
287+
req.getFirstType()->isEqual(ctx.TheSelfType))
288+
continue;
289+
290+
auto isSelfDerived = [&](Type t) -> bool {
291+
return t->getRootGenericParam()->isEqual(ctx.TheSelfType);
292+
};
293+
294+
// If the requirement's subject type is rooted in an inner generic
295+
// parameter, this requirement is okay.
296+
if (!isSelfDerived(req.getFirstType()))
297+
continue;
298+
299+
Type firstType = req.getFirstType();
300+
Type secondType;
301+
if (req.getKind() == RequirementKind::Layout)
302+
secondType = ctx.getAnyObjectConstraint();
303+
else
304+
secondType = req.getSecondType();
276305

277-
if (type->isTypeParameter() &&
278-
type->getRootGenericParam()->isEqual(protoSelf))
306+
// Self.A.B == <<inner generic parameter>> is OK.
307+
if (req.getKind() == RequirementKind::SameType &&
308+
secondType->isTypeParameter() &&
309+
!isSelfDerived(secondType))
310+
continue;
311+
312+
// Anything else is a new requirement on 'Self', which is not allowed.
313+
314+
// Downgrade even harder in this case, since the old logic always missed it.
315+
if (secondType->hasTypeParameter() && !secondType->isTypeParameter())
316+
downgrade = true;
317+
318+
// Re-sugar the types, since effectiveSig might be canonical.
319+
firstType = originalSig->getSugaredType(firstType);
320+
secondType = originalSig->getSugaredType(secondType);
321+
static_assert((unsigned)RequirementKind::LAST_KIND == 4,
322+
"update %select in diagnostic!");
323+
324+
ctx.Diags.diagnose(decl, diag::requirement_restricts_self, decl,
325+
firstType.getString(),
326+
static_cast<unsigned>(req.getKind()),
327+
secondType.getString())
328+
// FIXME: This should become an unconditional error since violating
329+
// this invariant can introduce compiler and run time crashes.
330+
.warnUntilFutureSwiftVersionIf(downgrade);
279331
return true;
332+
}
280333

281334
return false;
282335
}
283336

284337
// For a generic requirement in a protocol, make sure that the requirement
285338
// set didn't add any requirements to Self or its associated types.
286339
void TypeChecker::checkProtocolSelfRequirements(ValueDecl *decl) {
287-
// For a generic requirement in a protocol, make sure that the requirement
288-
// set didn't add any requirements to Self or its associated types.
340+
// Make sure the generic signature of a protocol method doesn't
341+
// impose any new requirements on Self or one of its member types.
289342
if (auto *proto = dyn_cast<ProtocolDecl>(decl->getDeclContext())) {
343+
auto *genCtx = decl->getAsGenericContext();
344+
ASSERT(genCtx != nullptr);
345+
346+
// If it's not generic and it doesn't have a where clause, there is
347+
// nothing to check.
348+
if (!genCtx->getGenericParams() && !genCtx->getTrailingWhereClause())
349+
return;
350+
290351
auto &ctx = proto->getASTContext();
291-
auto protoSelf = proto->getSelfInterfaceType();
292-
auto sig = decl->getInnermostDeclContext()->getGenericSignatureOfContext();
352+
auto sig = genCtx->getGenericSignature();
353+
354+
bool hasSameTypeRequirement = false;
355+
356+
// Perform the check as it was formerly implemented first, by looking at
357+
// the syntactic requirements of the original generic signature.
358+
if (checkProtocolSelfRequirementsImpl(ctx, proto, decl, sig, sig,
359+
/*downgrade=*/false,
360+
&hasSameTypeRequirement)) {
361+
return;
362+
}
363+
364+
// If the generic signature was sufficiently simple, we're done.
365+
if (!hasSameTypeRequirement)
366+
return;
367+
368+
// The quick check doesn't catch everything when same-type requirements
369+
// are involved, so the correct thing is to build a new signature where
370+
// the innermost generic parameters added by the protocol method now have
371+
// a non-zero weight. In this signature, any type that can be made
372+
// equivalent to a member type of Self will have a reduced type rooted
373+
// in Self.
374+
SmallVector<GenericTypeParamType *, 2> params;
375+
SmallVector<Requirement, 2> reqs;
376+
377+
auto transformParam = [&](GenericTypeParamType *paramTy)
378+
-> GenericTypeParamType * {
379+
if (paramTy->getDepth() == sig->getMaxDepth()) {
380+
return GenericTypeParamType::get(
381+
paramTy->getParamKind(),
382+
paramTy->getDepth(),
383+
paramTy->getIndex(),
384+
/*weight=*/1,
385+
paramTy->getValueType(), ctx);
386+
}
387+
388+
return cast<GenericTypeParamType>(paramTy->getCanonicalType());
389+
};
390+
391+
for (auto *paramTy : sig.getGenericParams())
392+
params.push_back(transformParam(paramTy));
393+
394+
auto transformType = [&](Type t) -> Type {
395+
return t.transformRec([&](TypeBase *t) -> std::optional<Type> {
396+
if (auto *paramTy = dyn_cast<GenericTypeParamType>(t))
397+
return transformParam(paramTy);
398+
399+
return std::nullopt;
400+
})->getCanonicalType();
401+
};
402+
293403
for (auto req : sig.getRequirements()) {
294-
// If one of the types in the requirement is dependent on a non-Self
295-
// type parameter, this requirement is okay.
296-
if (!isSelfDerivedOrConcrete(protoSelf, req.getFirstType()) ||
297-
!isSelfDerivedOrConcrete(protoSelf, req.getSecondType()))
298-
continue;
299-
300-
// The conformance of 'Self' to the protocol is okay.
301-
if (req.getKind() == RequirementKind::Conformance &&
302-
req.getProtocolDecl() == proto &&
303-
req.getFirstType()->is<GenericTypeParamType>())
304-
continue;
305-
306-
static_assert((unsigned)RequirementKind::LAST_KIND == 4,
307-
"update %select in diagnostic!");
308-
ctx.Diags.diagnose(decl, diag::requirement_restricts_self, decl,
309-
req.getFirstType().getString(),
310-
static_cast<unsigned>(req.getKind()),
311-
req.getSecondType().getString());
404+
if (req.getKind() != RequirementKind::Layout) {
405+
reqs.emplace_back(req.getKind(),
406+
transformType(req.getFirstType()),
407+
transformType(req.getSecondType()));
408+
} else {
409+
reqs.emplace_back(req.getKind(),
410+
transformType(req.getFirstType()),
411+
req.getLayoutConstraint());
412+
}
312413
}
414+
415+
auto weightedSig = buildGenericSignature(
416+
ctx, GenericSignature(), params, reqs, /*allowInverses=*/false);
417+
418+
// Repeat the check with the new signature.
419+
checkProtocolSelfRequirementsImpl(ctx, proto, decl, sig, weightedSig,
420+
/*downgrade=*/true, nullptr);
313421
}
314422
}
315423

0 commit comments

Comments
 (0)