Skip to content

[SE-0313] Implement type system, ABI, and runtime support for isolated parameters #37794

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 7 commits into from
Jun 9, 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
2 changes: 1 addition & 1 deletion docs/ABI/Mangling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,7 @@ Types
type-list ::= empty-list

// FIXME: Consider replacing 'h' with a two-char code
list-type ::= type identifier? 'Yk'? 'z'? 'h'? 'n'? 'd'? // type with optional label, '@noDerivative', inout convention, shared convention, owned convention, and variadic specifier
list-type ::= type identifier? 'Yk'? 'z'? 'h'? 'n'? 'Yi'? 'd'? // type with optional label, '@noDerivative', inout convention, shared convention, owned convention, actor 'isolated', and variadic specifier

METATYPE-REPR ::= 't' // Thin metatype representation
METATYPE-REPR ::= 'T' // Thick metatype representation
Expand Down
10 changes: 9 additions & 1 deletion include/swift/ABI/MetadataValues.h
Original file line number Diff line number Diff line change
Expand Up @@ -950,7 +950,8 @@ class TargetParameterTypeFlags {
ValueOwnershipMask = 0x7F,
VariadicMask = 0x80,
AutoClosureMask = 0x100,
NoDerivativeMask = 0x200
NoDerivativeMask = 0x200,
IsolatedMask = 0x400,
};
int_type Data;

Expand Down Expand Up @@ -983,10 +984,17 @@ class TargetParameterTypeFlags {
(Data & ~NoDerivativeMask) | (isNoDerivative ? NoDerivativeMask : 0));
}

constexpr TargetParameterTypeFlags<int_type>
withIsolated(bool isIsolated) const {
return TargetParameterTypeFlags<int_type>(
(Data & ~IsolatedMask) | (isIsolated ? IsolatedMask : 0));
}

bool isNone() const { return Data == 0; }
bool isVariadic() const { return Data & VariadicMask; }
bool isAutoClosure() const { return Data & AutoClosureMask; }
bool isNoDerivative() const { return Data & NoDerivativeMask; }
bool isIsolated() const { return Data & IsolatedMask; }

