Skip to content

[SE-0302] Implement '@unchecked Sendable' syntax. #38343

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 3 commits into from
Jul 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
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
3 changes: 2 additions & 1 deletion include/swift/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -1019,7 +1019,8 @@ class ASTContext final {
ProtocolDecl *protocol,
SourceLoc loc,
DeclContext *dc,
ProtocolConformanceState state);
ProtocolConformanceState state,
bool isUnchecked);

/// Produce a self-conformance for the given protocol.
SelfProtocolConformance *
Expand Down
6 changes: 4 additions & 2 deletions include/swift/AST/ASTPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "swift/Basic/QuotedString.h"
#include "swift/Basic/UUID.h"
#include "swift/AST/Identifier.h"
#include "swift/AST/Decl.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/DenseSet.h"
Expand Down Expand Up @@ -351,8 +352,9 @@ void printEnumElementsAsCases(
llvm::DenseSet<EnumElementDecl *> &UnhandledElements,
llvm::raw_ostream &OS);

void getInheritedForPrinting(const Decl *decl, const PrintOptions &options,
llvm::SmallVectorImpl<TypeLoc> &Results);
void getInheritedForPrinting(
const Decl *decl, const PrintOptions &options,
llvm::SmallVectorImpl<InheritedEntry> &Results);

StringRef getAccessorKindString(AccessorKind value);

Expand Down
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(unchecked)

// SIL-specific attributes
TYPE_ATTR(block_storage)
Expand Down
41 changes: 26 additions & 15 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1209,6 +1209,17 @@ class ImportDecl final : public Decl,
}
};

