@@ -61,6 +61,15 @@ lookupDirectWithoutExtensions(NominalTypeDecl *decl, Identifier id) {
61
61
return result;
62
62
}
63
63
64
+ template <typename Decl>
65
+ static Decl *lookupDirectSingleWithoutExtensions (NominalTypeDecl *decl,
66
+ Identifier id) {
67
+ auto results = lookupDirectWithoutExtensions (decl, id);
68
+ if (results.size () != 1 )
69
+ return nullptr ;
70
+ return dyn_cast<Decl>(results.front ());
71
+ }
72
+
64
73
// / Similar to ModuleDecl::conformsToProtocol, but doesn't introduce a
65
74
// / dependency on Sema.
66
75
static bool isConcreteAndValid (ProtocolConformanceRef conformanceRef,
@@ -315,19 +324,14 @@ void swift::conformToCxxIteratorIfNeeded(
315
324
316
325
// Check if present: `var pointee: Pointee { get }`
317
326
auto pointeeId = ctx.getIdentifier (" pointee" );
318
- auto pointees = lookupDirectWithoutExtensions (decl, pointeeId);
319
- if (pointees.size () != 1 )
320
- return ;
321
- auto pointee = dyn_cast<VarDecl>(pointees.front ());
327
+ auto pointee = lookupDirectSingleWithoutExtensions<VarDecl>(decl, pointeeId);
322
328
if (!pointee || pointee->isGetterMutating () || pointee->getType ()->hasError ())
323
329
return ;
324
330
325
331
// Check if present: `func successor() -> Self`
326
332
auto successorId = ctx.getIdentifier (" successor" );
327
- auto successors = lookupDirectWithoutExtensions (decl, successorId);
328
- if (successors.size () != 1 )
329
- return ;
330
- auto successor = dyn_cast<FuncDecl>(successors.front ());
333
+ auto successor =
334
+ lookupDirectSingleWithoutExtensions<FuncDecl>(decl, successorId);
331
335
if (!successor || successor->isMutating ())
332
336
return ;
333
337
auto successorTy = successor->getResultInterfaceType ();
@@ -398,20 +402,14 @@ void swift::conformToCxxSequenceIfNeeded(
398
402
399
403
// Check if present: `func __beginUnsafe() -> RawIterator`
400
404
auto beginId = ctx.getIdentifier (" __beginUnsafe" );
401
- auto begins = lookupDirectWithoutExtensions (decl, beginId);
402
- if (begins.size () != 1 )
403
- return ;
404
- auto begin = dyn_cast<FuncDecl>(begins.front ());
405
+ auto begin = lookupDirectSingleWithoutExtensions<FuncDecl>(decl, beginId);
405
406
if (!begin)
406
407
return ;
407
408
auto rawIteratorTy = begin->getResultInterfaceType ();
408
409
409
410
// Check if present: `func __endUnsafe() -> RawIterator`
410
411
auto endId = ctx.getIdentifier (" __endUnsafe" );
411
- auto ends = lookupDirectWithoutExtensions (decl, endId);
412
- if (ends.size () != 1 )
413
- return ;
414
- auto end = dyn_cast<FuncDecl>(ends.front ());
412
+ auto end = lookupDirectSingleWithoutExtensions<FuncDecl>(decl, endId);
415
413
if (!end)
416
414
return ;
417
415
@@ -524,6 +522,16 @@ void swift::conformToCxxSequenceIfNeeded(
524
522
}
525
523
}
526
524
525
+ static bool isStdDecl (const clang::CXXRecordDecl *clangDecl,
526
+ llvm::ArrayRef<StringRef> names) {
527
+ if (!clangDecl->isInStdNamespace ())
528
+ return false ;
529
+ if (!clangDecl->getIdentifier ())
530
+ return false ;
531
+ StringRef name = clangDecl->getName ();
532
+ return llvm::is_contained (names, name);
533
+ }
534
+
527
535
void swift::conformToCxxSetIfNeeded (ClangImporter::Implementation &impl,
528
536
NominalTypeDecl *decl,
529
537
const clang::CXXRecordDecl *clangDecl) {
@@ -535,29 +543,88 @@ void swift::conformToCxxSetIfNeeded(ClangImporter::Implementation &impl,
535
543
536
544
// Only auto-conform types from the C++ standard library. Custom user types
537
545
// might have a similar interface but different semantics.
538
- if (!clangDecl->isInStdNamespace ())
539
- return ;
540
- if (!clangDecl->getIdentifier ())
541
- return ;
542
- StringRef name = clangDecl->getName ();
543
- if (name != " set" && name != " unordered_set" && name != " multiset" )
544
- return ;
545
-
546
- auto valueTypeId = ctx.getIdentifier (" value_type" );
547
- auto valueTypes = lookupDirectWithoutExtensions (decl, valueTypeId);
548
- if (valueTypes.size () != 1 )
546
+ if (!isStdDecl (clangDecl, {" set" , " unordered_set" , " multiset" }))
549
547
return ;
550
- auto valueType = dyn_cast<TypeAliasDecl>(valueTypes.front ());
551
548
552
- auto sizeTypeId = ctx.getIdentifier (" size_type" );
553
- auto sizeTypes = lookupDirectWithoutExtensions (decl, sizeTypeId);
554
- if (sizeTypes.size () != 1 )
549
+ auto valueType = lookupDirectSingleWithoutExtensions<TypeAliasDecl>(
550
+ decl, ctx.getIdentifier (" value_type" ));
551
+ auto sizeType = lookupDirectSingleWithoutExtensions<TypeAliasDecl>(
552
+ decl, ctx.getIdentifier (" size_type" ));
553
+ if (!valueType || !sizeType)
555
554
return ;
556
- auto sizeType = dyn_cast<TypeAliasDecl>(sizeTypes.front ());
557
555
558
556
impl.addSynthesizedTypealias (decl, ctx.Id_Element ,
559
557
valueType->getUnderlyingType ());
560
558
impl.addSynthesizedTypealias (decl, ctx.getIdentifier (" Size" ),
561
559
sizeType->getUnderlyingType ());
562
560
impl.addSynthesizedProtocolAttrs (decl, {KnownProtocolKind::CxxSet});
563
561
}
562
+
563
+ void swift::conformToCxxPairIfNeeded (ClangImporter::Implementation &impl,
564
+ NominalTypeDecl *decl,
565
+ const clang::CXXRecordDecl *clangDecl) {
566
+ PrettyStackTraceDecl trace (" conforming to CxxPair" , decl);
567
+
568
+ assert (decl);
569
+ assert (clangDecl);
570
+ ASTContext &ctx = decl->getASTContext ();
571
+
572
+ // Only auto-conform types from the C++ standard library. Custom user types
573
+ // might have a similar interface but different semantics.
574
+ if (!isStdDecl (clangDecl, {" pair" }))
575
+ return ;
576
+
577
+ auto firstType = lookupDirectSingleWithoutExtensions<TypeAliasDecl>(
578
+ decl, ctx.getIdentifier (" first_type" ));
579
+ auto secondType = lookupDirectSingleWithoutExtensions<TypeAliasDecl>(
580
+ decl, ctx.getIdentifier (" second_type" ));
581
+ if (!firstType || !secondType)
582
+ return ;
583
+
584
+ impl.addSynthesizedTypealias (decl, ctx.getIdentifier (" First" ),
585
+ firstType->getUnderlyingType ());
586
+ impl.addSynthesizedTypealias (decl, ctx.getIdentifier (" Second" ),
587
+ secondType->getUnderlyingType ());
588
+ impl.addSynthesizedProtocolAttrs (decl, {KnownProtocolKind::CxxPair});
589
+ }
590
+
591
+ void swift::conformToCxxDictionaryIfNeeded (
592
+ ClangImporter::Implementation &impl, NominalTypeDecl *decl,
593
+ const clang::CXXRecordDecl *clangDecl) {
594
+ PrettyStackTraceDecl trace (" conforming to CxxDictionary" , decl);
595
+
596
+ assert (decl);
597
+ assert (clangDecl);
598
+ ASTContext &ctx = decl->getASTContext ();
599
+
600
+ // Only auto-conform types from the C++ standard library. Custom user types
601
+ // might have a similar interface but different semantics.
602
+ if (!isStdDecl (clangDecl, {" map" , " unordered_map" }))
603
+ return ;
604
+
605
+ auto keyType = lookupDirectSingleWithoutExtensions<TypeAliasDecl>(
606
+ decl, ctx.getIdentifier (" key_type" ));
607
+ auto valueType = lookupDirectSingleWithoutExtensions<TypeAliasDecl>(
608
+ decl, ctx.getIdentifier (" mapped_type" ));
609
+ auto iterType = lookupDirectSingleWithoutExtensions<TypeAliasDecl>(
610
+ decl, ctx.getIdentifier (" const_iterator" ));
611
+ if (!keyType || !valueType || !iterType)
612
+ return ;
613
+
614
+ // Make the original subscript that returns a non-optional value unavailable.
615
+ // CxxDictionary adds another subscript that returns an optional value,
616
+ // similarly to Swift.Dictionary.
617
+ for (auto member : decl->getCurrentMembersWithoutLoading ()) {
618
+ if (auto subscript = dyn_cast<SubscriptDecl>(member)) {
619
+ impl.markUnavailable (subscript,
620
+ " use subscript with optional return value" );
621
+ }
622
+ }
623
+
624
+ impl.addSynthesizedTypealias (decl, ctx.Id_Key , keyType->getUnderlyingType ());
625
+ impl.addSynthesizedTypealias (decl, ctx.Id_Value ,
626
+ valueType->getUnderlyingType ());
627
+ impl.addSynthesizedTypealias (decl, ctx.getIdentifier (" RawIterator" ),
628
+ iterType->getUnderlyingType ());
629
+ impl.addSynthesizedProtocolAttrs (decl, {KnownProtocolKind::CxxDictionary});
630
+ }
0 commit comments