@@ -51,6 +51,9 @@ struct TypeJoin : CanTypeVisitor<TypeJoin, CanType> {
51
51
}
52
52
53
53
static CanType getSuperclassJoin (CanType first, CanType second);
54
+ CanType computeProtocolCompositionJoin (ArrayRef<Type> firstMembers,
55
+ ArrayRef<Type> secondMembers);
56
+
54
57
55
58
CanType visitErrorType (CanType second);
56
59
CanType visitTupleType (CanType second);
@@ -105,10 +108,10 @@ struct TypeJoin : CanTypeVisitor<TypeJoin, CanType> {
105
108
106
109
// Likewise, rather than making every visitor deal with Any,
107
110
// always dispatch to the protocol composition side of the join.
108
- if (first->isAny ())
111
+ if (first->is <ProtocolCompositionType> ())
109
112
return TypeJoin (second).visit (first);
110
113
111
- if (second->isAny ())
114
+ if (second->is <ProtocolCompositionType> ())
112
115
return TypeJoin (first).visit (second);
113
116
114
117
// Otherwise the first type might be an optional (or not), so
@@ -184,16 +187,6 @@ CanType TypeJoin::visitClassType(CanType second) {
184
187
return getSuperclassJoin (First, second);
185
188
}
186
189
187
- CanType TypeJoin::visitProtocolType (CanType second) {
188
- assert (First != second);
189
-
190
- // FIXME: We should compute a tighter bound and/or return nullptr if
191
- // we cannot. We do this now because existing tests rely on
192
- // producing Any for the join of protocols that have a common
193
- // supertype.
194
- return TheAnyType;
195
- }
196
-
197
190
CanType TypeJoin::visitBoundGenericClassType (CanType second) {
198
191
return getSuperclassJoin (First, second);
199
192
}
@@ -352,16 +345,111 @@ CanType TypeJoin::visitGenericFunctionType(CanType second) {
352
345
return Unimplemented;
353
346
}
354
347
348
+ // Use the distributive law to compute the join of the protocol
349
+ // compositions.
350
+ //
351
+ // (A ^ B) v (C ^ D)
352
+ // = (A v C) ^ (A v D) ^ (B v C) ^ (B v D)
353
+ //
354
+ // In general this law only applies to distributive lattices.
355
+ //
356
+ // In our case, this should be safe because our meet operation only
357
+ // produces an existing nominal type when it is one of the operands of
358
+ // the operation. So we can never arbitrarily climb down the lattice
359
+ // in ways that would break distributivity.
360
+ //
361
+ CanType TypeJoin::computeProtocolCompositionJoin (ArrayRef<Type> firstMembers,
362
+ ArrayRef<Type> secondMembers) {
363
+ SmallVector<Type, 8 > result;
364
+ for (auto first : firstMembers) {
365
+ for (auto second : secondMembers) {
366
+ auto joined = Type::join (first, second);
367
+ if (!joined)
368
+ return Unimplemented;
369
+
370
+ if ((*joined)->isAny ())
371
+ continue ;
372
+
373
+ result.push_back (*joined);
374
+ }
375
+ }
376
+
377
+ if (result.empty ())
378
+ return TheAnyType;
379
+
380
+ auto &ctx = result[0 ]->getASTContext ();
381
+ return ProtocolCompositionType::get (ctx, result, false )->getCanonicalType ();
382
+ }
383
+
355
384
CanType TypeJoin::visitProtocolCompositionType (CanType second) {
385
+ // The join of Any and a no-escape function doesn't exist; it isn't
386
+ // Any. If it were Any, it would mean we would allow these functions
387
+ // to escape through Any.
356
388
if (second->isAny ()) {
357
389
auto *fnTy = First->getAs <AnyFunctionType>();
358
390
if (fnTy && fnTy->getExtInfo ().isNoEscape ())
359
391
return Nonexistent;
360
392
361
- return second ;
393
+ return TheAnyType ;
362
394
}
363
395
364
- return Unimplemented;
396
+ assert (First != second);
397
+
398
+ // FIXME: Handle other types here.
399
+ if (!First->isExistentialType ())
400
+ return TheAnyType;
401
+
402
+ SmallVector<Type, 1 > protocolType;
403
+ ArrayRef<Type> firstMembers;
404
+ if (First->is <ProtocolType>()) {
405
+ protocolType.push_back (First);
406
+ firstMembers = protocolType;
407
+ } else {
408
+ firstMembers = cast<ProtocolCompositionType>(First)->getMembers ();
409
+ }
410
+ auto secondMembers = cast<ProtocolCompositionType>(second)->getMembers ();
411
+
412
+ return computeProtocolCompositionJoin (firstMembers, secondMembers);
413
+ }
414
+
415
+ CanType TypeJoin::visitProtocolType (CanType second) {
416
+ assert (First != second);
417
+
418
+ assert (!First->is <ProtocolCompositionType>() &&
419
+ !second->is <ProtocolCompositionType>());
420
+
421
+ // FIXME: Handle other types here.
422
+ if (First->getKind () != second->getKind ())
423
+ return TheAnyType;
424
+
425
+ auto *firstDecl =
426
+ cast<ProtocolDecl>(First->getNominalOrBoundGenericNominal ());
427
+
428
+ auto *secondDecl =
429
+ cast<ProtocolDecl>(second->getNominalOrBoundGenericNominal ());
430
+
431
+ if (firstDecl->getInheritedProtocols ().empty () &&
432
+ secondDecl->getInheritedProtocols ().empty ())
433
+ return TheAnyType;
434
+
435
+ if (firstDecl->inheritsFrom (secondDecl))
436
+ return second;
437
+
438
+ if (secondDecl->inheritsFrom (firstDecl))
439
+ return First;
440
+
441
+ // One isn't the supertype of the other, so instead, treat each as
442
+ // if it's a protocol composition of its inherited members, and join
443
+ // those.
444
+ SmallVector<Type, 4 > firstMembers;
445
+ for (auto *decl : firstDecl->getInheritedProtocols ())
446
+ firstMembers.push_back (decl->getDeclaredInterfaceType ());
447
+
448
+ SmallVector<Type, 4 > secondMembers;
449
+ for (auto *decl : secondDecl->getInheritedProtocols ())
450
+ secondMembers.push_back (decl->getDeclaredInterfaceType ());
451
+
452
+ return computeProtocolCompositionJoin (firstMembers, secondMembers);
365
453
}
366
454
367
455
CanType TypeJoin::visitLValueType (CanType second) { return Unimplemented; }
0 commit comments