/// An entry in the "inherited" list of a type or extension.
struct InheritedEntry : public TypeLoc {
/// Whether there was an @unchecked attribute.
bool isUnchecked = false;

InheritedEntry(const TypeLoc &typeLoc);

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

/// ExtensionDecl - This represents a type extension containing methods
/// associated with the type. This is not a ValueDecl and has no Type because
/// there are no runtime values of the Extension's type.
Expand All @@ -1227,7 +1238,7 @@ class ExtensionDecl final : public GenericContext, public Decl,
/// extended nominal.
llvm::PointerIntPair<NominalTypeDecl *, 1, bool> ExtendedNominal;

ArrayRef<TypeLoc> Inherited;
ArrayRef<InheritedEntry> Inherited;

/// The next extension in the linked list of extensions.
///
Expand All @@ -1246,7 +1257,7 @@ class ExtensionDecl final : public GenericContext, public Decl,
friend class IterableDeclContext;

ExtensionDecl(SourceLoc extensionLoc, TypeRepr *extendedType,
ArrayRef<TypeLoc> inherited,
ArrayRef<InheritedEntry> inherited,
DeclContext *parent,
TrailingWhereClause *trailingWhereClause);

Expand All @@ -1271,7 +1282,7 @@ class ExtensionDecl final : public GenericContext, public Decl,
/// Create a new extension declaration.
static ExtensionDecl *create(ASTContext &ctx, SourceLoc extensionLoc,
TypeRepr *extendedType,
ArrayRef<TypeLoc> inherited,
ArrayRef<InheritedEntry> inherited,
DeclContext *parent,
TrailingWhereClause *trailingWhereClause,
ClangNode clangNode = ClangNode());
Expand Down Expand Up @@ -1326,9 +1337,9 @@ class ExtensionDecl final : public GenericContext, public Decl,

/// Retrieve the set of protocols that this type inherits (i.e,
/// explicitly conforms to).
ArrayRef<TypeLoc> getInherited() const { return Inherited; }
ArrayRef<InheritedEntry> getInherited() const { return Inherited; }

void setInherited(ArrayRef<TypeLoc> i) { Inherited = i; }
void setInherited(ArrayRef<InheritedEntry> i) { Inherited = i; }

bool hasDefaultAccessLevel() const {
return Bits.ExtensionDecl.DefaultAndMaxAccessLevel != 0;
Expand Down Expand Up @@ -2538,12 +2549,12 @@ class ValueDecl : public Decl {

/// This is a common base class for declarations which declare a type.
class TypeDecl : public ValueDecl {
ArrayRef<TypeLoc> Inherited;
ArrayRef<InheritedEntry> Inherited;

protected:
TypeDecl(DeclKind K, llvm::PointerUnion<DeclContext *, ASTContext *> context,
Identifier name, SourceLoc NameLoc,
ArrayRef<TypeLoc> inherited) :
ArrayRef<InheritedEntry> inherited) :
ValueDecl(K, context, name, NameLoc), Inherited(inherited) {}

public:
Expand All @@ -2561,9 +2572,9 @@ class TypeDecl : public ValueDecl {

/// Retrieve the set of protocols that this type inherits (i.e,
/// explicitly conforms to).
ArrayRef<TypeLoc> getInherited() const { return Inherited; }
ArrayRef<InheritedEntry> getInherited() const { return Inherited; }

void setInherited(ArrayRef<TypeLoc> i) { Inherited = i; }
void setInherited(ArrayRef<InheritedEntry> i) { Inherited = i; }

static bool classof(const Decl *D) {
return D->getKind() >= DeclKind::First_TypeDecl &&
Expand All @@ -2588,7 +2599,7 @@ class GenericTypeDecl : public GenericContext, public TypeDecl {
public:
GenericTypeDecl(DeclKind K, DeclContext *DC,
Identifier name, SourceLoc nameLoc,
ArrayRef<TypeLoc> inherited,
ArrayRef<InheritedEntry> inherited,
GenericParamList *GenericParams);

// Resolve ambiguity due to multiple base classes.
Expand Down Expand Up @@ -3115,7 +3126,7 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {

NominalTypeDecl(DeclKind K, DeclContext *DC, Identifier name,
SourceLoc NameLoc,
ArrayRef<TypeLoc> inherited,
ArrayRef<InheritedEntry> inherited,
GenericParamList *GenericParams) :
GenericTypeDecl(K, DC, name, NameLoc, inherited, GenericParams),
IterableDeclContext(IterableDeclContextKind::NominalTypeDecl)
Expand Down Expand Up @@ -3411,7 +3422,7 @@ class EnumDecl final : public NominalTypeDecl {

public:
EnumDecl(SourceLoc EnumLoc, Identifier Name, SourceLoc NameLoc,
ArrayRef<TypeLoc> Inherited,
ArrayRef<InheritedEntry> Inherited,
GenericParamList *GenericParams, DeclContext *DC);

SourceLoc getStartLoc() const { return EnumLoc; }
Expand Down Expand Up @@ -3579,7 +3590,7 @@ class StructDecl final : public NominalTypeDecl {

public:
StructDecl(SourceLoc StructLoc, Identifier Name, SourceLoc NameLoc,
ArrayRef<TypeLoc> Inherited,
ArrayRef<InheritedEntry> Inherited,
GenericParamList *GenericParams, DeclContext *DC);

SourceLoc getStartLoc() const { return StructLoc; }
Expand Down Expand Up @@ -3725,7 +3736,7 @@ class ClassDecl final : public NominalTypeDecl {

public:
ClassDecl(SourceLoc ClassLoc, Identifier Name, SourceLoc NameLoc,
ArrayRef<TypeLoc> Inherited,
ArrayRef<InheritedEntry> Inherited,
GenericParamList *GenericParams, DeclContext *DC,
bool isActor);

Expand Down Expand Up @@ -4160,7 +4171,7 @@ class ProtocolDecl final : public NominalTypeDecl {

public:
ProtocolDecl(DeclContext *DC, SourceLoc ProtocolLoc, SourceLoc NameLoc,
Identifier Name, ArrayRef<TypeLoc> Inherited,
Identifier Name, ArrayRef<InheritedEntry> Inherited,
TrailingWhereClause *TrailingWhere);

using Decl::getASTContext;
Expand Down
11 changes: 9 additions & 2 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -4516,16 +4516,23 @@ ERROR(concurrent_value_class_mutable_property,none,
(DeclName, DescriptiveDeclKind, DeclName))
ERROR(concurrent_value_outside_source_file,none,
"conformance to 'Sendable' must occur in the same source file as "
"%0 %1; use 'UnsafeSendable' for retroactive conformance",
"%0 %1; use '@unchecked Sendable' for retroactive conformance",
(DescriptiveDeclKind, DeclName))
ERROR(concurrent_value_nonfinal_class,none,
"non-final class %0 cannot conform to `Sendable`; "
"use `UnsafeSendable`", (DeclName))
"use `@unchecked Sendable`", (DeclName))
ERROR(concurrent_value_inherit,none,
"`Sendable` class %1 cannot inherit from another class"
"%select{| other than 'NSObject'}0",
(bool, DeclName))

WARNING(unchecked_conformance_not_special,none,
"@unchecked conformance to %0 has no meaning", (Type))
ERROR(unchecked_not_inheritance_clause,none,
"'unchecked' attribute only applies in inheritance clauses", ())
ERROR(unchecked_not_existential,none,
"'unchecked' attribute cannot apply to non-protocol type %0", (Type))

ERROR(nonisolated_let,none,
"'nonisolated' is meaningless on 'let' declarations because "
"they are immutable",
Expand Down
17 changes: 15 additions & 2 deletions include/swift/AST/NameLookup.h
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,19 @@ void filterForDiscriminator(SmallVectorImpl<Result> &results,

} // end namespace namelookup

/// Describes an inherited nominal entry.
struct InheritedNominalEntry : Located<NominalTypeDecl *> {
/// The location of the "unchecked" attribute, if present.
SourceLoc uncheckedLoc;

InheritedNominalEntry() { }

InheritedNominalEntry(
NominalTypeDecl *item, SourceLoc loc,
SourceLoc uncheckedLoc
) : Located(item, loc), uncheckedLoc(uncheckedLoc) { }
};

/// Retrieve the set of nominal type declarations that are directly
/// "inherited" by the given declaration at a particular position in the
/// list of "inherited" types.
Expand All @@ -511,15 +524,15 @@ void filterForDiscriminator(SmallVectorImpl<Result> &results,
/// AnyObject type, set \c anyObject true.
void getDirectlyInheritedNominalTypeDecls(
llvm::PointerUnion<const TypeDecl *, const ExtensionDecl *> decl,
unsigned i, llvm::SmallVectorImpl<Located<NominalTypeDecl *>> &result,
unsigned i, llvm::SmallVectorImpl<InheritedNominalEntry> &result,
bool &anyObject);

/// Retrieve the set of nominal type declarations that are directly
/// "inherited" by the given declaration, looking through typealiases
/// and splitting out the components of compositions.
///
/// If we come across the AnyObject type, set \c anyObject true.
SmallVector<Located<NominalTypeDecl *>, 4> getDirectlyInheritedNominalTypeDecls(
SmallVector<InheritedNominalEntry, 4> getDirectlyInheritedNominalTypeDecls(
llvm::PointerUnion<const TypeDecl *, const ExtensionDecl *> decl,
bool &anyObject);

Expand Down
29 changes: 22 additions & 7 deletions include/swift/AST/ProtocolConformance.h
Original file line number Diff line number Diff line change
Expand Up @@ -412,11 +412,20 @@ class NormalProtocolConformance : public RootProtocolConformance,
/// The location of this protocol conformance in the source.
SourceLoc Loc;

// Flag bits used in ContextAndBits.
enum {
/// The conformance is invalid.
InvalidFlag = 0x01,

/// The conformance was labeled with @unchecked.
UncheckedFlag = 0x02,
};

/// The declaration context containing the ExtensionDecl or
/// NominalTypeDecl that declared the conformance.
///
/// Also stores the "invalid" bit.
llvm::PointerIntPair<DeclContext *, 1, bool> ContextAndInvalid;
/// Also stores the "invalid" and "unchecked" bits.
llvm::PointerIntPair<DeclContext *, 2, unsigned> ContextAndBits;

/// The reason that this conformance exists.
///
Expand Down Expand Up @@ -457,11 +466,12 @@ class NormalProtocolConformance : public RootProtocolConformance,
public:
NormalProtocolConformance(Type conformingType, ProtocolDecl *protocol,
SourceLoc loc, DeclContext *dc,
ProtocolConformanceState state)
ProtocolConformanceState state,
bool isUnchecked)
: RootProtocolConformance(ProtocolConformanceKind::Normal,
conformingType),
ProtocolAndState(protocol, state), Loc(loc),
ContextAndInvalid(dc, false) {
ContextAndBits(dc, isUnchecked ? UncheckedFlag : 0) {
assert(!conformingType->hasArchetype() &&
"ProtocolConformances should store interface types");
}
Expand All @@ -475,7 +485,7 @@ class NormalProtocolConformance : public RootProtocolConformance,
/// Get the declaration context that contains the conforming extension or
/// nominal type declaration.
DeclContext *getDeclContext() const {
return ContextAndInvalid.getPointer();
return ContextAndBits.getPointer();
}

/// Get any additional requirements that are required for this conformance to
Expand All @@ -497,15 +507,20 @@ class NormalProtocolConformance : public RootProtocolConformance,

/// Determine whether this conformance is invalid.
bool isInvalid() const {
return ContextAndInvalid.getInt();
return ContextAndBits.getInt() & InvalidFlag;
}

/// Mark this conformance as invalid.
void setInvalid() {
ContextAndInvalid.setInt(true);
ContextAndBits.setInt(ContextAndBits.getInt() | InvalidFlag);
SignatureConformances = {};
}

/// Whether this is an "unchecked" conformance.
bool isUnchecked() const {
return ContextAndBits.getInt() & UncheckedFlag;
}

/// Get the kind of source from which this conformance comes.
ConformanceEntryKind getSourceKind() const {
return SourceKindAndImplyingConformance.getInt();
Expand Down
2 changes: 1 addition & 1 deletion include/swift/AST/TypeLoc.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class TypeRepr;

/// TypeLoc - Provides source location information for a parsed type.
/// A TypeLoc is stored in AST nodes which use an explicitly written type.
class alignas(1 << TypeReprAlignInBits) TypeLoc final {
class alignas(1 << TypeReprAlignInBits) TypeLoc {
Type Ty;
TypeRepr *TyR = nullptr;

Expand Down
4 changes: 4 additions & 0 deletions include/swift/AST/TypeRepr.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ 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;

/// Is this type grammatically a type-simple?
inline bool isSimple() const; // bottom of this file

Expand Down
2 changes: 1 addition & 1 deletion include/swift/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -1127,7 +1127,7 @@ class Parser {

ParserResult<ImportDecl> parseDeclImport(ParseDeclOptions Flags,
DeclAttributes &Attributes);
ParserStatus parseInheritance(SmallVectorImpl<TypeLoc> &Inherited,
ParserStatus parseInheritance(SmallVectorImpl<InheritedEntry> &Inherited,
bool allowClassRequirement,
bool allowAnyObject);
ParserStatus parseDeclItem(bool &PreviousHadSemi,
Expand Down
6 changes: 4 additions & 2 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2188,7 +2188,8 @@ ASTContext::getConformance(Type conformingType,
ProtocolDecl *protocol,
SourceLoc loc,
DeclContext *dc,
ProtocolConformanceState state) {
ProtocolConformanceState state,
bool isUnchecked) {
assert(dc->isTypeContext());

llvm::FoldingSetNodeID id;
Expand All @@ -2204,7 +2205,8 @@ ASTContext::getConformance(Type conformingType,
// Build a new normal protocol conformance.
auto result
= new (*this, AllocationArena::Permanent)
NormalProtocolConformance(conformingType, protocol, loc, dc, state);
NormalProtocolConformance(
conformingType, protocol, loc, dc, state,isUnchecked);
normalConformances.InsertNode(result, insertPos);

return result;
Expand Down
5 changes: 3 additions & 2 deletions lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -499,11 +499,12 @@ namespace {
PrintWithColorRAII(OS, DeclModifierColor) << " trailing_semi";
}

void printInherited(ArrayRef<TypeLoc> Inherited) {
void printInherited(ArrayRef<InheritedEntry> Inherited) {
if (Inherited.empty())
return;
OS << " inherits: ";
interleave(Inherited, [&](TypeLoc Super) { Super.getType().print(OS); },
interleave(Inherited,
[&](InheritedEntry Super) { Super.getType().print(OS); },
[&] { OS << ", "; });
}

Expand Down
Loading