Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/swift/AST/Attr.def
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ TYPE_ATTR(differentiable)
TYPE_ATTR(noDerivative)
TYPE_ATTR(async)
TYPE_ATTR(Sendable)
TYPE_ATTR(retroactive)
TYPE_ATTR(unchecked)
TYPE_ATTR(_local)
TYPE_ATTR(_noMetadata)
Expand Down
1 change: 1 addition & 0 deletions include/swift/AST/CASTBridging.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ typedef enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedTypeAttrKind : size_t {
BridgedTypeAttrKind_noDerivative,
BridgedTypeAttrKind_async,
BridgedTypeAttrKind_Sendable,
BridgedTypeAttrKind_retroactive,
BridgedTypeAttrKind_unchecked,
BridgedTypeAttrKind__local,
BridgedTypeAttrKind__noMetadata,
Expand Down
8 changes: 6 additions & 2 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1563,10 +1563,14 @@ struct InheritedEntry : public TypeLoc {
/// Whether there was an @unchecked attribute.
bool isUnchecked = false;

/// Whether there was an @retroactive attribute.
bool isRetroactive = false;

InheritedEntry(const TypeLoc &typeLoc);

InheritedEntry(const TypeLoc &typeLoc, bool isUnchecked)
: TypeLoc(typeLoc), isUnchecked(isUnchecked) { }
InheritedEntry(const TypeLoc &typeLoc, bool isUnchecked, bool isRetroactive)
: TypeLoc(typeLoc), isUnchecked(isUnchecked), isRetroactive(isRetroactive) {
}
};

/// A wrapper for the collection of inherited types for either a `TypeDecl` or
Expand Down
17 changes: 17 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -2444,6 +2444,23 @@ NOTE(invalid_extension_rewrite,none,
ERROR(synthesized_nominal_extension,none,
"cannot extend synthesized type %0", (Type))

ERROR(retroactive_not_in_extension_inheritance_clause,none,
"'retroactive' attribute only applies in inheritance clauses in "
"extensions", ())

ERROR(retroactive_attr_does_not_apply,none,
"'retroactive' attribute does not apply; %0 is declared in this module",
(Identifier))

WARNING(extension_retroactive_conformance,none,
"extension declares a conformance of imported type %0 to imported "
"%select{protocols|protocol}1 %2; this will not behave correctly if "
"the owners of %3 introduce this conformance in the future",
(Identifier, bool, StringRef, Identifier))

NOTE(extension_retroactive_conformance_silence,none,
"add '@retroactive' to silence this warning", ())

// Protocols
ERROR(type_does_not_conform,none,
"type %0 does not conform to protocol %1", (Type, Type))
Expand Down
7 changes: 7 additions & 0 deletions include/swift/AST/Module.h
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,13 @@ class ModuleDecl
/// module if one exists.
ModuleDecl *getUnderlyingModuleIfOverlay() const;

/// Returns true if this module is the Clang overlay of \p other.
bool isClangOverlayOf(ModuleDecl *other);

/// Returns true if this module is the same module or either module is a clang
/// overlay of the other.
bool isSameModuleLookingThroughOverlays(ModuleDecl *other);

/// Returns true if this module is an underscored cross import overlay
/// declared by \p other or its underlying clang module, either directly or
/// transitively (via intermediate cross-import overlays - for cross-imports
Expand Down
5 changes: 5 additions & 0 deletions include/swift/AST/ProtocolConformance.h
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,11 @@ class alignas(1 << DeclAlignInBits) ProtocolConformance
/// is either the default definition or was otherwise deduced.
bool usesDefaultDefinition(AssociatedTypeDecl *requirement) const;

/// Determines whether this conformance is retroactive; that is, if the
/// conformance's declaration is in a different module from both the
/// conforming type and the protocol.
bool isRetroactive() const;

/// Print a parseable and human-readable description of the identifying
/// information of the protocol conformance.
void printName(raw_ostream &os,
Expand Down
6 changes: 3 additions & 3 deletions include/swift/AST/TypeRepr.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,9 @@ class alignas(1 << TypeReprAlignInBits) TypeRepr
SourceLoc getEndLoc() const;
SourceRange getSourceRange() const;

/// Find an @unchecked attribute and return its source location, or return
/// an invalid source location if there is no such attribute.
SourceLoc findUncheckedAttrLoc() const;
/// Find an attribute with the provided kind and return its source location,
/// or return an invalid source location if there is no such attribute.
SourceLoc findAttrLoc(TypeAttrKind kind) const;

/// Is this type grammatically a type-simple?
inline bool isSimple() const; // bottom of this file
Expand Down
1 change: 1 addition & 0 deletions include/swift/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ LANGUAGE_FEATURE(MoveOnly, 390, "noncopyable types", true)
LANGUAGE_FEATURE(ParameterPacks, 393, "Value and type parameter packs", true)
SUPPRESSIBLE_LANGUAGE_FEATURE(LexicalLifetimes, 0, "@_eagerMove/@_noEagerMove/@_lexicalLifetimes annotations", true)
LANGUAGE_FEATURE(FreestandingMacros, 397, "freestanding declaration macros", true)
SUPPRESSIBLE_LANGUAGE_FEATURE(RetroactiveAttribute, 364, "@retroactive", true)

UPCOMING_FEATURE(ConciseMagicFile, 274, 6)
UPCOMING_FEATURE(ForwardTrailingClosures, 286, 6)
Expand Down
28 changes: 26 additions & 2 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ PrintOptions PrintOptions::printSwiftInterfaceFile(ModuleDecl *ModuleToPrint,
DAK_ObjCImplementation,
DAK_StaticInitializeObjCMetadata,
DAK_RestatedObjCConformance,
DAK_NonSendable,
DAK_NonSendable
};

return result;
Expand Down Expand Up @@ -2579,6 +2579,9 @@ void PrintAST::printInherited(const Decl *decl) {
interleave(TypesToPrint, [&](InheritedEntry inherited) {
if (inherited.isUnchecked)
Printer << "@unchecked ";
if (inherited.isRetroactive &&
!llvm::is_contained(Options.ExcludeAttrList, TAK_retroactive))
Printer << "@retroactive ";

printTypeLoc(inherited);
}, [&]() {
Expand Down Expand Up @@ -3049,6 +3052,18 @@ static bool usesFeatureGlobalActors(Decl *decl) {
return false;
}

static bool usesFeatureRetroactiveAttribute(Decl *decl) {
auto ext = dyn_cast<ExtensionDecl>(decl);
if (!ext)
return false;

ArrayRef<InheritedEntry> entries = ext->getInherited().getEntries();
return std::find_if(entries.begin(), entries.end(),
[](const InheritedEntry &entry) {
return entry.isRetroactive;
}) != entries.end();
}

static bool usesBuiltinType(Decl *decl, BuiltinTypeKind kind) {
auto typeMatches = [kind](Type type) {
return type.findIf([&](Type type) {
Expand Down Expand Up @@ -3475,6 +3490,14 @@ suppressingFeatureNoAsyncAvailability(PrintOptions &options,
action();
}

static void suppressingFeatureRetroactiveAttribute(
PrintOptions &options,
llvm::function_ref<void()> action) {
llvm::SaveAndRestore<PrintOptions> originalOptions(options);
options.ExcludeAttrList.push_back(TAK_retroactive);
action();
}

static bool usesFeatureReferenceBindings(Decl *decl) {
auto *vd = dyn_cast<VarDecl>(decl);
return vd && vd->getIntroducer() == VarDecl::Introducer::InOut;
Expand Down Expand Up @@ -7871,7 +7894,8 @@ swift::getInheritedForPrinting(
}

Results.push_back({TypeLoc::withoutLoc(proto->getDeclaredInterfaceType()),
isUnchecked});
isUnchecked,
/*isRetroactive=*/false});
}
}

Expand Down
6 changes: 4 additions & 2 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1544,8 +1544,10 @@ NominalTypeDecl::takeConformanceLoaderSlow() {

InheritedEntry::InheritedEntry(const TypeLoc &typeLoc)
: TypeLoc(typeLoc), isUnchecked(false) {
if (auto typeRepr = typeLoc.getTypeRepr())
isUnchecked = typeRepr->findUncheckedAttrLoc().isValid();
if (auto typeRepr = typeLoc.getTypeRepr()) {
isUnchecked = typeRepr->findAttrLoc(TAK_unchecked).isValid();
isRetroactive = typeRepr->findAttrLoc(TAK_retroactive).isValid();
}
}

InheritedTypes::InheritedTypes(
Expand Down
28 changes: 28 additions & 0 deletions lib/AST/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2909,6 +2909,34 @@ ModuleDecl::getDeclaringModuleAndBystander() {
return *(declaringModuleAndBystander = {nullptr, Identifier()});
}

bool ModuleDecl::isClangOverlayOf(ModuleDecl *potentialUnderlying) {
return getUnderlyingModuleIfOverlay() == potentialUnderlying;
}

bool ModuleDecl::isSameModuleLookingThroughOverlays(
ModuleDecl *other) {
if (this == other) {
return true;
}

if (this->isClangOverlayOf(other) || other->isClangOverlayOf(this)) {
return true;
}

// If the type has the @_originallyDefinedIn attribute, check if this is the
// "originally defined in" module.

if (getName().is(other->getAlternateModuleName())) {
return true;
}

if (other->getName().is(getAlternateModuleName())) {
return true;
}

return false;
}

bool ModuleDecl::isCrossImportOverlayOf(ModuleDecl *other) {
ModuleDecl *current = this;
ModuleDecl *otherClang = other->getUnderlyingModuleIfOverlay();
Expand Down
2 changes: 1 addition & 1 deletion lib/AST/NameLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3664,7 +3664,7 @@ void swift::getDirectlyInheritedNominalTypeDecls(
auto inheritedTypes = InheritedTypes(decl);
if (TypeRepr *typeRepr = inheritedTypes.getTypeRepr(i)) {
loc = typeRepr->getLoc();
uncheckedLoc = typeRepr->findUncheckedAttrLoc();
uncheckedLoc = typeRepr->findAttrLoc(TAK_unchecked);
}

// Form the result.
Expand Down
20 changes: 20 additions & 0 deletions lib/AST/ProtocolConformance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,26 @@ usesDefaultDefinition(AssociatedTypeDecl *requirement) const {
CONFORMANCE_SUBCLASS_DISPATCH(usesDefaultDefinition, (requirement))
}

bool ProtocolConformance::isRetroactive() const {
auto extensionModule = getDeclContext()->getParentModule();
auto protocolModule = getProtocol()->getParentModule();
if (extensionModule->isSameModuleLookingThroughOverlays(protocolModule)) {
return false;
}

auto conformingTypeDecl =
ConformingType->getNominalOrBoundGenericNominal();
if (conformingTypeDecl) {
auto conformingTypeModule = conformingTypeDecl->getParentModule();
if (extensionModule->
isSameModuleLookingThroughOverlays(conformingTypeModule)) {
return false;
}
}

return true;
}

GenericEnvironment *ProtocolConformance::getGenericEnvironment() const {
switch (getKind()) {
case ProtocolConformanceKind::Inherited:
Expand Down
6 changes: 3 additions & 3 deletions lib/AST/TypeRepr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,11 @@ TypeRepr *TypeRepr::getWithoutParens() const {
return repr;
}

SourceLoc TypeRepr::findUncheckedAttrLoc() const {
SourceLoc TypeRepr::findAttrLoc(TypeAttrKind kind) const {
auto typeRepr = this;
while (auto attrTypeRepr = dyn_cast<AttributedTypeRepr>(typeRepr)) {
if (attrTypeRepr->getAttrs().has(TAK_unchecked)) {
return attrTypeRepr->getAttrs().getLoc(TAK_unchecked);
if (attrTypeRepr->getAttrs().has(kind)) {
return attrTypeRepr->getAttrs().getLoc(kind);
}

typeRepr = attrTypeRepr->getTypeRepr();
Expand Down
8 changes: 4 additions & 4 deletions lib/ASTGen/Sources/ASTGen/Types.swift
Original file line number Diff line number Diff line change
Expand Up @@ -246,10 +246,10 @@ extension ASTGenVisitor {
fallthrough

case .autoclosure, .escaping, .noescape, .noDerivative, .async,
.sendable, .unchecked, ._local, ._noMetadata, .pack_owned,
.pack_guaranteed, .pack_inout, .pack_out, .pseudogeneric,
.yields, .yield_once, .yield_many, .thin, .thick, .count,
.unimplementable:
.sendable, .retroactive, .unchecked, ._local, ._noMetadata,
.pack_owned, .pack_guaranteed, .pack_inout, .pack_out,
.pseudogeneric, .yields, .yield_once, .yield_many, .thin, .thick,
.count, .unimplementable:
TypeAttributes_addSimpleAttr(typeAttributes, typeAttrKind, atLoc, attrLoc)

case .opened, .pack_element, .differentiable, .convention,
Expand Down
2 changes: 1 addition & 1 deletion lib/ClangImporter/ImportDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7094,7 +7094,7 @@ void SwiftDeclConverter::importObjCProtocols(
inheritedTypes.push_back(
InheritedEntry(
TypeLoc::withoutLoc(proto->getDeclaredInterfaceType()),
/*isUnchecked=*/false));
/*isUnchecked=*/false, /*isRetroactive=*/false));
}
}

Expand Down
3 changes: 2 additions & 1 deletion lib/Frontend/ModuleInterfaceSupport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -735,7 +735,8 @@ class InheritedProtocolCollector {
// Create a synthesized ExtensionDecl for the conformance.
ASTContext &ctx = M->getASTContext();
auto inherits = ctx.AllocateCopy(llvm::makeArrayRef(InheritedEntry(
TypeLoc::withoutLoc(proto->getDeclaredInterfaceType()), isUnchecked)));
TypeLoc::withoutLoc(proto->getDeclaredInterfaceType()), isUnchecked,
/*isRetroactive=*/false)));
auto extension =
ExtensionDecl::create(ctx, SourceLoc(), nullptr, inherits,
nominal->getModuleScopeContext(), nullptr);
Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/TypeCheckConcurrency.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5145,7 +5145,7 @@ ProtocolConformance *GetImplicitSendableRequest::evaluate(
// FIXME: This is a hack--we should give conformances real availability.
auto inherits = ctx.AllocateCopy(makeArrayRef(
InheritedEntry(TypeLoc::withoutLoc(proto->getDeclaredInterfaceType()),
/*isUnchecked*/true)));
/*isUnchecked*/true, /*isRetroactive=*/false)));
// If you change the use of AtLoc in the ExtensionDecl, make sure you
// update isNonSendableExtension() in ASTPrinter.
auto extension = ExtensionDecl::create(ctx, attrMakingUnavailable->AtLoc,
Expand Down
Loading