Skip to content

Commit 619c023

Browse files
committed
Add a Recursive Type Bit for Parameterized Existentials
1 parent 4b56634 commit 619c023

File tree

3 files changed

+129
-3
lines changed

3 files changed

+129
-3
lines changed

include/swift/AST/Types.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,10 @@ class RecursiveTypeProperties {
163163
/// type sequence
164164
HasTypeSequence = 0x1000,
165165

166-
Last_Property = HasTypeSequence
166+
/// This type contains a parameterized existential type \c any P<T>.
167+
HasParameterizedExistential = 0x2000,
168+
169+
Last_Property = HasParameterizedExistential
167170
};
168171
enum { BitWidth = countBitsUsed(Property::Last_Property) };
169172

@@ -223,6 +226,12 @@ class RecursiveTypeProperties {
223226

224227
bool hasTypeSequence() const { return Bits & HasTypeSequence; }
225228

229+
/// Does a type with these properties structurally contain a
230+
/// parameterized existential type?
231+
bool hasParameterizedExistential() const {
232+
return Bits & HasParameterizedExistential;
233+
}
234+
226235
/// Returns the set of properties present in either set.
227236
friend RecursiveTypeProperties operator|(Property lhs, Property rhs) {
228237
return RecursiveTypeProperties(unsigned(lhs) | unsigned(rhs));
@@ -626,6 +635,11 @@ class alignas(1 << TypeAlignInBits) TypeBase
626635
return getRecursiveProperties().hasTypeSequence();
627636
}
628637

638+
/// Determine whether the type involves a parameterized existential type.
639+
bool hasParameterizedExistential() const {
640+
return getRecursiveProperties().hasParameterizedExistential();
641+
}
642+
629643
/// Determine whether the type involves the given opened existential
630644
/// archetype.
631645
bool hasOpenedExistentialWithRoot(const OpenedArchetypeType *root) const;

lib/AST/ASTContext.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3441,6 +3441,8 @@ ExistentialMetatypeType::get(Type T, Optional<MetatypeRepresentation> repr,
34413441
T = existential->getConstraintType();
34423442

34433443
auto properties = T->getRecursiveProperties();
3444+
if (T->is<ParameterizedProtocolType>())
3445+
properties |= RecursiveTypeProperties::HasParameterizedExistential;
34443446
auto arena = getArena(properties);
34453447

34463448
unsigned reprKey;
@@ -3536,7 +3538,7 @@ isAnyFunctionTypeCanonical(ArrayRef<AnyFunctionType::Param> params,
35363538
static RecursiveTypeProperties
35373539
getGenericFunctionRecursiveProperties(ArrayRef<AnyFunctionType::Param> params,
35383540
Type result) {
3539-
static_assert(RecursiveTypeProperties::BitWidth == 13,
3541+
static_assert(RecursiveTypeProperties::BitWidth == 14,
35403542
"revisit this if you add new recursive type properties");
35413543
RecursiveTypeProperties properties;
35423544

@@ -4139,7 +4141,7 @@ CanSILFunctionType SILFunctionType::get(
41394141
void *mem = ctx.Allocate(bytes, alignof(SILFunctionType));
41404142

41414143
RecursiveTypeProperties properties;
4142-
static_assert(RecursiveTypeProperties::BitWidth == 13,
4144+
static_assert(RecursiveTypeProperties::BitWidth == 14,
41434145
"revisit this if you add new recursive type properties");
41444146
for (auto &param : params)
41454147
properties |= param.getInterfaceType()->getRecursiveProperties();
@@ -4257,6 +4259,8 @@ Type ExistentialType::get(Type constraint, bool forceExistential) {
42574259
assert(constraint->isConstraintType());
42584260

42594261
auto properties = constraint->getRecursiveProperties();
4262+
if (constraint->is<ParameterizedProtocolType>())
4263+
properties |= RecursiveTypeProperties::HasParameterizedExistential;
42604264
auto arena = getArena(properties);
42614265

42624266
auto &entry = C.getImpl().getArena(arena).ExistentialTypes[constraint];
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
// RUN: %target-typecheck-verify-swift -target %target-cpu-apple-macosx10.50 -disable-objc-attr-requires-foundation-module -enable-parameterized-existential-types
2+
// RUN: not %target-swift-frontend -target %target-cpu-apple-macosx10.50 -disable-objc-attr-requires-foundation-module -enable-parameterized-existential-types -typecheck %s 2>&1 | %FileCheck %s '--implicit-check-not=<unknown>:0'
3+
4+
// Make sure we do not emit availability errors or warnings when -disable-availability-checking is passed
5+
// RUN: not %target-swift-frontend -target %target-cpu-apple-macosx10.50 -typecheck -disable-objc-attr-requires-foundation-module -enable-parameterized-existential-types -disable-availability-checking %s 2>&1 | %FileCheck %s '--implicit-check-not=error:'
6+
7+
func hedge() {
8+
struct Value {}
9+
10+
// We rely on not allowing nesting of extensions, so test to make sure
11+
// this emits an error.
12+
// CHECK:error: declaration is only valid at file scope
13+
extension Value { } // expected-error {{declaration is only valid at file scope}}
14+
}
15+
16+
protocol P<T> {
17+
associatedtype T
18+
}
19+
20+
struct Wrapper<T> {}
21+
22+
func identity<T>(_ x: any P<T>) -> any P<T> { return x } // OK
23+
func unwrapUnwrap<T>(_ x: (any P<T>)???) -> (any P<T>)? { return x!! } // OK
24+
25+
func erase<T>(_ x: any P<T>) -> Any { return x } // expected-error {{runtime support for parameterized protocol types is only available in}}
26+
// expected-note@-1 {{add @available attribute to enclosing global function}}
27+
// expected-note@-2 {{add 'if #available' version check}}
28+
29+
func eraseOptional<T>(_ x: (any P<T>)?) -> Any { return x }
30+
// expected-note@-1 {{add @available attribute to enclosing global function}}
31+
// expected-error@-2 {{runtime support for parameterized protocol types is only available in}}
32+
// expected-note@-3 {{add 'if #available' version check}}
33+
// expected-warning@-4 {{expression implicitly coerced from '(any P<T>)?' to 'Any'}}
34+
// expected-note@-5 {{provide a default value to avoid this warning}}
35+
// expected-note@-6 {{force-unwrap the value to avoid this warning}}
36+
// expected-note@-7 {{explicitly cast to 'Any' with 'as Any' to silence this warning}}
37+
38+
func eraseOptional2<T>(_ x: (any P<T>)?) -> Any { return x as Any }
39+
// expected-note@-1 {{add @available attribute to enclosing global function}}
40+
// expected-error@-2 {{runtime support for parameterized protocol types is only available in}}
41+
// expected-note@-3 {{add 'if #available' version check}}
42+
43+
func tupleOut<T>() -> (any P<T>, Int) { return tupleOut() } // expected-error {{runtime support for parameterized protocol types is only available in}}
44+
// expected-note@-1 {{add @available attribute to enclosing global function}}
45+
func tupleIn<T>(_ xs: (any P<T>, Int)) -> Int { return tupleIn(xs) } // expected-error {{runtime support for parameterized protocol types is only available in}}
46+
// expected-note@-1 {{add @available attribute to enclosing global function}}
47+
func wrap<T>(_ x: any P<T>) -> Wrapper<any P<T>> { return wrap(x) } // expected-error {{runtime support for parameterized protocol types is only available in}}
48+
// expected-note@-1 {{add @available attribute to enclosing global function}}
49+
func optionalWrap<T>(_ x: any P<T>) -> Wrapper<(any P<T>)?> { return optionalWrap(x) } // expected-error {{runtime support for parameterized protocol types is only available in}}
50+
// expected-note@-1 {{add @available attribute to enclosing global function}}
51+
52+
struct UnavailableWitness: P { // expected-note {{add @available attribute to enclosing struct}}
53+
typealias T = any P<String> // expected-error {{runtime support for parameterized protocol types is only available in}}
54+
// expected-note@-1 {{add @available attribute to enclosing type alias}}
55+
}
56+
57+
struct UnavailableOptionalWitness: P { // expected-note {{add @available attribute to enclosing struct}}
58+
typealias T = (any P<String>)? // expected-error {{runtime support for parameterized protocol types is only available in}}
59+
// expected-note@-1 {{add @available attribute to enclosing type alias}}
60+
}
61+
62+
struct UnavailableWrappedWitness: P { // expected-note 2 {{add @available attribute to enclosing struct}}
63+
typealias T = Wrapper<any P<String>> // expected-error 2 {{runtime support for parameterized protocol types is only available in}}
64+
// expected-note@-1 2 {{add @available attribute to enclosing type alias}}
65+
}
66+
67+
struct ParameterizedMembers { // expected-note {{add @available attribute to enclosing struct}}
68+
var ok: any P<String>
69+
var okOptional: (any P<String>)?
70+
71+
var broken: Wrapper<(any P<String>)?> // expected-error {{runtime support for parameterized protocol types is only available in}}
72+
}
73+
74+
func casts() { // expected-note 5 {{add @available attribute to enclosing global function}}
75+
struct Value: P { typealias T = String }
76+
77+
let _ = Value() as any P<String> // OK
78+
let _ = Value() as! any P<String>
79+
// expected-warning@-1 {{forced cast from 'Value' to 'any P<String>' always succeeds; did you mean to use 'as'?}}
80+
// expected-error@-2 {{runtime support for parameterized protocol types is only available in}}
81+
// expected-note@-3 {{add 'if #available' version check}}
82+
83+
let _ = Value() is any P<String>
84+
// expected-warning@-1 {{'is' test is always true}}
85+
// expected-error@-2 {{runtime support for parameterized protocol types is only available in}}
86+
// expected-note@-3 {{add 'if #available' version check}}
87+
88+
let _ = Value() is (any P<String>)???
89+
// expected-warning@-1 {{'is' test is always true}}
90+
// expected-error@-2 {{runtime support for parameterized protocol types is only available in}}
91+
// expected-note@-3 {{add 'if #available' version check}}
92+
93+
let _ = Value() as! (any P<String>, Int)
94+
// expected-warning@-1 {{cast from 'Value' to unrelated type '(any P<String>, Int)' always fails}}
95+
// expected-error@-2 2 {{runtime support for parameterized protocol types is only available in}}
96+
// expected-note@-3 2 {{add 'if #available' version check}}
97+
}
98+
99+
// FIXME: It's a little aggressive to also ban metatypes.
100+
func metatypes<T>(_ x: T.Type) { // expected-note 2 {{add @available attribute to enclosing global function}}
101+
metatypes((any P<T>).self)
102+
// expected-error@-1 {{runtime support for parameterized protocol types is only available in}}
103+
// expected-note@-2 {{add 'if #available' version check}}
104+
105+
metatypes((any P<T>.Type).self)
106+
// expected-error@-1 {{runtime support for parameterized protocol types is only available in}}
107+
// expected-note@-2 {{add 'if #available' version check}}
108+
}

0 commit comments

Comments
 (0)