@@ -319,6 +319,8 @@ void swift::conformToCxxSequenceIfNeeded(
319
319
ctx.getProtocol (KnownProtocolKind::UnsafeCxxInputIterator);
320
320
ProtocolDecl *cxxSequenceProto =
321
321
ctx.getProtocol (KnownProtocolKind::CxxSequence);
322
+ ProtocolDecl *cxxConvertibleProto =
323
+ ctx.getProtocol (KnownProtocolKind::CxxConvertibleToCollection);
322
324
// If the Cxx module is missing, or does not include one of the necessary
323
325
// protocols, bail.
324
326
if (!cxxIteratorProto || !cxxSequenceProto)
@@ -389,47 +391,62 @@ void swift::conformToCxxSequenceIfNeeded(
389
391
390
392
// Try to conform to CxxRandomAccessCollection if possible.
391
393
392
- auto cxxRAIteratorProto =
393
- ctx.getProtocol (KnownProtocolKind::UnsafeCxxRandomAccessIterator);
394
- if (!cxxRAIteratorProto ||
395
- !ctx.getProtocol (KnownProtocolKind::CxxRandomAccessCollection))
396
- return ;
397
-
398
- // Check if `begin()` and `end()` are non-mutating.
399
- if (begin->isMutating () || end->isMutating ())
400
- return ;
394
+ auto tryToConformToRandomAccessCollection = [&]() -> bool {
395
+ auto cxxRAIteratorProto =
396
+ ctx.getProtocol (KnownProtocolKind::UnsafeCxxRandomAccessIterator);
397
+ if (!cxxRAIteratorProto ||
398
+ !ctx.getProtocol (KnownProtocolKind::CxxRandomAccessCollection))
399
+ return false ;
401
400
402
- // Check if RawIterator conforms to UnsafeCxxRandomAccessIterator.
403
- auto rawIteratorRAConformanceRef =
404
- decl->getModuleContext ()->lookupConformance (rawIteratorTy,
405
- cxxRAIteratorProto);
406
- if (!isConcreteAndValid (rawIteratorRAConformanceRef, module))
407
- return ;
401
+ // Check if `begin()` and `end()` are non-mutating.
402
+ if (begin->isMutating () || end->isMutating ())
403
+ return false ;
408
404
409
- // CxxRandomAccessCollection always uses Int as an Index.
410
- auto indexTy = ctx.getIntType ();
405
+ // Check if RawIterator conforms to UnsafeCxxRandomAccessIterator.
406
+ auto rawIteratorRAConformanceRef =
407
+ decl->getModuleContext ()->lookupConformance (rawIteratorTy,
408
+ cxxRAIteratorProto);
409
+ if (!isConcreteAndValid (rawIteratorRAConformanceRef, module))
410
+ return false ;
411
411
412
- auto sliceTy = ctx.getSliceType ();
413
- sliceTy = sliceTy.subst (
414
- [&](SubstitutableType *dependentType) {
415
- if (dependentType->isEqual (cxxSequenceSelfTy))
416
- return declSelfTy;
417
- return Type (dependentType);
418
- },
419
- LookUpConformanceInModule (module));
412
+ // CxxRandomAccessCollection always uses Int as an Index.
413
+ auto indexTy = ctx.getIntType ();
414
+
415
+ auto sliceTy = ctx.getSliceType ();
416
+ sliceTy = sliceTy.subst (
417
+ [&](SubstitutableType *dependentType) {
418
+ if (dependentType->isEqual (cxxSequenceSelfTy))
419
+ return declSelfTy;
420
+ return Type (dependentType);
421
+ },
422
+ LookUpConformanceInModule (module));
423
+
424
+ auto indicesTy = ctx.getRangeType ();
425
+ indicesTy = indicesTy.subst (
426
+ [&](SubstitutableType *dependentType) {
427
+ if (dependentType->isEqual (cxxSequenceSelfTy))
428
+ return indexTy;
429
+ return Type (dependentType);
430
+ },
431
+ LookUpConformanceInModule (module));
432
+
433
+ impl.addSynthesizedTypealias (decl, ctx.getIdentifier (" Index" ), indexTy);
434
+ impl.addSynthesizedTypealias (decl, ctx.getIdentifier (" Indices" ), indicesTy);
435
+ impl.addSynthesizedTypealias (decl, ctx.getIdentifier (" SubSequence" ),
436
+ sliceTy);
437
+ impl.addSynthesizedProtocolAttrs (
438
+ decl, {KnownProtocolKind::CxxRandomAccessCollection});
439
+ return true ;
440
+ };
420
441
421
- auto indicesTy = ctx.getRangeType ();
422
- indicesTy = indicesTy.subst (
423
- [&](SubstitutableType *dependentType) {
424
- if (dependentType->isEqual (cxxSequenceSelfTy))
425
- return indexTy;
426
- return Type (dependentType);
427
- },
428
- LookUpConformanceInModule (module));
442
+ bool conformedToRAC = tryToConformToRandomAccessCollection ();
429
443
430
- impl.addSynthesizedTypealias (decl, ctx.getIdentifier (" Index" ), indexTy);
431
- impl.addSynthesizedTypealias (decl, ctx.getIdentifier (" Indices" ), indicesTy);
432
- impl.addSynthesizedTypealias (decl, ctx.getIdentifier (" SubSequence" ), sliceTy);
433
- impl.addSynthesizedProtocolAttrs (
434
- decl, {KnownProtocolKind::CxxRandomAccessCollection});
444
+ // If the collection does not support random access, let's still allow the
445
+ // developer to explicitly convert a C++ sequence to a Swift Array (making a
446
+ // copy of the sequence's elements) by conforming the type to
447
+ // CxxCollectionConvertible. This enables an overload of Array.init declared
448
+ // in the Cxx module.
449
+ if (!conformedToRAC && cxxConvertibleProto)
450
+ impl.addSynthesizedProtocolAttrs (
451
+ decl, {KnownProtocolKind::CxxConvertibleToCollection});
435
452
}
0 commit comments