@@ -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,130 @@ 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
+ CanType TypeJoin::computeProtocolCompositionJoin (ArrayRef<Type> firstMembers,
354
+ ArrayRef<Type> secondMembers) {
355
+ SmallVector<Type, 8 > result;
356
+ for (auto first : firstMembers) {
357
+ for (auto second : secondMembers) {
358
+ auto joined = Type::join (first, second);
359
+ if (!joined)
360
+ return Unimplemented;
361
+
362
+ if ((*joined)->isAny ())
363
+ continue ;
364
+
365
+ result.push_back (*joined);
366
+ }
367
+ }
368
+
369
+ if (result.empty ())
370
+ return TheAnyType;
371
+
372
+ auto &ctx = result[0 ]->getASTContext ();
373
+ return ProtocolCompositionType::get (ctx, result, false )->getCanonicalType ();
374
+ }
375
+
355
376
CanType TypeJoin::visitProtocolCompositionType (CanType second) {
377
+ // The join of Any and a no-escape function doesn't exist; it isn't
378
+ // Any. If it were Any, it would mean we would allow these functions
379
+ // to escape through Any.
356
380
if (second->isAny ()) {
357
381
auto *fnTy = First->getAs <AnyFunctionType>();
358
382
if (fnTy && fnTy->getExtInfo ().isNoEscape ())
359
383
return Nonexistent;
360
384
361
- return second ;
385
+ return TheAnyType ;
362
386
}
363
387
364
- return Unimplemented;
388
+ assert (First != second);
389
+
390
+ // FIXME: Handle other types here.
391
+ if (First->getKind () != TypeKind::Protocol &&
392
+ First->getKind () != TypeKind::ProtocolComposition)
393
+ return TheAnyType;
394
+
395
+ SmallVector<Type, 1 > protocolType;
396
+ ArrayRef<Type> firstMembers;
397
+ if (First->getKind () == TypeKind::Protocol) {
398
+ protocolType.push_back (First);
399
+ firstMembers = protocolType;
400
+ } else {
401
+ firstMembers = cast<ProtocolCompositionType>(First)->getMembers ();
402
+ }
403
+ auto secondMembers = cast<ProtocolCompositionType>(second)->getMembers ();
404
+
405
+ return computeProtocolCompositionJoin (firstMembers, secondMembers);
406
+ }
407
+
408
+ // Return true if the first ProtocolDecl is a supertype of the second.
409
+ static bool isSupertypeOf (ProtocolDecl *super, ProtocolDecl *sub) {
410
+ if (super == sub)
411
+ return true ;
412
+
413
+ SmallVector<ProtocolDecl *, 4 > worklist;
414
+ for (auto *decl : sub->getInheritedProtocols ())
415
+ worklist.push_back (decl);
416
+
417
+ llvm::SmallPtrSet<ProtocolDecl *, 4 > visited;
418
+ while (!worklist.empty ()) {
419
+ auto *entry = worklist.pop_back_val ();
420
+ if (visited.count (entry))
421
+ continue ;
422
+ visited.insert (entry);
423
+
424
+ if (entry == super)
425
+ return true ;
426
+
427
+ for (auto *decl : entry->getInheritedProtocols ())
428
+ worklist.push_back (decl);
429
+ }
430
+
431
+ return false ;
432
+ }
433
+
434
+ CanType TypeJoin::visitProtocolType (CanType second) {
435
+ assert (First != second);
436
+
437
+ assert (First->getKind () != TypeKind::ProtocolComposition &&
438
+ second->getKind () != TypeKind::ProtocolComposition);
439
+
440
+ // FIXME: Handle other types here.
441
+ if (First->getKind () != second->getKind ())
442
+ return TheAnyType;
443
+
444
+ auto *firstDecl =
445
+ cast<ProtocolDecl>(First->getNominalOrBoundGenericNominal ());
446
+
447
+ auto *secondDecl =
448
+ cast<ProtocolDecl>(second->getNominalOrBoundGenericNominal ());
449
+
450
+ if (firstDecl->getInheritedProtocols ().empty () &&
451
+ secondDecl->getInheritedProtocols ().empty ())
452
+ return TheAnyType;
453
+
454
+ if (isSupertypeOf (firstDecl, secondDecl))
455
+ return First;
456
+
457
+ if (isSupertypeOf (secondDecl, firstDecl))
458
+ return second;
459
+
460
+ // One isn't the supertype of the other, so instead, treat each as
461
+ // if it's a protocol composition of its inherited members, and join
462
+ // those.
463
+ SmallVector<Type, 4 > firstMembers;
464
+ for (auto *decl : firstDecl->getInheritedProtocols ())
465
+ firstMembers.push_back (decl->getDeclaredInterfaceType ());
466
+
467
+ SmallVector<Type, 4 > secondMembers;
468
+ for (auto *decl : secondDecl->getInheritedProtocols ())
469
+ secondMembers.push_back (decl->getDeclaredInterfaceType ());
470
+
471
+ return computeProtocolCompositionJoin (firstMembers, secondMembers);
365
472
}
366
473
367
474
CanType TypeJoin::visitLValueType (CanType second) { return Unimplemented; }
0 commit comments