@@ -184,3 +184,80 @@ void swift::conformToCxxIteratorIfNeeded(
184184 impl.addSynthesizedProtocolAttrs (decl,
185185 {KnownProtocolKind::UnsafeCxxInputIterator});
186186}
187+
188+ void swift::conformToCxxSequenceIfNeeded (
189+ ClangImporter::Implementation &impl, NominalTypeDecl *decl,
190+ const clang::CXXRecordDecl *clangDecl) {
191+ PrettyStackTraceDecl trace (" conforming to CxxSequence" , decl);
192+
193+ assert (decl);
194+ assert (clangDecl);
195+ ASTContext &ctx = decl->getASTContext ();
196+
197+ ProtocolDecl *cxxIteratorProto =
198+ ctx.getProtocol (KnownProtocolKind::UnsafeCxxInputIterator);
199+ ProtocolDecl *cxxSequenceProto =
200+ ctx.getProtocol (KnownProtocolKind::CxxSequence);
201+ // If the Cxx module is missing, or does not include one of the necessary
202+ // protocols, bail.
203+ if (!cxxIteratorProto || !cxxSequenceProto)
204+ return ;
205+
206+ // Check if present: `mutating func __beginUnsafe() -> RawIterator`
207+ auto beginId = ctx.getIdentifier (" __beginUnsafe" );
208+ auto begins = lookupDirectWithoutExtensions (decl, beginId);
209+ if (begins.size () != 1 )
210+ return ;
211+ auto begin = dyn_cast<FuncDecl>(begins.front ());
212+ if (!begin)
213+ return ;
214+ auto rawIteratorTy = begin->getResultInterfaceType ();
215+
216+ // Check if present: `mutating func __endUnsafe() -> RawIterator`
217+ auto endId = ctx.getIdentifier (" __endUnsafe" );
218+ auto ends = lookupDirectWithoutExtensions (decl, endId);
219+ if (ends.size () != 1 )
220+ return ;
221+ auto end = dyn_cast<FuncDecl>(ends.front ());
222+ if (!end)
223+ return ;
224+
225+ // Check if `__beginUnsafe` and `__endUnsafe` have the same return type.
226+ auto endTy = end->getResultInterfaceType ();
227+ if (!endTy || endTy->getCanonicalType () != rawIteratorTy->getCanonicalType ())
228+ return ;
229+
230+ // Check if RawIterator conforms to UnsafeCxxInputIterator.
231+ auto rawIteratorConformanceRef = decl->getModuleContext ()->lookupConformance (
232+ rawIteratorTy, cxxIteratorProto);
233+ if (!rawIteratorConformanceRef.isConcrete ())
234+ return ;
235+ auto rawIteratorConformance = rawIteratorConformanceRef.getConcrete ();
236+ auto pointeeDecl =
237+ cxxIteratorProto->getAssociatedType (ctx.getIdentifier (" Pointee" ));
238+ assert (pointeeDecl &&
239+ " UnsafeCxxInputIterator must have a Pointee associated type" );
240+ auto pointeeTy = rawIteratorConformance->getTypeWitness (pointeeDecl);
241+ assert (pointeeTy && " valid conformance must have a Pointee witness" );
242+
243+ // Take the default definition of `Iterator` from CxxSequence protocol. This
244+ // type is currently `CxxIterator<Self>`.
245+ auto iteratorDecl = cxxSequenceProto->getAssociatedType (ctx.Id_Iterator );
246+ auto iteratorTy = iteratorDecl->getDefaultDefinitionType ();
247+ // Substitute generic `Self` parameter.
248+ auto cxxSequenceSelfTy = cxxSequenceProto->getSelfInterfaceType ();
249+ auto declSelfTy = decl->getDeclaredInterfaceType ();
250+ iteratorTy = iteratorTy.subst (
251+ [&](SubstitutableType *dependentType) {
252+ if (dependentType->isEqual (cxxSequenceSelfTy))
253+ return declSelfTy;
254+ return Type (dependentType);
255+ },
256+ LookUpConformanceInModule (decl->getModuleContext ()));
257+
258+ impl.addSynthesizedTypealias (decl, ctx.Id_Element , pointeeTy);
259+ impl.addSynthesizedTypealias (decl, ctx.Id_Iterator , iteratorTy);
260+ impl.addSynthesizedTypealias (decl, ctx.getIdentifier (" RawIterator" ),
261+ rawIteratorTy);
262+ impl.addSynthesizedProtocolAttrs (decl, {KnownProtocolKind::CxxSequence});
263+ }
0 commit comments