@@ -319,6 +319,8 @@ void swift::conformToCxxSequenceIfNeeded(
319319 ctx.getProtocol (KnownProtocolKind::UnsafeCxxInputIterator);
320320 ProtocolDecl *cxxSequenceProto =
321321 ctx.getProtocol (KnownProtocolKind::CxxSequence);
322+ ProtocolDecl *cxxConvertibleProto =
323+ ctx.getProtocol (KnownProtocolKind::CxxConvertibleToCollection);
322324 // If the Cxx module is missing, or does not include one of the necessary
323325 // protocols, bail.
324326 if (!cxxIteratorProto || !cxxSequenceProto)
@@ -389,47 +391,62 @@ void swift::conformToCxxSequenceIfNeeded(
389391
390392 // Try to conform to CxxRandomAccessCollection if possible.
391393
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 ;
401400
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 ;
408404
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 ;
411411
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+ };
420441
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 ();
429443
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});
435452}
0 commit comments