Skip to content

Commit 5dc66c0

Browse files
Merge pull request #78310 from AnthonyLatsis/nymphaea-alba
Sema: Handle the edge case of in-out metatype parameter in `canOpenExistentialCallArgument`
2 parents 8111fe9 + 08ccfad commit 5dc66c0

File tree

2 files changed

+85
-12
lines changed

2 files changed

+85
-12
lines changed

lib/Sema/OpenedExistentials.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -649,10 +649,11 @@ swift::canOpenExistentialCallArgument(ValueDecl *callee, unsigned paramIdx,
649649
if (param->isVariadic())
650650
return std::nullopt;
651651

652-
// Look through an inout and optional types on the formal type of the
653-
// parameter.
652+
// Look through an inout and an optional type on the parameter types.
654653
auto formalParamTy = param->getInterfaceType()->getInOutObjectType()
655654
->lookThroughSingleOptionalType();
655+
// Look through an inout and optional types on the parameter.
656+
paramTy = paramTy->getInOutObjectType()->lookThroughSingleOptionalType();
656657

657658
// If the argument is of an existential metatype, look through the
658659
// metatype on the parameter.
@@ -661,9 +662,6 @@ swift::canOpenExistentialCallArgument(ValueDecl *callee, unsigned paramIdx,
661662
paramTy = paramTy->getMetatypeInstanceType();
662663
}
663664

664-
// Look through an inout and optional types on the parameter.
665-
paramTy = paramTy->getInOutObjectType()->lookThroughSingleOptionalType();
666-
667665
// The parameter type must be a type variable.
668666
auto paramTypeVar = paramTy->getAs<TypeVariableType>();
669667
if (!paramTypeVar)

test/Constraints/opened_existentials.swift

Lines changed: 82 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,16 @@
1-
// RUN: %target-typecheck-verify-swift -disable-availability-checking
1+
// RUN: %target-typecheck-verify-swift -target %target-swift-5.7-abi-triple -dump-ast | %FileCheck %s
2+
3+
/// Used to verify the type of an expression. Use like this:
4+
/// ```
5+
/// var types = SwiftTypePair(typeOf: expr, type2: SwiftType<Int>.self)
6+
/// types.assertTypesAreEqual()
7+
/// ```
8+
struct SwiftType<T> {}
9+
struct SwiftTypePair<T1, T2> {
10+
init(typeOf: T1, type2: SwiftType<T2>.Type) {}
11+
12+
mutating func assertTypesAreEqual() where T1 == T2 {}
13+
}
214

315
protocol Q { }
416

@@ -26,16 +38,20 @@ func acceptCollection<C: Collection>(_ c: C) -> C.Element { c.first! }
2638

2739
// --- Simple opening of existential values
2840
func testSimpleExistentialOpening(p: any P, pq: any P & Q, c: any Collection) {
41+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
2942
let pa = acceptGeneric(p)
3043
let _: Int = pa // expected-error{{cannot convert value of type '(any Q)?' to specified type 'Int'}}
3144

3245
var vp = p
46+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
3347
let vpa = acceptGeneric(vp)
3448
let _: Int = vpa // expected-error{{cannot convert value of type '(any Q)?' to specified type 'Int'}}
3549

50+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
3651
let pqa = acceptGeneric(pq)
3752
let _: Int = pqa // expected-error{{cannot convert value of type '(any Q)?' to specified type 'Int'}}
3853

54+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
3955
let element = acceptCollection(c)
4056
let _: Int = element // expected-error{{cannot convert value of type 'Any' to specified type 'Int'}}
4157
}
@@ -50,6 +66,7 @@ func takeCollectionOfPs<C: Collection>(_: C) -> C.Element.A?
5066
}
5167

5268
func testCollectionOfPs(cp: any CollectionOfPs) {
69+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
5370
let e = takeCollectionOfPs(cp)
5471
let _: Int = e // expected-error{{cannot convert value of type '(any Q)?' to specified type 'Int'}}
5572
}
@@ -62,9 +79,11 @@ extension P {
6279
}
6380

