Skip to content

Commit 5583e69

Browse files
authored
Merge pull request #73258 from lorentey/you-cannot-escape-optionals
[stdlib] Generalize some constructs for non-escapable types
2 parents b878155 + 86f6c29 commit 5583e69

37 files changed

+499
-180
lines changed

include/swift/AST/ASTContext.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,11 @@ class ASTContext final {
682682
/// Retrieve the type Swift.Any as an existential type.
683683
CanType getAnyExistentialType() const;
684684

685+
/// Retrieve the existential type 'any ~Copyable & ~Escapable'.
686+
///
687+
/// This is the most permissive existential type.
688+
CanType getUnconstrainedAnyExistentialType() const;
689+
685690
/// Retrieve the type Swift.AnyObject as a constraint.
686691
CanType getAnyObjectConstraint() const;
687692

@@ -1043,6 +1048,9 @@ class ASTContext final {
10431048
const CanType TheEmptyTupleType; /// This is '()', aka Void
10441049
const CanType TheEmptyPackType;
10451050
const CanType TheAnyType; /// This is 'Any', the empty protocol composition
1051+
const CanType TheUnconstrainedAnyType; /// This is 'any ~Copyable & ~Escapable',
1052+
/// the empty protocol composition
1053+
/// without any implicit constraints.
10461054
#define SINGLETON_TYPE(SHORT_ID, ID) \
10471055
const CanType The##SHORT_ID##Type;
10481056
#include "swift/AST/TypeNodes.def"

include/swift/AST/ASTSynthesis.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ enum SingletonTypeSynthesizer {
5757
_taskExecutor, // the '_Concurrency.TaskExecutor' protocol
5858
_actor, // the '_Concurrency.Actor' protocol
5959
_distributedActor, // the 'Distributed.DistributedActor' protocol
60-
_unsafeRawBufferPointer // UnsafeRawBufferPointer
60+
_unsafeRawBufferPointer, // UnsafeRawBufferPointer
61+
_unconstrainedAny, // any ~Copyable & ~Escapable
6162
};
6263
inline Type synthesizeType(SynthesisContext &SC,
6364
SingletonTypeSynthesizer kind) {
@@ -98,6 +99,8 @@ inline Type synthesizeType(SynthesisContext &SC,
9899
case _escapable:
99100
return SC.Context.getProtocol(KnownProtocolKind::Escapable)
100101
->getDeclaredInterfaceType();
102+
case _unconstrainedAny:
103+
return SC.Context.getUnconstrainedAnyExistentialType();
101104
}
102105
}
103106

include/swift/AST/Builtins.def

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,8 @@ BUILTIN_MISC_OPERATION(IsConcrete, "isConcrete", "n", Special)
582582
/// IsBitwiseTakable has type T.Type -> Bool
583583
BUILTIN_MISC_OPERATION(IsBitwiseTakable, "isbitwisetakable", "n", Special)
584584

585-
/// IsSameMetatype has type (Any.Type, Any.Type) -> Bool
585+
/// IsSameMetatype has type
586+
/// (any (~Copyable & ~Escapable).Type, any (~Copyable & ~Escapable).Type) -> Bool
586587
BUILTIN_MISC_OPERATION(IsSameMetatype, "is_same_metatype", "n", Special)
587588

588589
/// AllocRaw has type (Int, Int) -> Builtin.RawPointer

include/swift/AST/LifetimeDependence.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,8 +247,12 @@ class LifetimeDependenceInfo {
247247
targetIndex(targetIndex) {
248248
assert(this->isImmortal() || inheritLifetimeParamIndices ||
249249
scopeLifetimeParamIndices);
250-
assert(!inheritLifetimeParamIndices ||
251-
!inheritLifetimeParamIndices->isEmpty());
250+
// FIXME: This assert can trigger when Optional/Result support ~Escapable use (rdar://147765187)
251+
// assert(!inheritLifetimeParamIndices ||
252+
// !inheritLifetimeParamIndices->isEmpty());
253+
if (inheritLifetimeParamIndices && inheritLifetimeParamIndices->isEmpty()) {
254+
inheritLifetimeParamIndices = nullptr;
255+
}
252256
assert(!scopeLifetimeParamIndices || !scopeLifetimeParamIndices->isEmpty());
253257
assert((!addressableParamIndices
254258
|| !conditionallyAddressableParamIndices

include/swift/AST/Types.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6362,6 +6362,12 @@ class ProtocolCompositionType final : public TypeBase,
63626362
/// Constructs a protocol composition corresponding to the `Any` type.
63636363
static Type theAnyType(const ASTContext &C);
63646364

6365+
/// Constructs a protocol composition corresponding to the `any ~Copyable &
6366+
/// ~Escapable` type.
6367+
///
6368+
/// Note: This includes the inverse of all current invertible protocols.
6369+
static Type theUnconstrainedAnyType(const ASTContext &C);
6370+
63656371
/// Constructs a protocol composition corresponding to the `AnyObject` type.
63666372
static Type theAnyObjectType(const ASTContext &C);
63676373

lib/AST/ASTContext.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -815,6 +815,8 @@ ASTContext::ASTContext(
815815
TheEmptyTupleType(TupleType::get(ArrayRef<TupleTypeElt>(), *this)),
816816
TheEmptyPackType(PackType::get(*this, {})),
817817
TheAnyType(ProtocolCompositionType::theAnyType(*this)),
818+
TheUnconstrainedAnyType(
819+
ProtocolCompositionType::theUnconstrainedAnyType(*this)),
818820
#define SINGLETON_TYPE(SHORT_ID, ID) \
819821
The##SHORT_ID##Type(new (*this, AllocationArena::Permanent) \
820822
ID##Type(*this)),
@@ -1326,6 +1328,10 @@ CanType ASTContext::getAnyExistentialType() const {
13261328
return ExistentialType::get(TheAnyType)->getCanonicalType();
13271329
}
13281330

1331+
CanType ASTContext::getUnconstrainedAnyExistentialType() const {
1332+
return ExistentialType::get(TheUnconstrainedAnyType)->getCanonicalType();
1333+
}
1334+
13291335
CanType ASTContext::getAnyObjectConstraint() const {
13301336
if (getImpl().AnyObjectType) {
13311337
return getImpl().AnyObjectType;

lib/AST/Builtins.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,8 +1108,8 @@ static ValueDecl *getIsOptionalOperation(ASTContext &ctx, Identifier id) {
11081108

11091109
static ValueDecl *getIsSameMetatypeOperation(ASTContext &ctx, Identifier id) {
11101110
return getBuiltinFunction(ctx, id, _thin,
1111-
_parameters(_existentialMetatype(_any),
1112-
_existentialMetatype(_any)),
1111+
_parameters(_existentialMetatype(_unconstrainedAny),
1112+
_existentialMetatype(_unconstrainedAny)),
11131113
_int(1));
11141114
}
11151115

lib/AST/Type.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3858,6 +3858,15 @@ Type ProtocolCompositionType::theAnyType(const ASTContext &C) {
38583858
/*HasExplicitAnyObject=*/false);
38593859
}
38603860

3861+
/// Constructs a protocol composition corresponding to the `any ~Copyable &
3862+
/// ~Escapable` type.
3863+
///
3864+
/// Note: This includes the inverse of all current invertible protocols.
3865+
Type ProtocolCompositionType::theUnconstrainedAnyType(const ASTContext &C) {
3866+
return ProtocolCompositionType::get(C, {}, InvertibleProtocolSet::allKnown(),
3867+
/*HasExplicitAnyObject=*/false);
3868+
}
3869+
38613870
/// Constructs a protocol composition containing the `AnyObject` constraint.
38623871
Type ProtocolCompositionType::theAnyObjectType(const ASTContext &C) {
38633872
return ProtocolCompositionType::get(C, {}, /*Inverses=*/{},

stdlib/public/core/Builtin.swift

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -165,13 +165,19 @@ internal func != (lhs: Builtin.RawPointer, rhs: Builtin.RawPointer) -> Bool {
165165
/// - t1: Another type to compare.
166166
/// - Returns: `true` if both `t0` and `t1` are `nil` or if they represent the
167167
/// same type; otherwise, `false`.
168-
@inlinable @_transparent
169-
public func == (t0: Any.Type?, t1: Any.Type?) -> Bool {
168+
@_alwaysEmitIntoClient
169+
@_transparent
170+
public func == (
171+
t0: (any (~Copyable & ~Escapable).Type)?,
172+
t1: (any (~Copyable & ~Escapable).Type)?
173+
) -> Bool {
170174
switch (t0, t1) {
171-
case (.none, .none): return true
175+
case (.none, .none):
176+
return true
172177
case let (.some(ty0), .some(ty1)):
173178
return Bool(Builtin.is_same_metatype(ty0, ty1))
174-
default: return false
179+
default:
180+
return false
175181
}
176182
}
177183

@@ -182,11 +188,35 @@ public func == (t0: Any.Type?, t1: Any.Type?) -> Bool {
182188
/// - t1: Another type to compare.
183189
/// - Returns: `true` if one, but not both, of `t0` and `t1` are `nil`, or if
184190
/// they represent different types; otherwise, `false`.
185-
@inlinable @_transparent
186-
public func != (t0: Any.Type?, t1: Any.Type?) -> Bool {
187-
return !(t0 == t1)
191+
@_alwaysEmitIntoClient
192+
@_transparent
193+
public func != (
194+
t0: (any (~Copyable & ~Escapable).Type)?,
195+
t1: (any (~Copyable & ~Escapable).Type)?
196+
) -> Bool {
197+
!(t0 == t1)
188198
}
189199

200+
#if !$Embedded
201+
// Embedded Swift is unhappy about conversions from `Any.Type` to
202+
// `any (~Copyable & ~Escapable).Type` (rdar://145706221)
203+
@usableFromInline
204+
@_spi(SwiftStdlibLegacyABI) @available(swift, obsoleted: 1)
205+
internal func == (t0: Any.Type?, t1: Any.Type?) -> Bool {
206+
switch (t0, t1) {
207+
case (.none, .none): return true
208+
case let (.some(ty0), .some(ty1)):
209+
return Bool(Builtin.is_same_metatype(ty0, ty1))
210+
default: return false
211+
}
212+
}
213+
214+
@usableFromInline
215+
@_spi(SwiftStdlibLegacyABI) @available(swift, obsoleted: 1)
216+
internal func != (t0: Any.Type?, t1: Any.Type?) -> Bool {
217+
!(t0 == t1)
218+
}
219+
#endif
190220

191221
/// Tell the optimizer that this code is unreachable if condition is
192222
/// known at compile-time to be true. If condition is false, or true
@@ -940,9 +970,11 @@ func _trueAfterDiagnostics() -> Builtin.Int1 {
940970
///
941971
/// - Parameter value: The value for which to find the dynamic type.
942972
/// - Returns: The dynamic type, which is a metatype instance.
943-
@_transparent
973+
@_alwaysEmitIntoClient
944974
@_semantics("typechecker.type(of:)")
945-
public func type<T, Metatype>(of value: T) -> Metatype {
975+
public func type<T: ~Copyable & ~Escapable, Metatype>(
976+
of value: borrowing T
977+
) -> Metatype {
946978
// This implementation is never used, since calls to `Swift.type(of:)` are
947979
// resolved as a special case by the type checker.
948980
unsafe Builtin.staticReport(_trueAfterDiagnostics(), true._value,
@@ -951,6 +983,17 @@ public func type<T, Metatype>(of value: T) -> Metatype {
951983
Builtin.unreachable()
952984
}
953985

986+
@_spi(SwiftStdlibLegacyABI) @available(swift, obsoleted: 1)
987+
@_silgen_name("$ss4type2ofq_x_tr0_lF")
988+
@usableFromInline
989+
func __abi_type<T, Metatype>(of value: T) -> Metatype {
990+
// This is a legacy entry point for the original definition of `type(of:)`
991+
// that the stdlib originally exported for no good reason. The current
992+
// definition no longer exports a symbol, and nothing is expected to link to
993+
// it, but we keep it around anyway.
994+
Builtin.unreachable()
995+
}
996+
954997
/// Allows a nonescaping closure to temporarily be used as if it were allowed
955998
/// to escape.
956999
///

stdlib/public/core/CompilerProtocols.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,8 +266,9 @@ public protocol CaseIterable {
266266
/// `Optional` type conforms to `ExpressibleByNilLiteral`.
267267
/// `ExpressibleByNilLiteral` conformance for types that use `nil` for other
268268
/// purposes is discouraged.
269-
public protocol ExpressibleByNilLiteral: ~Copyable {
269+
public protocol ExpressibleByNilLiteral: ~Copyable, ~Escapable {
270270
/// Creates an instance initialized with `nil`.
271+
@lifetime(immortal)
271272
init(nilLiteral: ())
272273
}
273274

0 commit comments

Comments
 (0)