Skip to content

Commit 4d61f48

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

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
@@ -32,6 +32,35 @@ Type Type::join(Type type1, Type type2) {
3232
if (type1->isEqual(type2))
3333
return type1;
3434

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