Skip to content

Commit 74d2a6c

Browse files
committed
[ConstraintSystem] Limit static member reference on protocol metatype to leading dot syntax only
Do not allow references to a static members with explicitly specified protocol metatype base, limit that to leading dot syntax only.
1 parent 55fdb6c commit 74d2a6c

File tree

5 files changed

+90
-77
lines changed

5 files changed

+90
-77
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5954,9 +5954,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
59545954

59555955
auto anchor = locator.getAnchor();
59565956

5957-
if ((isExpr<UnresolvedDotExpr>(anchor) ||
5958-
isExpr<UnresolvedMemberExpr>(anchor) ||
5959-
isExpr<SubscriptExpr>(anchor)) &&
5957+
if (isExpr<UnresolvedMemberExpr>(anchor) &&
59605958
req->is<LocatorPathElt::TypeParameterRequirement>()) {
59615959
auto signature = path[path.size() - 2]
59625960
.castTo<LocatorPathElt::OpenedGeneric>()
@@ -6761,7 +6759,8 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
67616759
// member conforms to this protocol -- the metatype value itself
67626760
// doesn't give us a witness so there's no static method to bind.
67636761
hasInstanceMethods = true;
6764-
hasStaticMembers = true;
6762+
hasStaticMembers |=
6763+
memberLocator->isLastElement<LocatorPathElt::UnresolvedMember>();
67656764
} else {
67666765
// Metatypes of nominal types and archetypes have instance methods and
67676766
// static members, but not instance properties.
@@ -6851,12 +6850,11 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
68516850
->hasTypeParameter()) {
68526851

68536852
/* We're OK */
6854-
} else if (baseObjTy->is<MetatypeType>() &&
6853+
} else if (hasStaticMembers && baseObjTy->is<MetatypeType>() &&
68556854
instanceTy->isExistentialType()) {
68566855
// Static member lookup on protocol metatype requires that result type
68576856
// of a selected member to conform to protocol this method is being
68586857
// referred from.
6859-
assert(hasStaticMembers);
68606858

68616859
// Cannot instantiate a protocol or reference a member on
68626860
// protocol composition type.

lib/Sema/ConstraintSystem.cpp

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1467,11 +1467,18 @@ ConstraintSystem::getTypeOfMemberReference(
14671467
auto baseObjTy = resolvedBaseTy->getMetatypeInstanceType();
14681468
FunctionType::Param baseObjParam(baseObjTy);
14691469

1470-
// Indicates whether this is a reference to a static member on a protocol
1471-
// metatype e.g. existential metatype.
1472-
bool isStaticMemberRefOnProtocol = resolvedBaseTy->is<MetatypeType>() &&
1473-
baseObjTy->isExistentialType() &&
1474-
value->isStatic();
1470+
// Indicates whether this is a valid reference to a static member on a
1471+
// protocol metatype. Such a reference is only valid if performed through
1472+
// leading dot syntax e.g. `foo(.bar)` where implicit base is a protocol
1473+
// metatype and `bar` is static member declared in a protocol or its
1474+
// extension.
1475+
bool isStaticMemberRefOnProtocol = false;
1476+
if (resolvedBaseTy->is<MetatypeType>() && baseObjTy->isExistentialType() &&
1477+
value->isStatic()) {
1478+
if (auto last = locator.last())
1479+
isStaticMemberRefOnProtocol =
1480+
last->is<LocatorPathElt::UnresolvedMember>();
1481+
}
14751482

14761483
if (auto *typeDecl = dyn_cast<TypeDecl>(value)) {
14771484
assert(!isa<ModuleDecl>(typeDecl) && "Nested module?");

test/Constraints/static_members_on_protocol_metatype.swift

Lines changed: 66 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -38,45 +38,51 @@ extension P {
3838
}
3939
}
4040

41-
_ = P.property // Ok
42-
_ = P.property.other // Ok
43-
_ = P.iuoProp // Ok
44-
_ = P.iuoProp.other // Ok
45-
_ = P.optProp // Ok
46-
_ = P.optProp?.other // Ok
47-
_ = P.fnProp // Ok
48-
_ = P.fnProp() // Ok
49-
_ = P.fnProp().other // Ok
50-
_ = P.method() // Ok
51-
_ = P.method // Ok (partial application)
52-
_ = P.method().other // Ok
53-
_ = P.genericFn(42) // Ok
54-
_ = P.genericFn(42).other // Ok
55-
_ = P[42] // Ok
56-
_ = P[42].other // OK
57-
_ = P[t: 42] // Ok
58-
_ = P[t: 42].other // Ok
59-
60-
let _: S = P.property // Ok
61-
let _: S = P.property.other // Ok
62-
let _: () -> S = P.fnProp
63-
let _: S = P.fnProp() // Ok
64-
let _: S = P.fnProp().other // Ok
65-
let _: () -> S = P.method // Ok
66-
let _: S = P.method() // Ok
67-
let _: S = P.method().other // Ok
68-
let _: G<Int> = P.genericFn(42) // Ok
69-
let _: G = P.genericFn(42) // Ok
41+
// References on protocol metatype are only allowed through a leading dot syntax
42+
43+
_ = P.property // expected-error {{static member 'property' cannot be used on protocol metatype 'P.Protocol'}}
44+
_ = P.property.other // expected-error {{static member 'property' cannot be used on protocol metatype 'P.Protocol'}}
45+
_ = P.iuoProp // expected-error {{static member 'iuoProp' cannot be used on protocol metatype 'P.Protocol'}}
46+
_ = P.iuoProp.other // expected-error {{static member 'iuoProp' cannot be used on protocol metatype 'P.Protocol'}}
47+
_ = P.optProp // expected-error {{static member 'optProp' cannot be used on protocol metatype 'P.Protocol'}}
48+
_ = P.optProp?.other // expected-error {{static member 'optProp' cannot be used on protocol metatype 'P.Protocol'}}
49+
_ = P.fnProp // expected-error {{static member 'fnProp' cannot be used on protocol metatype 'P.Protocol'}}
50+
_ = P.fnProp() // expected-error {{static member 'fnProp' cannot be used on protocol metatype 'P.Protocol'}}
51+
_ = P.fnProp().other // expected-error {{static member 'fnProp' cannot be used on protocol metatype 'P.Protocol'}}
52+
_ = P.method() // expected-error {{static member 'method' cannot be used on protocol metatype 'P.Protocol'}}
53+
_ = P.method // expected-error {{static member 'method' cannot be used on protocol metatype 'P.Protocol'}}
54+
_ = P.method().other // expected-error {{static member 'method' cannot be used on protocol metatype 'P.Protocol'}}
55+
_ = P.genericFn(42) // expected-error {{static member 'genericFn' cannot be used on protocol metatype 'P.Protocol'}}
56+
_ = P.genericFn(42).other // expected-error {{static member 'genericFn' cannot be used on protocol metatype 'P.Protocol'}}
57+
_ = P[42] // expected-error {{static member 'subscript' cannot be used on protocol metatype 'P.Protocol'}}
58+
_ = P[42].other // expected-error {{static member 'subscript' cannot be used on protocol metatype 'P.Protocol'}}
59+
_ = P[t: 42] // expected-error {{static member 'subscript' cannot be used on protocol metatype 'P.Protocol'}}
60+
_ = P[t: 42].other // expected-error {{static member 'subscript' cannot be used on protocol metatype 'P.Protocol'}}
61+
62+
let _: S = P.property // expected-error {{static member 'property' cannot be used on protocol metatype 'P.Protocol'}}
63+
let _: S = P.property.other // expected-error {{static member 'property' cannot be used on protocol metatype 'P.Protocol'}}
64+
let _: () -> S = P.fnProp // expected-error {{static member 'fnProp' cannot be used on protocol metatype 'P.Protocol'}}
65+
let _: S = P.fnProp() // expected-error {{static member 'fnProp' cannot be used on protocol metatype 'P.Protocol'}}
66+
let _: S = P.fnProp().other // expected-error {{static member 'fnProp' cannot be used on protocol metatype 'P.Protocol'}}
67+
let _: () -> S = P.method // expected-error {{static member 'method' cannot be used on protocol metatype 'P.Protocol'}}
68+
let _: S = P.method() // expected-error {{static member 'method' cannot be used on protocol metatype 'P.Protocol'}}
69+
let _: S = P.method().other // expected-error {{static member 'method' cannot be used on protocol metatype 'P.Protocol'}}
70+
let _: G<Int> = P.genericFn(42) // expected-error {{static member 'genericFn' cannot be used on protocol metatype 'P.Protocol'}}
71+
let _: G = P.genericFn(42) // expected-error {{static member 'genericFn' cannot be used on protocol metatype 'P.Protocol'}}
7072
let _: G<String> = P.genericFn(42) // expected-error {{cannot convert value of type 'Int' to expected argument type 'String'}}
71-
let _: G<Int> = P.genericFn(42).other // Ok
73+
// expected-error@-1 {{static member 'genericFn' cannot be used on protocol metatype 'P.Protocol'}}
74+
let _: G<Int> = P.genericFn(42).other // expected-error {{static member 'genericFn' cannot be used on protocol metatype 'P.Protocol'}}
7275
let _: G<String> = P.genericFn(42).other // expected-error {{cannot convert value of type 'Int' to expected argument type 'String'}}
73-
let _: S = P[42] // Ok
74-
let _: S = P[42].other // OK
75-
let _: G<Int> = P[t: 42] // Ok
76-
let _: G = P[t: 42] // Ok
76+
// expected-error@-1 {{static member 'genericFn' cannot be used on protocol metatype 'P.Protocol'}}
77+
let _: S = P[42] // expected-error {{static member 'subscript' cannot be used on protocol metatype 'P.Protocol'}}
78+
let _: S = P[42].other // expected-error {{static member 'subscript' cannot be used on protocol metatype 'P.Protocol'}}
79+
let _: G<Int> = P[t: 42] // expected-error {{static member 'subscript' cannot be used on protocol metatype 'P.Protocol'}}
80+
let _: G = P[t: 42] // expected-error {{static member 'subscript' cannot be used on protocol metatype 'P.Protocol'}}
7781
let _: G<String> = P[t: 42] // expected-error {{cannot convert value of type 'Int' to expected argument type 'String'}}
78-
let _: G<Int> = P[t: 42].other // Ok
82+
// expected-error@-1 {{static member 'subscript' cannot be used on protocol metatype 'P.Protocol'}}
83+
let _: G<Int> = P[t: 42].other // expected-error {{static member 'subscript' cannot be used on protocol metatype 'P.Protocol'}}
7984
let _: G<String> = P[t: 42].other // expected-error {{cannot convert value of type 'Int' to expected argument type 'String'}}
85+
// expected-error@-1 {{static member 'subscript' cannot be used on protocol metatype 'P.Protocol'}}
8086

8187
func test<T: P>(_: T) {}
8288

@@ -130,49 +136,50 @@ test_combo(.genericFn(42)) // expected-error {{global function 'test_combo' requ
130136
/* Invalid result types */
131137

132138
extension P {
133-
static var invalidProp: Int { 42 } // expected-note 5 {{'invalidProp' declared here}}
139+
static var invalidProp: Int { 42 } // expected-note 3 {{'invalidProp' declared here}}
134140
static var selfProp: Self { fatalError() }
135-
static func invalidMethod() -> Int { 42 } // expected-note 6 {{'invalidMethod()' declared here}}
136-
static func generic<T>(_: T) -> T { fatalError() } // expected-note 5 {{'generic' declared here}}
137-
static func genericWithReqs<T: Collection, Q>(_: T) -> Q where T.Element == Q { // expected-note 3 {{'genericWithReqs' declared here}} expected-note 3 {{required by static method 'genericWithReqs' where 'T' = '()'}}
141+
static func invalidMethod() -> Int { 42 } // expected-note 3 {{'invalidMethod()' declared here}}
142+
static func generic<T>(_: T) -> T { fatalError() } // expected-note 3 {{'generic' declared here}}
143+
static func genericWithReqs<T: Collection, Q>(_: T) -> Q where T.Element == Q { // expected-note {{in call to function 'genericWithReqs'}} expected-note 2 {{'genericWithReqs' declared here}} expected-note 3 {{required by static method 'genericWithReqs' where 'T' = '()'}}
138144
fatalError()
139145
}
140146

141-
static subscript(q q: String) -> Int { get { 42 } } // expected-note 2 {{'subscript(q:)' declared here}}
147+
static subscript(q q: String) -> Int { get { 42 } }
142148
}
143149

144150
_ = P.doesntExist // expected-error {{type 'P' has no member 'doesntExist'}}
145-
_ = P.selfProp // expected-error {{generic parameter 'Self' could not be inferred}}
151+
_ = P.selfProp // expected-error {{static member 'selfProp' cannot be used on protocol metatype 'P.Protocol'}}
146152
_ = P.invalidProp
147-
// expected-error@-1 {{cannot reference static property 'invalidProp' on 'P.Protocol' with non-conforming result type 'Int'}}
153+
// expected-error@-1 {{static member 'invalidProp' cannot be used on protocol metatype 'P.Protocol'}}
148154
_ = P.invalidProp.other
149-
// expected-error@-1 {{cannot reference static property 'invalidProp' on 'P.Protocol' with non-conforming result type 'Int'}}
155+
// expected-error@-1 {{static member 'invalidProp' cannot be used on protocol metatype 'P.Protocol'}}
150156
// expected-error@-2 {{value of type 'Int' has no member 'other'}}
151157
_ = P.invalidMethod // Partial application with an invalid base type
152-
// expected-error@-1 {{cannot reference static method 'invalidMethod()' on 'P.Protocol' with non-conforming result type 'Int'}}
158+
// expected-error@-1 {{static member 'invalidMethod' cannot be used on protocol metatype 'P.Protocol'}}
153159
_ = P.invalidMethod()
154-
// expected-error@-1 {{cannot reference static method 'invalidMethod()' on 'P.Protocol' with non-conforming result type 'Int'}}
160+
// expected-error@-1 {{static member 'invalidMethod' cannot be used on protocol metatype 'P.Protocol'}}
155161
_ = P.invalidMethod().other
156-
// expected-error@-1 {{cannot reference static method 'invalidMethod()' on 'P.Protocol' with non-conforming result type 'Int'}}
162+
// expected-error@-1 {{static member 'invalidMethod' cannot be used on protocol metatype 'P.Protocol'}}
157163
// expected-error@-2 {{value of type 'Int' has no member 'other'}}
158164
_ = P.generic(42)
159-
// expected-error@-1 {{cannot reference static method 'generic' on 'P.Protocol' with non-conforming result type 'Int'}}
165+
// expected-error@-1 {{static member 'generic' cannot be used on protocol metatype 'P.Protocol'}}
160166
_ = P.generic(42).other
161-
// expected-error@-1 {{cannot reference static method 'generic' on 'P.Protocol' with non-conforming result type 'Int'}}
167+
// expected-error@-1 {{static member 'generic' cannot be used on protocol metatype 'P.Protocol'}}
162168
// expected-error@-2 {{value of type 'Int' has no member 'other'}}
163-
_ = P.generic(S()) // Ok
164-
_ = P.generic(S()).other // Ok
165-
_ = P.generic(G<Int>()) // Ok
166-
_ = P.genericWithReqs([S()]) // Ok
169+
_ = P.generic(S()) // expected-error {{static member 'generic' cannot be used on protocol metatype 'P.Protocol'}}
170+
_ = P.generic(S()).other // expected-error {{static member 'generic' cannot be used on protocol metatype 'P.Protocol'}}
171+
_ = P.generic(G<Int>()) // expected-error {{static member 'generic' cannot be used on protocol metatype 'P.Protocol'}}
172+
_ = P.genericWithReqs([S()]) // expected-error {{static member 'genericWithReqs' cannot be used on protocol metatype 'P.Protocol'}}
167173
_ = P.genericWithReqs([42])
168-
// expected-error@-1 {{cannot reference static method 'genericWithReqs' on 'P.Protocol' with non-conforming result type 'Int'}}
174+
// expected-error@-1 {{static member 'genericWithReqs' cannot be used on protocol metatype 'P.Protocol'}}
169175
_ = P.genericWithReqs(())
170176
// expected-error@-1 {{type '()' cannot conform to 'Collection'}} expected-note@-1 {{only concrete types such as structs, enums and classes can conform to protocols}}
171-
// expected-error@-2 {{generic parameter 'Self' could not be inferred}}
177+
// expected-error@-2 {{static member 'genericWithReqs' cannot be used on protocol metatype 'P.Protocol'}}
178+
// expected-error@-3 {{generic parameter 'Q' could not be inferred}}
172179
_ = P[q: ""]
173-
// expected-error@-1 {{cannot reference static subscript 'subscript(q:)' on 'P.Protocol' with non-conforming result type 'Int'}}
180+
// expected-error@-1 {{static member 'subscript' cannot be used on protocol metatype 'P.Protocol'}}
174181
_ = P[q: ""].other
175-
// expected-error@-1 {{cannot reference static subscript 'subscript(q:)' on 'P.Protocol' with non-conforming result type 'Int'}}
182+
// expected-error@-1 {{static member 'subscript' cannot be used on protocol metatype 'P.Protocol'}}
176183
// expected-error@-2 {{value of type 'Int' has no member 'other'}}
177184

178185
test(.doesntExist) // expected-error {{type 'P' has no member 'doesntExist'}}
@@ -223,14 +230,13 @@ protocol Z {
223230
}
224231

225232
extension Z {
226-
static func method() -> T { fatalError() } // expected-note {{'method()' declared here}}
233+
static func method() -> T { fatalError() }
227234
}
228235

229236
_ = Z.prop
230237
// expected-error@-1 {{member 'prop' cannot be used on value of protocol type 'Z.Protocol'; use a generic constraint instead}}
231238
// expected-error@-2 {{protocol 'Z' can only be used as a generic constraint because it has Self or associated type requirements}}
232239

233240
_ = Z.method()
234-
// expected-error@-1 {{cannot reference static method 'method()' on 'Z.Protocol' with non-conforming result type 'Z.T'}}
235-
// expected-error@-2 {{member 'method' cannot be used on value of protocol type 'Z.Protocol'; use a generic constraint instead}}
236-
// expected-error@-3 {{protocol 'Z' can only be used as a generic constraint because it has Self or associated type requirements}}
241+
// expected-error@-1 {{member 'method' cannot be used on value of protocol type 'Z.Protocol'; use a generic constraint instead}}
242+
// expected-error@-2 {{protocol 'Z' can only be used as a generic constraint because it has Self or associated type requirements}}

test/Generics/where_clause_contextually_generic_decls.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ protocol Whereable {
3232
}
3333

3434
extension Whereable {
35-
// expected-note@+1 {{'staticExtensionFunc(arg:)' declared here}}
35+
// expected-note@+1 {{where 'Self' = 'T1'}}
3636
static func staticExtensionFunc(arg: Self.Element) -> Self.Element
3737
where Self: Sequence {
3838
return arg
@@ -53,7 +53,7 @@ func testProtocolExtensions<T1, T2, T3, T4>(t1: T1, t2: T2, t3: T3, t4: T4)
5353
T2: Whereable & Sequence,
5454
T3: Whereable, T3.Assoc == T3.Bssoc,
5555
T4: Whereable, T4.Assoc: Whereable {
56-
_ = T1.staticExtensionFunc // expected-error {{cannot reference static method 'staticExtensionFunc(arg:)' on 'Whereable.Protocol' with non-conforming result type 'T1.Element'}}
56+
_ = T1.staticExtensionFunc // expected-error {{static method 'staticExtensionFunc(arg:)' requires that 'T1' conform to 'Sequence'}}
5757
_ = T2.staticExtensionFunc
5858

5959
t1.extensionFunc() // expected-error {{instance method 'extensionFunc()' requires the types 'T1.Assoc' and 'T1.Bssoc' be equivalent}}

test/decl/ext/protocol.swift

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -197,8 +197,8 @@ extension AnotherBazProtocol where BazValue: AnotherBazProtocol {} // ok, does n
197197
// Protocol extensions with additional requirements
198198
// ----------------------------------------------------------------------------
199199
extension P4 where Self.AssocP4 : P1 {
200-
// expected-note@-1 {{where 'Self.AssocP4' = 'Int'}}
201-
// expected-note@-2 {{where 'Self.AssocP4' = 'S4aHelper'}}
200+
// expected-note@-1 {{candidate requires that 'Int' conform to 'P1' (requirement specified as 'Self.AssocP4' == 'P1')}}
201+
// expected-note@-2 {{candidate requires that 'S4aHelper' conform to 'P1' (requirement specified as 'Self.AssocP4' == 'P1')}}
202202
func extP4a() {
203203
acceptsP1(reqP4a())
204204
}
@@ -230,13 +230,15 @@ extension P4 where Self.AssocP4 == Int { // expected-note {{where 'Self.AssocP4'
230230
}
231231

232232
extension P4 where Self.AssocP4 == Bool {
233+
// expected-note@-1 {{candidate requires that the types 'Int' and 'Bool' be equivalent (requirement specified as 'Self.AssocP4' == 'Bool')}}
234+
// expected-note@-2 {{candidate requires that the types 'S4aHelper' and 'Bool' be equivalent (requirement specified as 'Self.AssocP4' == 'Bool')}}
233235
func extP4a() -> Bool { return reqP4a() }
234236
}
235237

236238
func testP4(_ s4a: S4a, s4b: S4b, s4c: S4c, s4d: S4d) {
237-
s4a.extP4a() // expected-error{{referencing instance method 'extP4a()' on 'P4' requires that 'S4aHelper' conform to 'P1'}}
239+
s4a.extP4a() // expected-error{{no exact matches in call to instance method 'extP4a'}}
238240
s4b.extP4a() // ok
239-
s4c.extP4a() // expected-error{{referencing instance method 'extP4a()' on 'P4' requires that 'Int' conform to 'P1'}}
241+
s4c.extP4a() // expected-error{{no exact matches in call to instance method 'extP4a'}}
240242
s4c.extP4Int() // okay
241243
var b1 = s4d.extP4a() // okay, "Bool" version
242244
b1 = true // checks type above

0 commit comments

Comments
 (0)