Skip to content

Commit 1b92e72

Browse files
committed
AST: Fix Type::join() to do the right thing with class metatypes
Fixes <rdar://problem/30233451>.
1 parent 4a3c5d8 commit 1b92e72

File tree

2 files changed

+83
-0
lines changed

2 files changed

+83
-0
lines changed

lib/AST/TypeJoinMeet.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,35 @@ Type Type::join(Type type1, Type type2) {
3333
if (type1->isEqual(type2))
3434
return type1;
3535

36+
// If both are class metatypes, compute the join of the instance type and
37+
// wrap the result in a metatype.
38+
if (auto *metatype1 = type1->getAs<MetatypeType>()) {
39+
if (auto *metatype2 = type2->getAs<MetatypeType>()) {
40+
auto instance1 = metatype1->getInstanceType();
41+
auto instance2 = metatype2->getInstanceType();
42+
if (instance1->mayHaveSuperclass() &&
43+
instance2->mayHaveSuperclass()) {
44+
auto result = Type::join(instance1, instance2);
45+
if (!result)
46+
return result;
47+
return MetatypeType::get(result);
48+
}
49+
}
50+
}
51+
52+
// If both are existential metatypes, compute the join of the instance type
53+
// and wrap the result in an existential metatype.
54+
if (auto *metatype1 = type1->getAs<ExistentialMetatypeType>()) {
55+
if (auto *metatype2 = type2->getAs<ExistentialMetatypeType>()) {
56+
auto instance1 = metatype1->getInstanceType();
57+
auto instance2 = metatype2->getInstanceType();
58+
auto result = Type::join(instance1, instance2);
59+
if (!result)
60+
return result;
61+
return ExistentialMetatypeType::get(result);
62+
}
63+
}
64+
3665
// If both are class types or opaque types that potentially have superclasses,
3766
// find the common superclass.
3867
if (type1->mayHaveSuperclass() && type2->mayHaveSuperclass()) {

test/Constraints/array_literal.swift

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,3 +173,57 @@ func testOptionSetLike(b: Bool) {
173173
let _: OptionSetLike = [ b ? [] : OptionSetLike.option, OptionSetLike.option]
174174
let _: OptionSetLike = [ b ? [] : .option, .option]
175175
}
176+
177+
// Join of class metatypes - <rdar://problem/30233451>
178+
179+
class Company<T> {
180+
init(routes: [() -> T]) { }
181+
}
182+
183+
class Person { }
184+
185+
class Employee: Person { }
186+
187+
class Manager: Person { }
188+
189+
let router = Company(
190+
routes: [
191+
{ () -> Employee.Type in
192+
_ = ()
193+
return Employee.self
194+
},
195+
196+
{ () -> Manager.Type in
197+
_ = ()
198+
return Manager.self
199+
}
200+
]
201+
)
202+
203+
// Same as above but with existentials
204+
205+
protocol Fruit {}
206+
207+
protocol Tomato : Fruit {}
208+
209+
struct Chicken : Tomato {}
210+
211+
protocol Pear : Fruit {}
212+
213+
struct Beef : Pear {}
214+
215+
let router = Company(
216+
routes: [
217+
// FIXME: implement join() for existentials
218+
// expected-error@+1 {{cannot convert value of type '() -> Tomato.Type' to expected element type '() -> _'}}
219+
{ () -> Tomato.Type in
220+
_ = ()
221+
return Chicken.self
222+
},
223+
224+
{ () -> Pear.Type in
225+
_ = ()
226+
return Beef.self
227+
}
228+
]
229+
)

0 commit comments

Comments
 (0)