6481
func testMultipleOpened(a: any P, b: any P & Q) {
82+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
6583
let r1 = takeTwoGenerics(a, b)
6684
let _: Int = r1 // expected-error{{cannot convert value of type '(any P, any P & Q)' to specified type 'Int'}}
6785

86+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
6887
let r2 = a.combineThePs(b)
6988
let _: Int = r2 // expected-error{{cannot convert value of type '(any Q, any Q)?' to specified type 'Int'}}
7089
}
@@ -75,6 +94,7 @@ func conjureValue<T: P>(of type: T.Type) -> T? {
7594
}
7695

7796
func testMagic(pt: any P.Type) {
97+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
7898
let pOpt = conjureValue(of: pt)
7999
let _: Int = pOpt // expected-error{{cannot convert value of type '(any P)?' to specified type 'Int'}}
80100
}
@@ -162,13 +182,15 @@ func takesInOut<T: P>(_ value: inout T) { }
162182

163183
func passesInOut(i: Int) {
164184
var p: any P = i
185+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
165186
takesInOut(&p)
166187
}
167188

168189
func takesOptional<T: P>(_ value: T?) { }
169190
// expected-note@-1{{required by global function 'takesOptional' where 'T' = 'any P'}}
170191

171192
func passesToOptional(p: any P, pOpt: (any P)?) {
193+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
172194
takesOptional(p) // okay
173195
takesOptional(pOpt) // expected-error{{type 'any P' cannot conform to 'P'}}
174196
// expected-note@-1{{only concrete types such as structs, enums and classes can conform to protocols}}
@@ -177,20 +199,24 @@ func passesToOptional(p: any P, pOpt: (any P)?) {
177199

178200
@available(SwiftStdlib 5.1, *)
179201
func testReturningOpaqueTypes(p: any P) {
202+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
180203
let q = p.getQ()
181204
let _: Int = q // expected-error{{cannot convert value of type 'any Q' to specified type 'Int'}}
182205

183206
p.getCollectionOf() // expected-error{{member 'getCollectionOf' cannot be used on value of type 'any P'; consider using a generic constraint instead}}
184207

208+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
185209
let q2 = getPQ(p)
186210
let _: Int = q2 // expected-error{{cannot convert value of type 'any Q' to specified type 'Int'}}
187211

188212
getCollectionOfP(p) // expected-error{{type 'any P' cannot conform to 'P'}}
189213
// expected-note@-1{{only concrete types such as structs, enums and classes can conform to protocols}}
190214

215+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
191216
let fi = funnyIdentity(p)
192217
let _: Int = fi // expected-error{{cannot convert value of type '(any P)?' to specified type 'Int'}}
193218

219+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
194220
_ = arrayOfOne(p) // okay, arrays are covariant in their argument
195221

196222
_ = createX(p) // expected-error{{type 'any P' cannot conform to 'P'}}
@@ -210,13 +236,20 @@ func overloadedGenericFunctionTakingP<T: P>(_: T) { }
210236

211237
func testTakeValueAndClosure(p: any P) {
212238
// Type-erase when not provided with a generic function.
239+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
213240
takeValueAndClosure(p) { x in
214-
print(x)
215-
let _: Int = x // expected-error{{cannot convert value of type 'any P' to specified type 'Int'}}
241+
var types = SwiftTypePair(typeOf: x, type2: SwiftType<any P>.self)
242+
types.assertTypesAreEqual()
243+
244+
return ()
216245
}
217246

218247
// Do not erase when referring to a generic function.
248+
// FIXME:
249+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
219250
takeValueAndClosure(p, body: genericFunctionTakingP)
251+
// FIXME:
252+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
220253
takeValueAndClosure(p, body: overloadedGenericFunctionTakingP)
221254
takeValueAndClosure(p, body: genericFunctionTakingPQ) // expected-error{{global function 'genericFunctionTakingPQ' requires that 'T' conform to 'Q'}}
222255

@@ -255,32 +288,47 @@ func testExplicitCoercionRequirement(v: any B, otherV: any B & D) {
255288
func overloaded<T: B>(_: T) -> (x: Int, y: T.C) { fatalError() }
256289
func overloaded<T: P>(_: T) -> Int { 42 }
257290

291+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
258292
_ = getC(v) // Ok
293+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
259294
_ = getC(v) as any P // Ok
260-
295+
296+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
261297
_ = getE(v) // Ok
298+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
262299
_ = getE(v) as any P1<Double> // Ok
263-
300+
301+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
264302
_ = getTuple(v) // Ok
303+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
265304
_ = getTuple(v) as (any B, any P) // Ok
266305
// Ok because T.C.A == Double
306+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
267307
_ = getNoError(v)
268308

309+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
269310
_ = getComplex(v) // Ok
311+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
270312
_ = getComplex(v) as ([(x: (a: any P, b: Int), y: Int)], [Int : any P]) // Ok
271313

314+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
272315
_ = overloaded(v) // Ok
273316

274317
func acceptsAny<T>(_: T) {}
275318

319+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
276320
acceptsAny(getC(v)) // Ok
321+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
277322
acceptsAny(getC(v) as any P) // Ok
278323

324+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
279325
acceptsAny(getComplex(v)) // Ok
326+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
280327
acceptsAny(getComplex(v) as ([(x: (a: any P, b: Int), y: Int)], [Int : any P]))
281328

282329
func getAssocNoRequirements<T: B>(_: T) -> (Int, [T.D]) { fatalError() }
283330

331+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
284332
_ = getAssocNoRequirements(v) // Ok, `D` doesn't have any requirements
285333

286334
// Test existential opening from protocol extension access
@@ -292,24 +340,35 @@ func testExplicitCoercionRequirement(v: any B, otherV: any B & D) {
292340

293341
func getF<T: D>(_: T) -> T.E { fatalError() }
294342

343+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
295344
_ = getF(otherV) // Ok `E` doesn't have a `where` clause
296345

297346
func getSelf<T: B>(_: T) -> T { fatalError() } // expected-note {{found this candidate}}
298347
func getSelf<T: D>(_: T) -> T { fatalError() } // expected-note {{found this candidate}}
299348

349+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
300350
_ = getSelf(v) // Ok
351+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
301352
_ = getSelf(v) as any B // Ok
302353
_ = getSelf(otherV) as any B & D // expected-error {{ambiguous use of 'getSelf'}}
303354

304355
func getBDSelf<T: D>(_: T) -> T { fatalError() }
356+
357+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
305358
_ = getBDSelf(otherV) // Ok
359+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
306360
_ = getBDSelf(otherV) as any B & D // Ok
307361

308362
func getP<T: P>(_: T) {}
363+
364+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
309365
getP(getC(v)) // Ok
366+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
310367
getP(v.getC()) // Ok
311368

369+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
312370
getP((getC(v) as any P)) // Ok - parens avoid opening suppression
371+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
313372
getP((v.getC() as any P)) // Ok - parens avoid opening suppression
314373
}
315374

@@ -417,9 +476,25 @@ struct S<T, U> {
417476
}
418477
}
419478

420-
func nestedMetatypeCallee<T>(_ t: T) {}
479+
do {
480+
func nestedMetatypeCallee<T>(_ t: T) {}
421481

422-
func nestedMetatypeCaller() {
423482
let t = String.Type.Type.Type.self as (any Q.Type.Type.Type.Type)
483+
// CHECK-NOT: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
424484
nestedMetatypeCallee(t)
425485
}
486+
487+
do {
488+
protocol P {}
489+
490+
func foo<T: P>(_ m: inout T.Type) {}
491+
492+
// expected-note@+1 {{change 'let' to 'var' to make it mutable}}
493+
let rValueP: P.Type
494+
var lValueP: P.Type
495+
496+
// expected-error@+1 {{cannot pass immutable value as inout argument: 'rValueP' is a 'let' constant}}
497+
foo(&rValueP)
498+
// CHECK: open_existential_expr {{.*}} location={{.*}}:[[@LINE+1]]:{{[0-9]+}} range=
499+
foo(&lValueP)
500+
}

0 commit comments

Comments
 (0)