ValueOwnership getValueOwnership() const {
return (ValueOwnership)(Data & ValueOwnershipMask);
Expand Down
7 changes: 5 additions & 2 deletions include/swift/AST/Attr.def
Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,11 @@ CONTEXTUAL_SIMPLE_DECL_ATTR(actor, Actor,
APIBreakingToAdd | APIBreakingToRemove,
102)

// Unused attribute 103
CONTEXTUAL_SIMPLE_DECL_ATTR(isolated, Isolated,
DeclModifier | OnParam |
ABIBreakingToAdd | ABIBreakingToRemove |
APIBreakingToAdd | APIBreakingToRemove,
103)

SIMPLE_DECL_ATTR(globalActor, GlobalActor,
OnClass | OnStruct | OnEnum | ConcurrencyOnly |
Expand Down Expand Up @@ -668,7 +672,6 @@ SIMPLE_DECL_ATTR(_distributedActorIndependent, DistributedActorIndependent,
APIBreakingToAdd | APIBreakingToRemove,
119)


#undef TYPE_ATTR
#undef DECL_ATTR_ALIAS
#undef CONTEXTUAL_DECL_ATTR_ALIAS
Expand Down
18 changes: 16 additions & 2 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -5262,7 +5262,7 @@ class ParamDecl : public VarDecl {

TypeRepr *TyRepr = nullptr;

struct StoredDefaultArgument {
struct alignas(1 << DeclAlignInBits) StoredDefaultArgument {
PointerUnion<Expr *, VarDecl *> DefaultArg;

/// Stores the context for the default argument as well as a bit to
Expand All @@ -5283,10 +5283,13 @@ class ParamDecl : public VarDecl {

/// Whether or not this parameter is `@autoclosure`.
IsAutoClosure = 1 << 1,

/// Whether or not this parameter is 'isolated'.
IsIsolated = 1 << 2,
};

/// The default value, if any, along with flags.
llvm::PointerIntPair<StoredDefaultArgument *, 2, OptionSet<Flags>>
llvm::PointerIntPair<StoredDefaultArgument *, 3, OptionSet<Flags>>
DefaultValueAndFlags;

friend class ParamSpecifierRequest;
Expand Down Expand Up @@ -5437,6 +5440,17 @@ class ParamDecl : public VarDecl {
: flags - Flags::IsAutoClosure);
}

/// Whether or not this parameter is marked with 'isolated'.
bool isIsolated() const {
return DefaultValueAndFlags.getInt().contains(Flags::IsIsolated);
}

void setIsolated(bool value = true) {
auto flags = DefaultValueAndFlags.getInt();
DefaultValueAndFlags.setInt(value ? flags | Flags::IsIsolated
: flags - Flags::IsIsolated);
}

/// Does this parameter reject temporary pointer conversions?
bool isNonEphemeral() const;

Expand Down
30 changes: 10 additions & 20 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -4349,31 +4349,27 @@ ERROR(override_implicit_unowned_executor,none,
"explicitly defined", ())

ERROR(actor_isolated_non_self_reference,none,
"actor-isolated %0 %1 can only be %select{referenced|mutated|used 'inout'}3 "
"%select{from inside the actor|on 'self'}2",
(DescriptiveDeclKind, DeclName, bool, unsigned))
"actor-isolated %0 %1 can not be "
"%select{referenced|mutated|used 'inout'}2 "
"%select{on a non-isolated actor instance|"
"from a Sendable function|from a Sendable closure|"
"from an 'async let' initializer|from global actor %4|"
"from the main actor|from a non-isolated context}3",
(DescriptiveDeclKind, DeclName, unsigned, unsigned, Type))
ERROR(distributed_actor_isolated_non_self_reference,none,
"distributed actor-isolated %0 %1 can only be referenced "
"inside the distributed actor",
(DescriptiveDeclKind, DeclName))
ERROR(distributed_actor_needs_explicit_distributed_import,none,
"'_Distributed' module not imported, required for 'distributed actor'",
())
ERROR(actor_isolated_self_independent_context,none,
"actor-isolated %0 %1 can not be %select{referenced|mutated|used 'inout'}2 from a "
"non-isolated context",
(DescriptiveDeclKind, DeclName, unsigned))
ERROR(actor_isolated_inout_state,none,
"actor-isolated %0 %1 cannot be passed 'inout' to"
"%select{| implicitly}2 'async' function call",
(DescriptiveDeclKind, DeclName, bool))
ERROR(actor_isolated_mutating_func,none,
"cannot call mutating async function %0 on actor-isolated %1 %2",
(DeclName, DescriptiveDeclKind, DeclName))
ERROR(actor_isolated_global_actor_context,none,
"actor-isolated %0 %1 can not be %select{referenced|mutated|used 'inout'}3 "
"from%select{| synchronous}4 context of global actor %2",
(DescriptiveDeclKind, DeclName, Type, unsigned, bool))
ERROR(global_actor_from_instance_actor_context,none,
"%0 %1 isolated to global actor %2 can not be %select{referenced|mutated|used 'inout'}4"
" from actor %3 %select{|in a synchronous context}5",
Expand All @@ -4398,15 +4394,6 @@ ERROR(actor_isolated_partial_apply,none,
ERROR(concurrent_access_local,none,
"use of local %0 %1 in concurrently-executing code",
(DescriptiveDeclKind, DeclName))
ERROR(actor_isolated_from_concurrent_closure,none,
"actor-isolated %0 %1 cannot be %select{referenced|mutated|used 'inout'}2 from a concurrent closure",
(DescriptiveDeclKind, DeclName, unsigned))
ERROR(actor_isolated_from_concurrent_function,none,
"actor-isolated %0 %1 cannot be %select{referenced|mutated|used 'inout'}2 from a concurrent function",
(DescriptiveDeclKind, DeclName, unsigned))
ERROR(actor_isolated_from_async_let,none,
"actor-isolated %0 %1 cannot be %select{referenced|mutated|used 'inout'}2 from 'async let' initializer",
(DescriptiveDeclKind, DeclName, unsigned))
ERROR(actor_isolated_keypath_component,none,
"cannot form key path to%select{| distributed}0 actor-isolated %1 %2",
(bool, DescriptiveDeclKind, DeclName))
Expand Down Expand Up @@ -4477,6 +4464,9 @@ ERROR(actor_cannot_conform_to_global_actor_protocol,none,
NOTE(protocol_isolated_to_global_actor_here,none,
"%0 is isolated to global actor %1 here", (Type, Type))

ERROR(isolated_parameter_not_actor,none,
"'isolated' parameter has non-actor type %0", (Type))

WARNING(non_concurrent_param_type,none,
"cannot pass argument of non-sendable type %0 across actors",
(Type))
Expand Down
14 changes: 14 additions & 0 deletions include/swift/AST/TypeCheckRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -1020,6 +1020,20 @@ class ActorIsolationRequest :
bool isCached() const { return true; }
};

/// Determine whether the given function should have an isolated 'self'.
class HasIsolatedSelfRequest :
public SimpleRequest<HasIsolatedSelfRequest,
bool(ValueDecl *),
RequestFlags::Uncached> {
public:
using SimpleRequest::SimpleRequest;

private:
friend SimpleRequest;

bool evaluate(Evaluator &evaluator, ValueDecl *func) const;
};

/// Request whether the storage has a mutating getter.
class IsGetterMutatingRequest :
public SimpleRequest<IsGetterMutatingRequest,
Expand Down
3 changes: 3 additions & 0 deletions include/swift/AST/TypeCheckerTypeIDZone.def
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ SWIFT_REQUEST(TypeChecker, GlobalActorAttributeRequest,
SWIFT_REQUEST(TypeChecker, ActorIsolationRequest,
ActorIsolationState(ValueDecl *),
Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, HasIsolatedSelfRequest,
bool(ValueDecl *),
Uncached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, FunctionOperatorRequest, OperatorDecl *(FuncDecl *),
Cached, NoLocationInfo)
SWIFT_REQUEST(NameLookup, GenericSignatureRequest,
Expand Down
19 changes: 18 additions & 1 deletion include/swift/AST/TypeRepr.h
Original file line number Diff line number Diff line change
Expand Up @@ -939,7 +939,8 @@ class SpecifierTypeRepr : public TypeRepr {
static bool classof(const TypeRepr *T) {
return T->getKind() == TypeReprKind::InOut ||
T->getKind() == TypeReprKind::Shared ||
T->getKind() == TypeReprKind::Owned;
T->getKind() == TypeReprKind::Owned ||
T->getKind() == TypeReprKind::Isolated;
}
static bool classof(const SpecifierTypeRepr *T) { return true; }

Expand Down Expand Up @@ -995,6 +996,21 @@ class OwnedTypeRepr : public SpecifierTypeRepr {
static bool classof(const OwnedTypeRepr *T) { return true; }
};

/// An 'isolated' type.
/// \code
/// x : isolated Actor
/// \endcode
class IsolatedTypeRepr : public SpecifierTypeRepr {
public:
IsolatedTypeRepr(TypeRepr *Base, SourceLoc InOutLoc)
: SpecifierTypeRepr(TypeReprKind::Isolated, Base, InOutLoc) {}

static bool classof(const TypeRepr *T) {
return T->getKind() == TypeReprKind::Isolated;
}
static bool classof(const IsolatedTypeRepr *T) { return true; }
};

/// A TypeRepr for a known, fixed type.
///
/// Fixed type representations should be used sparingly, in places
Expand Down Expand Up @@ -1226,6 +1242,7 @@ inline bool TypeRepr::isSimple() const {
case TypeReprKind::SILBox:
case TypeReprKind::Shared:
case TypeReprKind::Owned:
case TypeReprKind::Isolated:
case TypeReprKind::Placeholder:
return true;
}
Expand Down
1 change: 1 addition & 0 deletions include/swift/AST/TypeReprNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ ABSTRACT_TYPEREPR(Specifier, TypeRepr)
TYPEREPR(InOut, SpecifierTypeRepr)
TYPEREPR(Shared, SpecifierTypeRepr)
TYPEREPR(Owned, SpecifierTypeRepr)
TYPEREPR(Isolated, SpecifierTypeRepr)
TYPEREPR(Fixed, TypeRepr)
TYPEREPR(SILBox, TypeRepr)
LAST_TYPEREPR(SILBox)
Expand Down
27 changes: 20 additions & 7 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -1929,10 +1929,11 @@ class ParameterTypeFlags {
OwnershipShift = 3,
Ownership = 7 << OwnershipShift,
NoDerivative = 1 << 6,
NumBits = 7
Isolated = 1 << 7,
NumBits = 8
};
OptionSet<ParameterFlags> value;
static_assert(NumBits < 8*sizeof(OptionSet<ParameterFlags>), "overflowed");
static_assert(NumBits <= 8*sizeof(OptionSet<ParameterFlags>), "overflowed");

ParameterTypeFlags(OptionSet<ParameterFlags, uint8_t> val) : value(val) {}

Expand All @@ -1943,17 +1944,18 @@ class ParameterTypeFlags {
}

ParameterTypeFlags(bool variadic, bool autoclosure, bool nonEphemeral,
ValueOwnership ownership, bool noDerivative)
ValueOwnership ownership, bool isolated, bool noDerivative)
: value((variadic ? Variadic : 0) | (autoclosure ? AutoClosure : 0) |
(nonEphemeral ? NonEphemeral : 0) |
uint8_t(ownership) << OwnershipShift |
(isolated ? Isolated : 0) |
(noDerivative ? NoDerivative : 0)) {}

/// Create one from what's present in the parameter type
inline static ParameterTypeFlags
fromParameterType(Type paramTy, bool isVariadic, bool isAutoClosure,
bool isNonEphemeral, ValueOwnership ownership,
bool isNoDerivative);
bool isolated, bool isNoDerivative);

bool isNone() const { return !value; }
bool isVariadic() const { return value.contains(Variadic); }
Expand All @@ -1962,6 +1964,7 @@ class ParameterTypeFlags {
bool isInOut() const { return getValueOwnership() == ValueOwnership::InOut; }
bool isShared() const { return getValueOwnership() == ValueOwnership::Shared;}
bool isOwned() const { return getValueOwnership() == ValueOwnership::Owned; }
bool isIsolated() const { return value.contains(Isolated); }
bool isNoDerivative() const { return value.contains(NoDerivative); }

ValueOwnership getValueOwnership() const {
Expand Down Expand Up @@ -2005,6 +2008,12 @@ class ParameterTypeFlags {
: value - ParameterTypeFlags::NonEphemeral);
}

ParameterTypeFlags withIsolated(bool isolated) const {
return ParameterTypeFlags(isolated
? value | ParameterTypeFlags::Isolated
: value - ParameterTypeFlags::Isolated);
}

ParameterTypeFlags withNoDerivative(bool noDerivative) const {
return ParameterTypeFlags(noDerivative
? value | ParameterTypeFlags::NoDerivative
Expand Down Expand Up @@ -2078,7 +2087,7 @@ class YieldTypeFlags {
return ParameterTypeFlags(/*variadic*/ false,
/*autoclosure*/ false,
/*nonEphemeral*/ false, getValueOwnership(),
/*noDerivative*/ false);
/*isolated*/ false, /*noDerivative*/ false);
}

bool operator ==(const YieldTypeFlags &other) const {
Expand Down Expand Up @@ -2857,6 +2866,9 @@ class AnyFunctionType : public TypeBase {
/// Whether the parameter is marked '@_nonEphemeral'
bool isNonEphemeral() const { return Flags.isNonEphemeral(); }

/// Whether the parameter is 'isolated'.
bool isIsolated() const { return Flags.isIsolated(); }

/// Whether the parameter is marked '@noDerivative'.
bool isNoDerivative() const { return Flags.isNoDerivative(); }

Expand Down Expand Up @@ -6227,7 +6239,7 @@ inline TupleTypeElt TupleTypeElt::getWithType(Type T) const {
/// Create one from what's present in the parameter decl and type
inline ParameterTypeFlags ParameterTypeFlags::fromParameterType(
Type paramTy, bool isVariadic, bool isAutoClosure, bool isNonEphemeral,
ValueOwnership ownership, bool isNoDerivative) {
ValueOwnership ownership, bool isolated, bool isNoDerivative) {
// FIXME(Remove InOut): The last caller that needs this is argument
// decomposition. Start by enabling the assertion there and fixing up those
// callers, then remove this, then remove
Expand All @@ -6237,7 +6249,8 @@ inline ParameterTypeFlags ParameterTypeFlags::fromParameterType(
ownership == ValueOwnership::InOut);
ownership = ValueOwnership::InOut;
}
return {isVariadic, isAutoClosure, isNonEphemeral, ownership, isNoDerivative};
return {isVariadic, isAutoClosure, isNonEphemeral, ownership, isolated,
isNoDerivative};
}

inline const Type *BoundGenericType::getTrailingObjectsPointer() const {
Expand Down
1 change: 1 addition & 0 deletions include/swift/Demangling/DemangleNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ NODE(ImplErrorResult)
NODE(InOut)
NODE(InfixOperator)
CONTEXT_NODE(Initializer)
NODE(Isolated)
NODE(KeyPathGetterThunkHelper)
NODE(KeyPathSetterThunkHelper)
NODE(KeyPathEqualsThunkHelper)
Expand Down
7 changes: 7 additions & 0 deletions include/swift/Demangling/TypeDecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ class FunctionParam {
Flags = Flags.withValueOwnership(ownership);
}
void setNoDerivative() { Flags = Flags.withNoDerivative(true); }
void setIsolated() { Flags = Flags.withIsolated(true); }
void setFlags(ParameterFlags flags) { Flags = flags; };

FunctionParam withLabel(StringRef label) const {
Expand Down Expand Up @@ -1415,6 +1416,12 @@ class TypeDecoder {
hasParamFlags = true;
break;

case NodeKind::Isolated:
param.setIsolated();
node = node->getFirstChild();
hasParamFlags = true;
break;

case NodeKind::AutoClosureType:
case NodeKind::EscapingAutoClosureType:
param.setAutoClosure();
Expand Down
Loading