diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index b123b06dfab56..229e13dc4b578 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -356,6 +356,9 @@ class ASTContext final { llvm::SmallPtrSet> DerivativeAttrs; + /// The Swift module currently being compiled. + ModuleDecl *MainModule = nullptr; + private: /// The current generation number, which reflects the number of /// times that external modules have been loaded. diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 5c35e98b4f91e..955678b28014d 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -630,7 +630,7 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated { HasAnyUnavailableValues : 1 ); - SWIFT_INLINE_BITFIELD(ModuleDecl, TypeDecl, 1+1+1+1+1+1+1+1+1+1+1+1+1+1, + SWIFT_INLINE_BITFIELD(ModuleDecl, TypeDecl, 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1, /// If the module is compiled as static library. StaticLibrary : 1, @@ -676,7 +676,11 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated { /// Whether this module has been compiled with comprehensive checking for /// concurrency, e.g., Sendable checking. - IsConcurrencyChecked : 1 + IsConcurrencyChecked : 1, + + /// If the map from @objc provided name to top level swift::Decl in this + /// module is populated + ObjCNameLookupCachePopulated : 1 ); SWIFT_INLINE_BITFIELD(PrecedenceGroupDecl, Decl, 1+2, diff --git a/include/swift/AST/DiagnosticsClangImporter.def b/include/swift/AST/DiagnosticsClangImporter.def index 4a65f97830ede..7a11d72cbec57 100644 --- a/include/swift/AST/DiagnosticsClangImporter.def +++ b/include/swift/AST/DiagnosticsClangImporter.def @@ -246,8 +246,27 @@ NOTE(invoked_func_not_imported, none, "function %0 unavailable (cannot import)", NOTE(record_method_not_imported, none, "method %0 unavailable (cannot import)", (const clang::NamedDecl*)) NOTE(objc_property_not_imported, none, "property %0 unavailable (cannot import)", (const clang::NamedDecl*)) -NOTE(forward_declared_interface_label, none, "interface %0 forward declared here", (const clang::NamedDecl*)) -NOTE(forward_declared_protocol_label, none, "protocol %0 forward declared here", (const clang::NamedDecl*)) +NOTE(placeholder_for_forward_declared_interface_member_access_failure, none, + "class '%0' will be imported as an opaque placeholder class and may be " + "missing members; import the definition to access the complete " + "interface", (StringRef)) +NOTE(placeholder_for_forward_declared_protocol_member_access_failure, none, + "protocol '%0' will be imported as an opaque placeholder protocol " + "and may be missing members; import the definition to access the " + "complete protocol", (StringRef)) +NOTE(forward_declared_interface_label, none, + "interface %0 forward declared here", (const clang::NamedDecl*)) +NOTE(forward_declared_protocol_label, none, + "protocol %0 forward declared here", (const clang::NamedDecl*)) + +NOTE(forward_declared_interface_clashes_with_imported_objc_Swift_interface, none, + "interface %0 is incomplete and cannot be imported as a stub; " + "its name conflicts with a %1 in module %2", + (const clang::NamedDecl*, StringRef, StringRef)) +NOTE(forward_declared_protocol_clashes_with_imported_objc_Swift_protocol, none, + "protocol %0 is incomplete and cannot be imported as a stub; " + "its name conflicts with a %1 in module %2", + (const clang::NamedDecl*, StringRef, StringRef)) #define UNDEFINE_DIAGNOSTIC_MACROS #include "DefineDiagnosticMacros.h" diff --git a/include/swift/AST/Module.h b/include/swift/AST/Module.h index b544852b576a7..6da0300947ff4 100644 --- a/include/swift/AST/Module.h +++ b/include/swift/AST/Module.h @@ -275,6 +275,8 @@ class ModuleDecl llvm::SmallDenseMap> declaredCrossImports; + llvm::DenseMap> ObjCNameLookupCache; + /// A description of what should be implicitly imported by each file of this /// module. const ImplicitImportInfo ImportInfo; @@ -667,6 +669,14 @@ class ModuleDecl Bits.ModuleDecl.IsConcurrencyChecked = value; } + bool isObjCNameLookupCachePopulated() const { + return Bits.ModuleDecl.ObjCNameLookupCachePopulated; + } + + void setIsObjCNameLookupCachePopulated(bool value) { + Bits.ModuleDecl.ObjCNameLookupCachePopulated = value; + } + /// For the main module, retrieves the list of primary source files being /// compiled, that is, the files we're generating code for. ArrayRef getPrimarySourceFiles() const; @@ -704,6 +714,24 @@ class ModuleDecl VisibleDeclConsumer &Consumer, NLKind LookupKind) const; +private: + void populateObjCNameLookupCache(); + +public: + /// Finds top-levels decls of this module by @objc provided name. + /// Decls that have no @objc attribute are not considered. + /// + /// This does a simple local lookup, not recursively looking through imports. + /// The order of the results is not guaranteed to be meaningful. + /// + /// \param Results Vector collecting the decls. + /// + /// \param name The @objc simple name to look for. Declarations with matching + /// name and "anonymous" @objc attribute, as well a matching named @objc + /// attribute will be added to Results. + void lookupTopLevelDeclsByObjCName(SmallVectorImpl &Results, + DeclName name); + /// This is a hack for 'main' file parsing and the integrated REPL. /// /// FIXME: Refactor main file parsing to not pump the parser incrementally. diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 0e942767a3867..d9cbecfc53fb2 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -308,6 +308,10 @@ def enable_experimental_eager_clang_module_diagnostics : Flag<["-"], "enable-experimental-eager-clang-module-diagnostics">, HelpText<"Enable experimental eager diagnostics reporting on the importability of all referenced C, C++, and Objective-C libraries">; +def enable_import_objc_forward_declarations : + Flag<["-"], "enable-import-objc-forward-declarations">, + HelpText<"Attempt to import Objective-C forward declarations">; + def enable_experimental_pairwise_build_block : Flag<["-"], "enable-experimental-pairwise-build-block">, HelpText<"Enable experimental pairwise 'buildBlock' for result builders">; diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp index c79465caafa7d..53f4db64cb665 100644 --- a/lib/AST/Module.cpp +++ b/lib/AST/Module.cpp @@ -597,6 +597,7 @@ ModuleDecl::ModuleDecl(Identifier name, ASTContext &ctx, Bits.ModuleDecl.HasIncrementalInfo = 0; Bits.ModuleDecl.HasHermeticSealAtLink = 0; Bits.ModuleDecl.IsConcurrencyChecked = 0; + Bits.ModuleDecl.ObjCNameLookupCachePopulated = 0; } ImplicitImportList ModuleDecl::getImplicitImports() const { @@ -1176,6 +1177,60 @@ void ModuleDecl::getTopLevelDeclsWhereAttributesMatch( FORWARD(getTopLevelDeclsWhereAttributesMatch, (Results, matchAttributes)); } +void ModuleDecl::lookupTopLevelDeclsByObjCName(SmallVectorImpl &Results, + DeclName name) { + if (!isObjCNameLookupCachePopulated()) + populateObjCNameLookupCache(); + + // A top level decl can't be special anyways + if (name.isSpecial()) + return; + + auto resultsForFileUnit = ObjCNameLookupCache.find(name.getBaseIdentifier()); + if (resultsForFileUnit == ObjCNameLookupCache.end()) + return; + + Results.append(resultsForFileUnit->second.begin(), + resultsForFileUnit->second.end()); +} + +void ModuleDecl::populateObjCNameLookupCache() { + SmallVector topLevelObjCExposedDeclsInFileUnit; + auto hasObjCAttrNamePredicate = [](const DeclAttributes &attrs) -> bool { + return attrs.hasAttribute(); + }; + + for (FileUnit *file : getFiles()) { + file->getTopLevelDeclsWhereAttributesMatch( + topLevelObjCExposedDeclsInFileUnit, hasObjCAttrNamePredicate); + if (auto *synth = file->getSynthesizedFile()) { + synth->getTopLevelDeclsWhereAttributesMatch( + topLevelObjCExposedDeclsInFileUnit, hasObjCAttrNamePredicate); + } + } + + for (Decl *decl : topLevelObjCExposedDeclsInFileUnit) { + if (ValueDecl *VD = dyn_cast(decl); VD && VD->hasName()) { + const auto &declObjCAttribute = VD->getAttrs().getAttribute(); + // No top level decl (class, protocol, extension etc.) is allowed to have a + // compound name, @objc provided or otherwise. Global functions are allowed to + // have compound names, but not allowed to have @objc attributes. Thus we + // are sure to not hit asserts getting the simple name. + // + // Similarly, init, dealloc and subscript (the special names) can't be top + // level decls, so we won't hit asserts getting the base identifier out of the + // value decl. + const Identifier &declObjCName = + declObjCAttribute->hasName() + ? declObjCAttribute->getName()->getSimpleName() + : VD->getName().getBaseIdentifier(); + ObjCNameLookupCache[declObjCName].push_back(decl); + } + } + + setIsObjCNameLookupCachePopulated(true); +} + void SourceFile::getTopLevelDecls(SmallVectorImpl &Results) const { auto decls = getTopLevelDecls(); Results.append(decls.begin(), decls.end()); @@ -3347,6 +3402,9 @@ bool SourceFile::shouldCrossImport() const { void ModuleDecl::clearLookupCache() { getASTContext().getImportCache().clear(); + setIsObjCNameLookupCachePopulated(false); + ObjCNameLookupCache.clear(); + if (!Cache) return; diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 4cff0fe032401..341676ab50875 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -6209,7 +6209,15 @@ void ClangImporter::diagnoseTopLevelValue(const DeclName &name) { void ClangImporter::diagnoseMemberValue(const DeclName &name, const Type &baseType) { - if (!baseType->getAnyNominal()) + + // Return early for any type that namelookup::extractDirectlyReferencedNominalTypes + // does not know how to handle. + if (!(baseType->getAnyNominal() || + baseType->is() || + baseType->is() || + baseType->is() || + baseType->is() || + baseType->is())) return; SmallVector nominalTypesToLookInto; @@ -6221,6 +6229,41 @@ void ClangImporter::diagnoseMemberValue(const DeclName &name, Impl.diagnoseMemberValue(name, cast(clangContainerDecl)); } + + if (Impl.ImportForwardDeclarations) { + const clang::Decl *clangContainerDecl = containerDecl->getClangDecl(); + if (const clang::ObjCInterfaceDecl *objCInterfaceDecl = + llvm::dyn_cast_or_null( + clangContainerDecl); objCInterfaceDecl && !objCInterfaceDecl->hasDefinition()) { + // Emit a diagnostic about how the base type represents a forward + // declared ObjC interface and is in all likelihood missing members. + // We only attach this diagnostic in diagnoseMemberValue rather than + // in SwiftDeclConverter because it is only relevant when the user + // tries to access an unavailable member. + Impl.addImportDiagnostic( + objCInterfaceDecl, + Diagnostic( + diag:: + placeholder_for_forward_declared_interface_member_access_failure, + objCInterfaceDecl->getName()), + objCInterfaceDecl->getSourceRange().getBegin()); + // Emit any diagnostics attached to the source Clang node (ie. forward + // declaration here note) + Impl.diagnoseTargetDirectly(clangContainerDecl); + } else if (const clang::ObjCProtocolDecl *objCProtocolDecl = + llvm::dyn_cast_or_null( + clangContainerDecl); objCProtocolDecl && !objCProtocolDecl->hasDefinition()) { + // Same as above but for protocols + Impl.addImportDiagnostic( + objCProtocolDecl, + Diagnostic( + diag:: + placeholder_for_forward_declared_protocol_member_access_failure, + objCProtocolDecl->getName()), + objCProtocolDecl->getSourceRange().getBegin()); + Impl.diagnoseTargetDirectly(clangContainerDecl); + } + } } } diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 329d21172ab9f..c5f136b7326d7 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -4288,7 +4288,9 @@ namespace { template T *resolveSwiftDeclImpl(const U *decl, Identifier name, - bool hasKnownSwiftName, ModuleDecl *overlay) { + bool hasKnownSwiftName, ModuleDecl *module, + bool allowObjCMismatchFallback, + bool cacheResult) { const auto &languageVersion = Impl.SwiftContext.LangOpts.EffectiveLanguageVersion; @@ -4320,7 +4322,7 @@ namespace { // First look at Swift types with the same name. SmallVector swiftDeclsByName; - overlay->lookupValue(name, NLKind::QualifiedLookup, swiftDeclsByName); + module->lookupValue(name, NLKind::QualifiedLookup, swiftDeclsByName); T *found = nullptr; for (auto result : swiftDeclsByName) { if (auto singleResult = dyn_cast(result)) { @@ -4342,14 +4344,7 @@ namespace { SmallVector matchingTopLevelDecls; // Get decls with a matching @objc attribute - overlay->getTopLevelDeclsWhereAttributesMatch( - matchingTopLevelDecls, - [&name](const DeclAttributes attrs) -> bool { - if (auto objcAttr = attrs.getAttribute()) - if (auto objcName = objcAttr->getName()) - return objcName->getSimpleName() == name; - return false; - }); + module->lookupTopLevelDeclsByObjCName(matchingTopLevelDecls, name); // Filter by decl kind for (auto result : matchingTopLevelDecls) { @@ -4361,7 +4356,7 @@ namespace { } } - if (!found) { + if (!found && allowObjCMismatchFallback) { // Go back to the first list and find classes with matching Swift names // *even if the ObjC name doesn't match.* // This shouldn't be allowed but we need it for source compatibility; @@ -4379,7 +4374,7 @@ namespace { } } - if (found) + if (found && cacheResult) Impl.ImportedDecls[{decl->getCanonicalDecl(), getActiveSwiftVersion()}] = found; @@ -4390,27 +4385,81 @@ namespace { T *resolveSwiftDecl(const U *decl, Identifier name, bool hasKnownSwiftName, ClangModuleUnit *clangModule) { if (auto overlay = clangModule->getOverlayModule()) - return resolveSwiftDeclImpl(decl, name, hasKnownSwiftName, overlay); + return resolveSwiftDeclImpl(decl, name, hasKnownSwiftName, overlay, + /*allowObjCMismatchFallback*/ true, /*cacheResult*/ true); if (clangModule == Impl.ImportedHeaderUnit) { // Use an index-based loop because new owners can come in as we're // iterating. for (size_t i = 0; i < Impl.ImportedHeaderOwners.size(); ++i) { ModuleDecl *owner = Impl.ImportedHeaderOwners[i]; - if (T *result = resolveSwiftDeclImpl(decl, name, - hasKnownSwiftName, owner)) + if (T *result = + resolveSwiftDeclImpl(decl, name, hasKnownSwiftName, owner, + /*allowObjCMismatchFallback*/ true, /*cacheResult*/ true)) return result; } } return nullptr; } + /// Given some forward declared Objective-C type `@class Foo` or `@protocol Bar`, this + /// method attempts to find a matching @objc annotated Swift declaration `@objc class Foo {}` + /// or `@objc protocol Bar {}`, in an imported Swift module. That is if the Clang node is in + /// a Clang module, the Swift overlay for that module does not count as "non-local". Similarly, + /// if the Clang node is in a bridging header, any owners of that header also do not count as + /// "non-local". This is intended to find @objc exposed Swift declarations in a different module + /// that share the name as the forward declaration. + /// + /// Pass \p hasKnownSwiftName when the Clang declaration is annotated with NS_SWIFT_NAME or similar, + /// such that the @objc provided name is known. + template + T* hasNonLocalNativeSwiftDecl(U *decl, Identifier name, bool hasKnownSwiftName) { + assert(!decl->hasDefinition() && "This method is only intended to be used on incomplete Clang types"); + + // We intentionally do not consider if the declaration has a clang::ExternalSourceSymbolAttr + // attribute, since we can't know if the corresponding Swift definition is "local" (ie. + // in the overlay or bridging header owner) or not. + + // Check first if the Swift definition is "local" + auto owningClangModule = Impl.getClangModuleForDecl(decl, /*allowForwardDeclaration*/ true); + if (owningClangModule && resolveSwiftDecl(decl, name, hasKnownSwiftName, owningClangModule)) + return nullptr; + + // If not, check all imported Swift modules for a definition + if (auto mainModule = Impl.SwiftContext.MainModule) { + llvm::SmallVector results; + llvm::SmallVector importedModules; + + ModuleDecl::ImportFilter moduleImportFilter = ModuleDecl::ImportFilterKind::Default; + moduleImportFilter |= ModuleDecl::ImportFilterKind::Exported; + moduleImportFilter |= ModuleDecl::ImportFilterKind::ImplementationOnly; + moduleImportFilter |= ModuleDecl::ImportFilterKind::PackageOnly; + moduleImportFilter |= ModuleDecl::ImportFilterKind::SPIOnly; + moduleImportFilter |= ModuleDecl::ImportFilterKind::ShadowedByCrossImportOverlay; + + mainModule->getImportedModules(importedModules, moduleImportFilter); + + for (auto &import : importedModules) { + if (import.importedModule->isNonSwiftModule()) + continue; + + if (T *result = resolveSwiftDeclImpl( + decl, name, hasKnownSwiftName, import.importedModule, + /*allowObjCMismatchFallback*/ false, /*cacheResult*/ false)) + return result; + } + } + + return nullptr; + } + template bool hasNativeSwiftDecl(const U *decl, Identifier name, - const DeclContext *dc, T *&swiftDecl) { + const DeclContext *dc, T *&swiftDecl, + bool hasKnownSwiftName = true) { if (!importer::hasNativeSwiftDecl(decl)) return false; auto wrapperUnit = cast(dc->getModuleScopeContext()); - swiftDecl = resolveSwiftDecl(decl, name, /*hasCustomSwiftName=*/true, + swiftDecl = resolveSwiftDecl(decl, name, hasKnownSwiftName, wrapperUnit); return true; } @@ -4443,8 +4492,6 @@ namespace { Identifier name = importedName.getDeclName().getBaseIdentifier(); bool hasKnownSwiftName = importedName.hasCustomName(); - // FIXME: Figure out how to deal with incomplete protocols, since that - // notion doesn't exist in Swift. if (!decl->hasDefinition()) { // Check if this protocol is implemented in its overlay. if (auto clangModule = Impl.getClangModuleForDecl(decl, true)) @@ -4457,6 +4504,39 @@ namespace { decl, Diagnostic(diag::forward_declared_protocol_label, decl), decl->getSourceRange().getBegin()); + if (Impl.ImportForwardDeclarations) { + if (auto native = hasNonLocalNativeSwiftDecl(decl, name, hasKnownSwiftName)) { + const ModuleDecl* moduleForNativeDecl = native->getParentModule(); + assert(moduleForNativeDecl); + Impl.addImportDiagnostic(decl, Diagnostic(diag::forward_declared_protocol_clashes_with_imported_objc_Swift_protocol, + decl, Decl::getDescriptiveKindName(native->getDescriptiveKind()), moduleForNativeDecl->getNameStr()), + decl->getSourceRange().getBegin()); + } else { + auto result = Impl.createDeclWithClangNode( + decl, AccessLevel::Public, + Impl.getClangModuleForDecl(decl->getCanonicalDecl(), + /*allowForwardDeclaration=*/true), + Impl.importSourceLoc(decl->getBeginLoc()), + Impl.importSourceLoc(decl->getLocation()), name, + ArrayRef(), None, + /*TrailingWhere=*/nullptr); + + Impl.ImportedDecls[{decl->getCanonicalDecl(), getVersion()}] = result; + result->setAddedImplicitInitializers(); // suppress all initializers + addObjCAttribute(result, + Impl.importIdentifier(decl->getIdentifier())); + result->setImplicit(); + auto attr = AvailableAttr::createPlatformAgnostic( + Impl.SwiftContext, + "This Objective-C protocol has only been forward-declared; " + "import its owning module to use it"); + result->getAttrs().add(attr); + result->getAttrs().add(new (Impl.SwiftContext) + ForbidSerializingReferenceAttr(true)); + return result; + } + } + forwardDeclaration = true; return nullptr; } @@ -4510,7 +4590,9 @@ namespace { } Decl *VisitObjCInterfaceDecl(const clang::ObjCInterfaceDecl *decl) { - auto createFakeRootClass = [=](Identifier name, + + auto createFakeClass = [=](Identifier name, bool cacheResult, + bool inheritFromNSObject, DeclContext *dc = nullptr) -> ClassDecl * { if (!dc) { dc = Impl.getClangModuleForDecl(decl->getCanonicalDecl(), @@ -4523,8 +4605,14 @@ namespace { SourceLoc(), None, nullptr, dc, /*isActor*/false); - Impl.ImportedDecls[{decl->getCanonicalDecl(), getVersion()}] = result; - result->setSuperclass(Type()); + if (cacheResult) + Impl.ImportedDecls[{decl->getCanonicalDecl(), getVersion()}] = result; + + if (inheritFromNSObject) + result->setSuperclass(Impl.getNSObjectType()); + else + result->setSuperclass(Type()); + result->setAddedImplicitInitializers(); // suppress all initializers result->setHasMissingVTableEntries(false); addObjCAttribute(result, Impl.importIdentifier(decl->getIdentifier())); @@ -4544,8 +4632,10 @@ namespace { const ClassDecl *nsObjectDecl = nsObjectTy->getClassOrBoundGenericClass(); - auto result = createFakeRootClass(Impl.SwiftContext.Id_Protocol, - nsObjectDecl->getDeclContext()); + auto result = createFakeClass(Impl.SwiftContext.Id_Protocol, + /* cacheResult */ false, + /* inheritFromNSObject */ false, + nsObjectDecl->getDeclContext()); result->setForeignClassKind(ClassDecl::ForeignKind::RuntimeOnly); return result; } @@ -4577,21 +4667,30 @@ namespace { } } + Impl.addImportDiagnostic( + decl, Diagnostic(diag::forward_declared_interface_label, decl), + decl->getSourceRange().getBegin()); + if (Impl.ImportForwardDeclarations) { - // Fake it by making an unavailable opaque @objc root class. - auto result = createFakeRootClass(name); - result->setImplicit(); - auto attr = AvailableAttr::createPlatformAgnostic(Impl.SwiftContext, - "This Objective-C class has only been forward-declared; " - "import its owning module to use it"); - result->getAttrs().add(attr); - result->getAttrs().add( - new (Impl.SwiftContext) ForbidSerializingReferenceAttr(true)); - return result; - } else { - Impl.addImportDiagnostic( - decl, Diagnostic(diag::forward_declared_interface_label, decl), - decl->getSourceRange().getBegin()); + if (auto native = hasNonLocalNativeSwiftDecl(decl, name, hasKnownSwiftName)) { + const ModuleDecl* moduleForNativeDecl = native->getParentModule(); + assert(moduleForNativeDecl); + Impl.addImportDiagnostic(decl, Diagnostic(diag::forward_declared_interface_clashes_with_imported_objc_Swift_interface, + decl, Decl::getDescriptiveKindName(native->getDescriptiveKind()), moduleForNativeDecl->getNameStr()), + decl->getSourceRange().getBegin()); + } else { + // Fake it by making an unavailable opaque @objc root class. + auto result = createFakeClass(name, /* cacheResult */ true, + /* inheritFromNSObject */ true); + result->setImplicit(); + auto attr = AvailableAttr::createPlatformAgnostic(Impl.SwiftContext, + "This Objective-C class has only been forward-declared; " + "import its owning module to use it"); + result->getAttrs().add(attr); + result->getAttrs().add( + new (Impl.SwiftContext) ForbidSerializingReferenceAttr(true)); + return result; + } } forwardDeclaration = true; diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 0e29265589355..049ee1038b08d 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -1247,7 +1247,9 @@ static bool ValidateModulesOnceOptions(const ClangImporterOptions &Opts, static bool ParseClangImporterArgs(ClangImporterOptions &Opts, ArgList &Args, DiagnosticEngine &Diags, - StringRef workingDirectory) { + StringRef workingDirectory, + const LangOptions &LangOpts, + const FrontendOptions &FrontendOpts) { using namespace options; if (const Arg *a = Args.getLastArg(OPT_tools_directory)) { @@ -1315,6 +1317,15 @@ static bool ParseClangImporterArgs(ClangImporterOptions &Opts, Opts.DumpClangDiagnostics |= Args.hasArg(OPT_dump_clang_diagnostics); + // When the repl is invoked directly (ie. `lldb --repl="..."`) the action + // type seems to be NoneAction. + if (FrontendOpts.RequestedAction != FrontendOptions::ActionType::REPL && + FrontendOpts.RequestedAction != FrontendOptions::ActionType::NoneAction && + (Args.hasArg(OPT_enable_import_objc_forward_declarations) || + LangOpts.isSwiftVersionAtLeast(6))) { + Opts.ImportForwardDeclarations = true; + } + if (Args.hasArg(OPT_embed_bitcode)) Opts.Mode = ClangImporterOptions::Modes::EmbedBitcode; else if (Args.hasArg(OPT_emit_pcm) || Args.hasArg(OPT_dump_pcm)) @@ -2714,7 +2725,7 @@ bool CompilerInvocation::parseArgs( } if (ParseClangImporterArgs(ClangImporterOpts, ParsedArgs, Diags, - workingDirectory)) { + workingDirectory, LangOpts, FrontendOpts)) { return true; } diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index 459546c2b4250..370f88b7d3527 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -1145,6 +1145,7 @@ ModuleDecl *CompilerInstance::getMainModule() const { // Register the main module with the AST context. Context->addLoadedModule(MainModule); + Context->MainModule = MainModule; // Create and add the module's files. SmallVector files; @@ -1167,6 +1168,7 @@ void CompilerInstance::setMainModule(ModuleDecl *newMod) { assert(newMod->isMainModule()); MainModule = newMod; Context->addLoadedModule(newMod); + Context->MainModule = newMod; } bool CompilerInstance::performParseAndResolveImportsOnly() { diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index b5f0719d4c59a..68552e48feac8 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -623,10 +623,6 @@ DeclID Serializer::addDeclRef(const Decl *D, bool allowTypeAliasXRef) { isa(D)) && "cannot cross-reference this decl"); - assert((!D || !isDeclXRef(D) || - !D->getAttrs().hasAttribute()) && - "cannot cross-reference this decl"); - assert((!D || allowTypeAliasXRef || !isa(D) || D->getModuleContext() == M) && "cannot cross-reference typealiases directly (use the TypeAliasType)"); diff --git a/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/complete-swift-types.swift b/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/complete-swift-types.swift new file mode 100644 index 0000000000000..a738d018c9779 --- /dev/null +++ b/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/complete-swift-types.swift @@ -0,0 +1,38 @@ +import Foundation + +@objc public class Foo : NSObject { + @objc public func sayHello() { + print("Hello from Foo.sayHello!") + } +} + +@objc(Baz) public class Bar : NSObject { + @objc public func sayHello() { + print("Hello from Bar.sayHello!") + } +} + +class ConflictingTypeName {} + +@objc(ConflictingTypeName) public class Qux : NSObject { + @objc public func sayHello() { + print("Hello from Qux.sayHello!") + } +} + +// Created to verify if using a special +// name as an @objc identifier causes issues +@objc(subscript) public class Corge : NSObject { + @objc public func sayHello() { + print("Hello from Corge.sayHello!") + } +} + +@objc protocol ShadowedProtocol {} + +@objc public protocol ProtocolFoo {} +@objc(ProtocolBaz) public protocol Bam {} +protocol ProtocolConflictingTypeName {} +@objc(ProtocolConflictingTypeName) public protocol Quux { } + +@objc public class ProtocolConformer : NSObject, ProtocolFoo, Quux, ProtocolConflictingTypeName {} diff --git a/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/complete-types.h b/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/complete-types.h new file mode 100644 index 0000000000000..7e2c494b673f5 --- /dev/null +++ b/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/complete-types.h @@ -0,0 +1,13 @@ +#import + +@interface ForwardDeclaredInterface : NSObject +- (id)init; +- (void)doSomethingForwardDeclaredInterfacesCan; +@end + +@protocol ForwardDeclaredProtocol +- (void)doSomethingForwardDeclaredProtocolsCan; +@end + +void takeACompleteInterface(ForwardDeclaredInterface *param); +void takeACompleteProtocol(NSObject *param); diff --git a/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/complete-types.m b/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/complete-types.m new file mode 100644 index 0000000000000..1fefda2370731 --- /dev/null +++ b/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/complete-types.m @@ -0,0 +1,19 @@ +#import "complete-types.h" + +@implementation ForwardDeclaredInterface +- (id)init { + return [super init]; +} +- (void)doSomethingForwardDeclaredInterfacesCan { + NSLog(@"Doing something forward declared interfaces can!"); +} +@end + +void takeACompleteInterface(ForwardDeclaredInterface *param) { + NSLog(@"takeACompleteInterface"); + [param doSomethingForwardDeclaredInterfacesCan]; +} +void takeACompleteProtocol(NSObject *param) { + NSLog(@"takeACompleteProcotol"); + [param doSomethingForwardDeclaredProtocolsCan]; +} diff --git a/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/incomplete-noroottype-protocol-library.h b/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/incomplete-noroottype-protocol-library.h new file mode 100644 index 0000000000000..72c6986c2865e --- /dev/null +++ b/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/incomplete-noroottype-protocol-library.h @@ -0,0 +1,16 @@ +#import + +@protocol NoRootTypeProtocol; + +@interface NoRootTypeProtocolConsumer : NSObject +@property(strong) id + propertyUsingAForwardDeclaredNoRootTypeProtocol; +- (id)init; +- (id)methodReturningForwardDeclaredNoRootTypeProtocol; +- (void)methodTakingAForwardDeclaredNoRootTypeProtocol: + (id)param; +@end + +id CFunctionReturningAForwardDeclaredNoRootTypeProtocol(); +void CFunctionTakingAForwardDeclaredNoRootTypeProtocol( + id param); diff --git a/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/incomplete-noroottype-protocol-library.m b/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/incomplete-noroottype-protocol-library.m new file mode 100644 index 0000000000000..6a811d1d2af9f --- /dev/null +++ b/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/incomplete-noroottype-protocol-library.m @@ -0,0 +1,52 @@ +#import "incomplete-noroottype-protocol-library.h" + +@protocol NoRootTypeProtocol +- (void)sayHello; +@end + +@interface NoRootTypeProtocolConformingType : NSObject +- (void)sayHello; +@end + +@implementation NoRootTypeProtocolConformingType +- (void)sayHello { + NSLog(@"Hello from NoRootTypeProtocolConformingType!"); +} +@end + +@implementation NoRootTypeProtocolConsumer +- (id)init { + self = [super init]; + if (self) { + self.propertyUsingAForwardDeclaredNoRootTypeProtocol = + [[NoRootTypeProtocolConformingType alloc] init]; + } + return self; +} +- (id)methodReturningForwardDeclaredNoRootTypeProtocol { + NSLog(@"methodReturningForwardDeclaredNoRootTypeProtocol"); + NoRootTypeProtocolConformingType *result = + [[NoRootTypeProtocolConformingType alloc] init]; + [result sayHello]; + return result; +} +- (void)methodTakingAForwardDeclaredNoRootTypeProtocol: + (id)param { + NSLog(@"methodTakingAForwardDeclaredNoRootTypeProtocol"); + [param sayHello]; +} +@end + +id CFunctionReturningAForwardDeclaredNoRootTypeProtocol() { + NSLog(@"CFunctionReturningAForwardDeclaredNoRootTypeProtocol"); + NoRootTypeProtocolConformingType *result = + [[NoRootTypeProtocolConformingType alloc] init]; + [result sayHello]; + return result; +} + +void CFunctionTakingAForwardDeclaredNoRootTypeProtocol( + id param) { + NSLog(@"CFunctionTakingAForwardDeclaredNoRootTypeProtocol"); + [param sayHello]; +} diff --git a/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/incomplete-nsproxy-library.h b/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/incomplete-nsproxy-library.h new file mode 100644 index 0000000000000..1bf49830ac74f --- /dev/null +++ b/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/incomplete-nsproxy-library.h @@ -0,0 +1,18 @@ +#import + +@class ForwardDeclaredNSProxyInterface; + +@interface NSProxyConsumer : NSObject +@property ForwardDeclaredNSProxyInterface + *propertyUsingAForwardDeclaredNSProxyInterface; +- (id)init; +- (ForwardDeclaredNSProxyInterface *) + methodReturningForwardDeclaredNSProxyInterface; +- (void)methodTakingAForwardDeclaredNSProxyInterface: + (ForwardDeclaredNSProxyInterface *)param; +@end + +ForwardDeclaredNSProxyInterface * +CFunctionReturningAForwardDeclaredNSProxyInterface(); +void CFunctionTakingAForwardDeclaredNSProxyInterface( + ForwardDeclaredNSProxyInterface *param); diff --git a/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/incomplete-nsproxy-library.m b/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/incomplete-nsproxy-library.m new file mode 100644 index 0000000000000..d19a2baa02232 --- /dev/null +++ b/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/incomplete-nsproxy-library.m @@ -0,0 +1,46 @@ +#import "incomplete-nsproxy-library.h" + +@interface ForwardDeclaredNSProxyInterface : NSProxy +- (id)init; +- (void)doSomethingForwardDeclaredNSProxyInterfacesCan; +@end + +@implementation ForwardDeclaredNSProxyInterface +- (id)init { + return self; +} +- (void)doSomethingForwardDeclaredNSProxyInterfacesCan { + NSLog(@"Doing something forward declared NSProxy can version!"); +} +@end + +@implementation NSProxyConsumer +- (id)init { + self = [super init]; + if (self) { + self.propertyUsingAForwardDeclaredNSProxyInterface = + [[ForwardDeclaredNSProxyInterface alloc] init]; + } + return self; +} +- (ForwardDeclaredNSProxyInterface *) + methodReturningForwardDeclaredNSProxyInterface { + NSLog(@"methodReturningForwardDeclaredNSProxyInterface"); + return [[ForwardDeclaredNSProxyInterface alloc] init]; +} +- (void)methodTakingAForwardDeclaredNSProxyInterface: + (ForwardDeclaredNSProxyInterface *)param { + [param doSomethingForwardDeclaredNSProxyInterfacesCan]; +} +@end + +ForwardDeclaredNSProxyInterface * +CFunctionReturningAForwardDeclaredNSProxyInterface() { + NSLog(@"CFunctionReturningAForwardDeclaredNSProxyInterface"); + return [[ForwardDeclaredNSProxyInterface alloc] init]; +} +void CFunctionTakingAForwardDeclaredNSProxyInterface( + ForwardDeclaredNSProxyInterface *param) { + NSLog(@"CFunctionTakingAForwardDeclaredNSProxyInterface"); + [param doSomethingForwardDeclaredNSProxyInterfacesCan]; +} diff --git a/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/incomplete-type-library-1.h b/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/incomplete-type-library-1.h new file mode 100644 index 0000000000000..947b62e9e37f6 --- /dev/null +++ b/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/incomplete-type-library-1.h @@ -0,0 +1,24 @@ +#import + +@class ForwardDeclaredInterface; +@protocol ForwardDeclaredProtocol; + +@interface IncompleteTypeConsumer1 : NSObject +@property id propertyUsingAForwardDeclaredProtocol1; +@property ForwardDeclaredInterface *propertyUsingAForwardDeclaredInterface1; +- (id)init; +- (NSObject *)methodReturningForwardDeclaredProtocol1; +- (ForwardDeclaredInterface *)methodReturningForwardDeclaredInterface1; +- (void)methodTakingAForwardDeclaredProtocol1: + (id)param; +- (void)methodTakingAForwardDeclaredInterface1: + (ForwardDeclaredInterface *)param; +@end + +ForwardDeclaredInterface *CFunctionReturningAForwardDeclaredInterface1(); +void CFunctionTakingAForwardDeclaredInterface1(ForwardDeclaredInterface *param); + +NSObject * +CFunctionReturningAForwardDeclaredProtocol1(); +void CFunctionTakingAForwardDeclaredProtocol1( + id param); diff --git a/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/incomplete-type-library-1.m b/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/incomplete-type-library-1.m new file mode 100644 index 0000000000000..ad981b1076dcd --- /dev/null +++ b/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/incomplete-type-library-1.m @@ -0,0 +1,69 @@ +#import "incomplete-type-library-1.h" +#import "complete-types.h" + +@interface TypeConformingToForwardDeclaredProtocol1 + : NSObject +- (id)init; +- (void)doSomethingForwardDeclaredProtocolsCan; +@end + +@implementation TypeConformingToForwardDeclaredProtocol1 +- (id)init { + return [super init]; +} +- (void)doSomethingForwardDeclaredProtocolsCan { + NSLog(@"Doing something forward declared protocols can version 1!"); +} +@end + +@implementation IncompleteTypeConsumer1 +- (id)init { + self = [super init]; + if (self) { + self.propertyUsingAForwardDeclaredInterface1 = + [[ForwardDeclaredInterface alloc] init]; + self.propertyUsingAForwardDeclaredProtocol1 = + [[TypeConformingToForwardDeclaredProtocol1 alloc] init]; + } + return self; +} +- (NSObject *)methodReturningForwardDeclaredProtocol1 { + NSLog(@"methodReturningForwardDeclaredProtocol1"); + return [[TypeConformingToForwardDeclaredProtocol1 alloc] init]; +} +- (ForwardDeclaredInterface *)methodReturningForwardDeclaredInterface1 { + NSLog(@"methodReturningForwardDeclaredInterface1"); + return [[ForwardDeclaredInterface alloc] init]; +} +- (void)methodTakingAForwardDeclaredProtocol1: + (id)param { + NSLog(@"methodTakingAForwardDeclaredProtocol1"); + [param doSomethingForwardDeclaredProtocolsCan]; +} +- (void)methodTakingAForwardDeclaredInterface1: + (ForwardDeclaredInterface *)param { + NSLog(@"methodTakingAForwardDeclaredInterface1"); + [param doSomethingForwardDeclaredInterfacesCan]; +} +@end + +ForwardDeclaredInterface *CFunctionReturningAForwardDeclaredInterface1() { + NSLog(@"CFunctionReturningAForwardDeclaredInterface1"); + return [[ForwardDeclaredInterface alloc] init]; +} +void CFunctionTakingAForwardDeclaredInterface1( + ForwardDeclaredInterface *param) { + NSLog(@"CFunctionTakingAForwardDeclaredInterface1"); + [param doSomethingForwardDeclaredInterfacesCan]; +} + +NSObject * +CFunctionReturningAForwardDeclaredProtocol1() { + NSLog(@"CFunctionReturningAForwardDeclaredProtocol1"); + return [[TypeConformingToForwardDeclaredProtocol1 alloc] init]; +} +void CFunctionTakingAForwardDeclaredProtocol1( + id param) { + NSLog(@"CFunctionTakingAForwardDeclaredProtocol1"); + [param doSomethingForwardDeclaredProtocolsCan]; +} diff --git a/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/incomplete-type-library-2.h b/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/incomplete-type-library-2.h new file mode 100644 index 0000000000000..7eb9c87139a1c --- /dev/null +++ b/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/incomplete-type-library-2.h @@ -0,0 +1,24 @@ +#import + +@class ForwardDeclaredInterface; +@protocol ForwardDeclaredProtocol; + +@interface IncompleteTypeConsumer2 : NSObject +@property id propertyUsingAForwardDeclaredProtocol2; +@property ForwardDeclaredInterface *propertyUsingAForwardDeclaredInterface2; +- (id)init; +- (NSObject *)methodReturningForwardDeclaredProtocol2; +- (ForwardDeclaredInterface *)methodReturningForwardDeclaredInterface2; +- (void)methodTakingAForwardDeclaredProtocol2: + (id)param; +- (void)methodTakingAForwardDeclaredInterface2: + (ForwardDeclaredInterface *)param; +@end + +ForwardDeclaredInterface *CFunctionReturningAForwardDeclaredInterface2(); +void CFunctionTakingAForwardDeclaredInterface2(ForwardDeclaredInterface *param); + +NSObject * +CFunctionReturningAForwardDeclaredProtocol2(); +void CFunctionTakingAForwardDeclaredProtocol2( + id param); diff --git a/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/incomplete-type-library-2.m b/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/incomplete-type-library-2.m new file mode 100644 index 0000000000000..db4b85cfbac04 --- /dev/null +++ b/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/incomplete-type-library-2.m @@ -0,0 +1,69 @@ +#import "incomplete-type-library-2.h" +#import "complete-types.h" + +@interface TypeConformingToForwardDeclaredProtocol2 + : NSObject +- (id)init; +- (void)doSomethingForwardDeclaredProtocolsCan; +@end + +@implementation TypeConformingToForwardDeclaredProtocol2 +- (id)init { + return [super init]; +} +- (void)doSomethingForwardDeclaredProtocolsCan { + NSLog(@"Doing something forward declared protocols can version 2!"); +} +@end + +@implementation IncompleteTypeConsumer2 +- (id)init { + self = [super init]; + if (self) { + self.propertyUsingAForwardDeclaredInterface2 = + [[ForwardDeclaredInterface alloc] init]; + self.propertyUsingAForwardDeclaredProtocol2 = + [[TypeConformingToForwardDeclaredProtocol2 alloc] init]; + } + return self; +} +- (NSObject *)methodReturningForwardDeclaredProtocol2 { + NSLog(@"methodReturningForwardDeclaredProtocol2"); + return [[TypeConformingToForwardDeclaredProtocol2 alloc] init]; +} +- (ForwardDeclaredInterface *)methodReturningForwardDeclaredInterface2 { + NSLog(@"methodReturningForwardDeclaredInterface2"); + return [[ForwardDeclaredInterface alloc] init]; +} +- (void)methodTakingAForwardDeclaredProtocol2: + (id)param { + NSLog(@"methodTakingAForwardDeclaredProtocol2"); + [param doSomethingForwardDeclaredProtocolsCan]; +} +- (void)methodTakingAForwardDeclaredInterface2: + (ForwardDeclaredInterface *)param { + NSLog(@"methodTakingAForwardDeclaredInterface2"); + [param doSomethingForwardDeclaredInterfacesCan]; +} +@end + +ForwardDeclaredInterface *CFunctionReturningAForwardDeclaredInterface2() { + NSLog(@"CFunctionReturningAForwardDeclaredInterface2"); + return [[ForwardDeclaredInterface alloc] init]; +} +void CFunctionTakingAForwardDeclaredInterface2( + ForwardDeclaredInterface *param) { + NSLog(@"CFunctionTakingAForwardDeclaredInterface2"); + [param doSomethingForwardDeclaredInterfacesCan]; +} + +NSObject * +CFunctionReturningAForwardDeclaredProtocol2() { + NSLog(@"CFunctionReturningAForwardDeclaredProtocol2"); + return [[TypeConformingToForwardDeclaredProtocol2 alloc] init]; +} +void CFunctionTakingAForwardDeclaredProtocol2( + id param) { + NSLog(@"CFunctionTakingAForwardDeclaredProtocol2"); + [param doSomethingForwardDeclaredProtocolsCan]; +} diff --git a/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/module.modulemap b/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/module.modulemap new file mode 100644 index 0000000000000..5b6aba37ed7cb --- /dev/null +++ b/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/module.modulemap @@ -0,0 +1,23 @@ +module CompleteTypes { + header "complete-types.h" +} + +module IncompleteTypeLibrary1 { + header "incomplete-type-library-1.h" +} + +module IncompleteTypeLibrary2 { + header "incomplete-type-library-2.h" +} + +module IncompleteNSProxyLibrary { + header "incomplete-nsproxy-library.h" +} + +module IncompleteNoRootTypeProtocolLibrary { + header "incomplete-noroottype-protocol-library.h" +} + +module ObjCLibraryForwardDeclaringCompleteSwiftTypes { + header "objc-library-forward-declaring-complete-swift-types.h" +} diff --git a/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/objc-library-forward-declaring-complete-swift-types.h b/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/objc-library-forward-declaring-complete-swift-types.h new file mode 100644 index 0000000000000..9f3e440b15bf9 --- /dev/null +++ b/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/objc-library-forward-declaring-complete-swift-types.h @@ -0,0 +1,30 @@ +@class Foo; +@class Baz; +@class ConflictingTypeName; +@class subscript; +@class ShadowedProtocol; + +void takeAFoo(Foo *foo); +Foo *returnAFoo(); + +void takeABaz(Baz *baz); +Baz *returnABaz(); + +void takeAConflictingTypeName(ConflictingTypeName *param); +ConflictingTypeName *returnAConflictingTypeName(); + +void takeASubscript(subscript *param); +subscript* returnASubscript(); + +// There is a Swift protocol, @objc protocol ShadowedProtocol, but +// since here we are refering to a class and not a protocol, this +// shouldn't be an issue. +ShadowedProtocol* returnANativeObjCClassShadowedProtocol(); + +@protocol ProtocolFoo; +@protocol ProtocolBaz; +@protocol ProtocolConflictingTypeName; + +id returnAProtocolFoo(); +id returnAProtocolBaz(); +id returnAProtocolConflictingTypeName(); diff --git a/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/objc-library-forward-declaring-complete-swift-types.m b/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/objc-library-forward-declaring-complete-swift-types.m new file mode 100644 index 0000000000000..f128773fe91dc --- /dev/null +++ b/test/ClangImporter/Inputs/custom-modules/IncompleteTypes/objc-library-forward-declaring-complete-swift-types.m @@ -0,0 +1,56 @@ +#import "objc-library-forward-declaring-complete-swift-types.h" +#import "CompleteSwiftTypes-Swift.h" + +void takeAFoo(Foo *foo) { [foo sayHello]; } + +Foo *returnAFoo() { + Foo *result = [[Foo alloc] init]; + [result sayHello]; + return result; +} + +void takeABaz(Baz *baz) { [baz sayHello]; } + +Baz *returnABaz() { + Baz *result = [[Baz alloc] init]; + [result sayHello]; + return result; +} + +void takeAConflictingTypeName(ConflictingTypeName *param) { [param sayHello]; } + +ConflictingTypeName *returnAConflictingTypeName() { + ConflictingTypeName *result = [[ConflictingTypeName alloc] init]; + [result sayHello]; + return result; +} + +void takeASubscript(subscript *baz) { [baz sayHello]; } + +subscript *returnASubscript() { + subscript *result = [[subscript alloc] init]; + [result sayHello]; + return result; +} + +@interface ShadowedProtocol : NSObject +@end + +@implementation ShadowedProtocol +@end + +ShadowedProtocol* returnANativeObjCClassShadowedProtocol() { + return [[ShadowedProtocol alloc] init]; +} + +id returnAProtocolFoo() { + return [[ProtocolConformer alloc] init]; +} + +id returnAProtocolBaz() { + return [[ProtocolConformer alloc] init]; +} + +id returnAProtocolConflictingTypeName() { + return [[ProtocolConformer alloc] init]; +} diff --git a/test/ClangImporter/experimental_clang_importer_diagnostics_bridging_header.swift b/test/ClangImporter/experimental_clang_importer_diagnostics_bridging_header.swift index 4435fee175286..e213787072bf1 100644 --- a/test/ClangImporter/experimental_clang_importer_diagnostics_bridging_header.swift +++ b/test/ClangImporter/experimental_clang_importer_diagnostics_bridging_header.swift @@ -1,4 +1,4 @@ -// RUN: not %target-swift-frontend -enable-objc-interop -import-objc-header %S/Inputs/experimental_clang_importer_diagnostics_bridging_header.h -typecheck %s 2>&1 | %FileCheck %s +// RUN: not %target-swift-frontend -enable-objc-interop -swift-version 5 -import-objc-header %S/Inputs/experimental_clang_importer_diagnostics_bridging_header.h -typecheck %s 2>&1 | %FileCheck %s let s: PartialImport s.c = 5 diff --git a/test/ClangImporter/experimental_diagnostics_incomplete_types.swift b/test/ClangImporter/experimental_diagnostics_incomplete_types.swift index 37fc8d3b89ddd..7aee643d66d30 100644 --- a/test/ClangImporter/experimental_diagnostics_incomplete_types.swift +++ b/test/ClangImporter/experimental_diagnostics_incomplete_types.swift @@ -1,4 +1,4 @@ -// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -enable-objc-interop -typecheck %s 2>&1 | %FileCheck %s --strict-whitespace +// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -swift-version 5 -enable-objc-interop -typecheck %s 2>&1 | %FileCheck %s --strict-whitespace // REQUIRES: objc_interop diff --git a/test/ClangImporter/experimental_diagnostics_incomplete_types_negative.swift b/test/ClangImporter/experimental_diagnostics_incomplete_types_negative.swift index 9bc9f27e1dda5..a351f4856ad82 100644 --- a/test/ClangImporter/experimental_diagnostics_incomplete_types_negative.swift +++ b/test/ClangImporter/experimental_diagnostics_incomplete_types_negative.swift @@ -1,4 +1,4 @@ -// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -enable-objc-interop -typecheck %s 2>&1 | %FileCheck %s --strict-whitespace +// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -swift-version 5 -enable-objc-interop -typecheck %s 2>&1 | %FileCheck %s --strict-whitespace // REQUIRES: objc_interop diff --git a/test/ClangImporter/experimental_diagnostics_no_noise.swift b/test/ClangImporter/experimental_diagnostics_no_noise.swift index 16ab5a4e584e5..19baedc524cf6 100644 --- a/test/ClangImporter/experimental_diagnostics_no_noise.swift +++ b/test/ClangImporter/experimental_diagnostics_no_noise.swift @@ -1,4 +1,4 @@ -// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -enable-objc-interop -typecheck %s 2>&1 | %FileCheck %s --strict-whitespace +// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -swift-version 5 -enable-objc-interop -typecheck %s 2>&1 | %FileCheck %s --strict-whitespace // REQUIRES: objc_interop diff --git a/test/ClangImporter/experimental_diagnostics_opt_out.swift b/test/ClangImporter/experimental_diagnostics_opt_out.swift index 3c8e7ab5c3d68..468594e6ad9f0 100644 --- a/test/ClangImporter/experimental_diagnostics_opt_out.swift +++ b/test/ClangImporter/experimental_diagnostics_opt_out.swift @@ -1,4 +1,4 @@ -// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -disable-experimental-clang-importer-diagnostics -enable-objc-interop -typecheck %s 2>&1 | %FileCheck %s --strict-whitespace +// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -swift-version 5 -disable-experimental-clang-importer-diagnostics -enable-objc-interop -typecheck %s 2>&1 | %FileCheck %s --strict-whitespace // REQUIRES: objc_interop diff --git a/test/ClangImporter/experimental_eager_diagnostics.swift b/test/ClangImporter/experimental_eager_diagnostics.swift index 1cc6a228bcb5a..aae71a987b0dd 100644 --- a/test/ClangImporter/experimental_eager_diagnostics.swift +++ b/test/ClangImporter/experimental_eager_diagnostics.swift @@ -1,4 +1,4 @@ -// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -enable-experimental-eager-clang-module-diagnostics -enable-objc-interop -typecheck %s 2>&1 | %FileCheck %s --strict-whitespace +// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -swift-version 5 -enable-experimental-eager-clang-module-diagnostics -enable-objc-interop -typecheck %s 2>&1 | %FileCheck %s --strict-whitespace // REQUIRES: objc_interop diff --git a/test/ClangImporter/incomplete_objc_types_availability.swift b/test/ClangImporter/incomplete_objc_types_availability.swift new file mode 100644 index 0000000000000..5e47340080ab1 --- /dev/null +++ b/test/ClangImporter/incomplete_objc_types_availability.swift @@ -0,0 +1,33 @@ +// RUN: %empty-directory(%t) +// RUN: %target-clang %S/Inputs/custom-modules/IncompleteTypes/incomplete-type-library-1.m -c -o %t/incomplete-type-library-1.o +// RUN: %target-clang %S/Inputs/custom-modules/IncompleteTypes/complete-types.m -c -o %t/complete-types.o + +// RUN: %target-build-swift -Xfrontend -enable-import-objc-forward-declarations -Xfrontend -enable-objc-interop -I %S/Inputs/custom-modules/IncompleteTypes %s %t/incomplete-type-library-1.o %t/complete-types.o -Xlinker -framework -Xlinker Foundation -o %t/a.out +// RUN: %target-run %t/a.out + +// RUN: %target-build-swift -swift-version 6 -Xfrontend -enable-objc-interop -I %S/Inputs/custom-modules/IncompleteTypes %s %t/incomplete-type-library-1.o %t/complete-types.o -Xlinker -framework -Xlinker Foundation -o %t/a.out +// RUN: %target-run %t/a.out + +// REQUIRES: objc_interop +// REQUIRES: executable_test + +// Verify that Clang declarations referencing either of the forward declares types "ForwardDeclaredInterface" or +// "ForwardDeclaredProtocol" are usable from Swift. + +import IncompleteTypeLibrary1 + +let incompleteTypeConsumer = IncompleteTypeConsumer1()! + +let incompleteInterface = incompleteTypeConsumer.methodReturningForwardDeclaredInterface1()! +incompleteTypeConsumer.methodTakingAForwardDeclaredInterface1(incompleteInterface) +let interfacePropertyCopy = incompleteTypeConsumer.propertyUsingAForwardDeclaredInterface1 +incompleteTypeConsumer.propertyUsingAForwardDeclaredInterface1 = incompleteInterface +_ = CFunctionReturningAForwardDeclaredInterface1() +CFunctionTakingAForwardDeclaredInterface1(incompleteInterface) + +let incompleteProtocol = incompleteTypeConsumer.methodReturningForwardDeclaredProtocol1()! +incompleteTypeConsumer.methodTakingAForwardDeclaredProtocol1(incompleteProtocol) +let protcolPropertyCopy = incompleteTypeConsumer.propertyUsingAForwardDeclaredProtocol1 +incompleteTypeConsumer.propertyUsingAForwardDeclaredProtocol1 = incompleteProtocol +_ = CFunctionReturningAForwardDeclaredProtocol1() +CFunctionTakingAForwardDeclaredProtocol1(incompleteProtocol) diff --git a/test/ClangImporter/incomplete_objc_types_base_interface.swift b/test/ClangImporter/incomplete_objc_types_base_interface.swift new file mode 100644 index 0000000000000..c1e1890adc602 --- /dev/null +++ b/test/ClangImporter/incomplete_objc_types_base_interface.swift @@ -0,0 +1,25 @@ +// RUN: %empty-directory(%t) +// RUN: %target-clang %S/Inputs/custom-modules/IncompleteTypes/incomplete-type-library-1.m -c -o %t/incomplete-type-library-1.o +// RUN: %target-clang %S/Inputs/custom-modules/IncompleteTypes/complete-types.m -c -o %t/complete-types.o + +// RUN: %target-build-swift -Xfrontend -enable-import-objc-forward-declarations -Xfrontend -enable-objc-interop -I %S/Inputs/custom-modules/IncompleteTypes %s %t/incomplete-type-library-1.o %t/complete-types.o -Xlinker -framework -Xlinker Foundation -o %t/a.out +// RUN: %target-run %t/a.out + +// REQUIRES: objc_interop +// REQUIRES: executable_test +// REQUIRES: OS=macosx + +import Foundation +import IncompleteTypeLibrary1 + +let incompleteTypeConsumer = IncompleteTypeConsumer1()! +let incompleteInterface = incompleteTypeConsumer.methodReturningForwardDeclaredInterface1()! +let incompleteProtocol = incompleteTypeConsumer.methodReturningForwardDeclaredProtocol1()! + +// Call some methods provided by the NSObject interface + +_ = incompleteInterface.perform(#selector(NSObject.description)) +_ = incompleteInterface.perform(#selector(NSObject.debugDescription)) +_ = incompleteInterface.perform(#selector(NSObject.hash)) +_ = incompleteInterface.isEqual(to: incompleteInterface) +_ = incompleteInterface.isLike("abc") diff --git a/test/ClangImporter/incomplete_objc_types_base_interface_swift_6.swift b/test/ClangImporter/incomplete_objc_types_base_interface_swift_6.swift new file mode 100644 index 0000000000000..e9ccfdc1a7e97 --- /dev/null +++ b/test/ClangImporter/incomplete_objc_types_base_interface_swift_6.swift @@ -0,0 +1,25 @@ +// RUN: %empty-directory(%t) +// RUN: %target-clang %S/Inputs/custom-modules/IncompleteTypes/incomplete-type-library-1.m -c -o %t/incomplete-type-library-1.o +// RUN: %target-clang %S/Inputs/custom-modules/IncompleteTypes/complete-types.m -c -o %t/complete-types.o + +// RUN: %target-build-swift -swift-version 6 -Xfrontend -enable-objc-interop -I %S/Inputs/custom-modules/IncompleteTypes %s %t/incomplete-type-library-1.o %t/complete-types.o -Xlinker -framework -Xlinker Foundation -o %t/a.out +// RUN: %target-run %t/a.out + +// REQUIRES: objc_interop +// REQUIRES: executable_test +// REQUIRES: OS=macosx + +import Foundation +import IncompleteTypeLibrary1 + +let incompleteTypeConsumer = IncompleteTypeConsumer1()! +let incompleteInterface = incompleteTypeConsumer.methodReturningForwardDeclaredInterface1()! +let incompleteProtocol = incompleteTypeConsumer.methodReturningForwardDeclaredProtocol1()! + +// Call some methods provided by the NSObject interface + +_ = incompleteInterface.perform(#selector(NSObject.description)) +_ = incompleteInterface.perform(#selector(NSObject.debugDescription)) +_ = incompleteInterface.perform(#selector(NSObject.hash)) +_ = incompleteInterface.isEqual(to: incompleteInterface) +_ = incompleteInterface.isLike("abc") diff --git a/test/ClangImporter/incomplete_objc_types_compatibility_complete_incomplete.swift b/test/ClangImporter/incomplete_objc_types_compatibility_complete_incomplete.swift new file mode 100644 index 0000000000000..257e9d47bbd44 --- /dev/null +++ b/test/ClangImporter/incomplete_objc_types_compatibility_complete_incomplete.swift @@ -0,0 +1,62 @@ +// RUN: %empty-directory(%t) +// RUN: %target-clang %S/Inputs/custom-modules/IncompleteTypes/incomplete-type-library-1.m -c -o %t/incomplete-type-library-1.o +// RUN: %target-clang %S/Inputs/custom-modules/IncompleteTypes/incomplete-type-library-2.m -c -o %t/incomplete-type-library-2.o +// RUN: %target-clang %S/Inputs/custom-modules/IncompleteTypes/complete-types.m -c -o %t/complete-types.o + +// RUN: %target-build-swift -Xfrontend -enable-import-objc-forward-declarations -Xfrontend -enable-objc-interop -I %S/Inputs/custom-modules/IncompleteTypes %s %t/incomplete-type-library-1.o %t/incomplete-type-library-2.o %t/complete-types.o -Xlinker -framework -Xlinker Foundation -o %t/a.out +// RUN: %target-run %t/a.out + +// RUN: %target-build-swift -swift-version 6 -Xfrontend -enable-objc-interop -I %S/Inputs/custom-modules/IncompleteTypes %s %t/incomplete-type-library-1.o %t/incomplete-type-library-2.o %t/complete-types.o -Xlinker -framework -Xlinker Foundation -o %t/a.out +// RUN: %target-run %t/a.out + +// REQUIRES: objc_interop +// REQUIRES: executable_test + +// "ForwardDeclaredInterface" and "ForwardDeclaredProtocol" are forward declared in IncompleteTypeLibrary1/2, and +// completely declared in CompleteTypes. This test verifies that instances of the complete types can be passed +// to the consuming libraries. + +import CompleteTypes +import IncompleteTypeLibrary1 +import IncompleteTypeLibrary2 + +let incompleteTypeConsumer1 = IncompleteTypeConsumer1()! +let incompleteTypeConsumer2 = IncompleteTypeConsumer2()! + +let completeInterface = ForwardDeclaredInterface() +let incompleteInterface = CFunctionReturningAForwardDeclaredInterface1() + +incompleteTypeConsumer1.methodTakingAForwardDeclaredInterface1(completeInterface) +let interfacePropertyCopy = incompleteTypeConsumer1.propertyUsingAForwardDeclaredInterface1 +incompleteTypeConsumer1.propertyUsingAForwardDeclaredInterface1 = completeInterface +CFunctionTakingAForwardDeclaredInterface1(completeInterface) + +incompleteTypeConsumer2.methodTakingAForwardDeclaredInterface2(completeInterface) +incompleteTypeConsumer2.propertyUsingAForwardDeclaredInterface2 = completeInterface +CFunctionTakingAForwardDeclaredInterface2(completeInterface) + +class SwiftTypeConformingToForwardDeclaredProtocol : ForwardDeclaredProtocol { + init() {} + func doSomethingForwardDeclaredProtocolsCan() { + print("Doing something forward declared protocols can!"); + } +} + +let completeProtocol = SwiftTypeConformingToForwardDeclaredProtocol() +let incompleteProtocol = CFunctionReturningAForwardDeclaredProtocol1() + +incompleteTypeConsumer1.methodTakingAForwardDeclaredProtocol1(completeProtocol) +let protocolPropertyCopy = incompleteTypeConsumer1.propertyUsingAForwardDeclaredProtocol1 +incompleteTypeConsumer1.propertyUsingAForwardDeclaredProtocol1 = completeProtocol +_ = CFunctionReturningAForwardDeclaredProtocol1() +CFunctionTakingAForwardDeclaredProtocol1(completeProtocol) + +incompleteTypeConsumer2.methodTakingAForwardDeclaredProtocol2(completeProtocol) +incompleteTypeConsumer2.propertyUsingAForwardDeclaredProtocol2 = completeProtocol +_ = CFunctionReturningAForwardDeclaredProtocol2() +CFunctionTakingAForwardDeclaredProtocol2(completeProtocol) + +takeACompleteInterface(incompleteInterface) +takeACompleteInterface(interfacePropertyCopy) +takeACompleteProtocol(incompleteProtocol) +takeACompleteProtocol(protocolPropertyCopy) diff --git a/test/ClangImporter/incomplete_objc_types_compatibility_complete_incomplete_inter_file_clang_definition.swift b/test/ClangImporter/incomplete_objc_types_compatibility_complete_incomplete_inter_file_clang_definition.swift new file mode 100644 index 0000000000000..dd74416217dfa --- /dev/null +++ b/test/ClangImporter/incomplete_objc_types_compatibility_complete_incomplete_inter_file_clang_definition.swift @@ -0,0 +1,38 @@ +// RUN: %empty-directory(%t) +// RUN: split-file %s %t + +// RUN: %target-clang %S/Inputs/custom-modules/IncompleteTypes/incomplete-type-library-1.m -c -o %t/incomplete-type-library-1.o +// RUN: %target-clang %S/Inputs/custom-modules/IncompleteTypes/complete-types.m -c -o %t/complete-types.o + +// RUN: %target-build-swift -Xfrontend -enable-import-objc-forward-declarations -Xfrontend -enable-objc-interop -I %S/Inputs/custom-modules/IncompleteTypes %t/full_definition.swift %t/incomplete_definition.swift %t/incomplete-type-library-1.o %t/complete-types.o -Xlinker -framework -Xlinker Foundation -o %t/a.out +// RUN: %target-run %t/a.out + +// REQUIRES: executable_test +// REQUIRES: objc_interop + +//--- full_definition.swift + +import CompleteTypes +import IncompleteTypeLibrary1 + +func getACompleteForwardDeclaredInterface() -> ForwardDeclaredInterface { + return ForwardDeclaredInterface() +} + +func takeACompleteForwardDeclaredInterface(_ param: ForwardDeclaredInterface) { + param.doSomethingForwardDeclaredInterfacesCan() +} + +//--- incomplete_definition.swift + +import IncompleteTypeLibrary1 + +@main +class Main { + static func main() { + let incompleteForwardDeclaredInterface = CFunctionReturningAForwardDeclaredInterface1()! + takeACompleteForwardDeclaredInterface(incompleteForwardDeclaredInterface) + let completeForwardDeclaredInterface = getACompleteForwardDeclaredInterface() + assert(type(of: incompleteForwardDeclaredInterface) == type(of: completeForwardDeclaredInterface)) + } +} diff --git a/test/ClangImporter/incomplete_objc_types_compatibility_complete_incomplete_inter_file_swift_definition.swift b/test/ClangImporter/incomplete_objc_types_compatibility_complete_incomplete_inter_file_swift_definition.swift new file mode 100644 index 0000000000000..5c65fc8666184 --- /dev/null +++ b/test/ClangImporter/incomplete_objc_types_compatibility_complete_incomplete_inter_file_swift_definition.swift @@ -0,0 +1,40 @@ +// RUN: %empty-directory(%t) +// RUN: split-file %s %t + +// RUN: %target-build-swift -module-name CompleteSwiftTypes -parse-as-library %S/Inputs/custom-modules/IncompleteTypes/complete-swift-types.swift -emit-module -emit-module-path %t/CompleteSwiftTypes.swiftmodule +// RUN: not %target-swift-frontend -enable-import-objc-forward-declarations -enable-objc-interop -typecheck -I %S/Inputs/custom-modules/IncompleteTypes -I %t %t/incomplete_definition.swift %t/full_definition.swift 2>&1 | %FileCheck %s + +// REQUIRES: objc_interop + +//--- full_definition.swift + +import CompleteSwiftTypes + +//--- incomplete_definition.swift + +import ObjCLibraryForwardDeclaringCompleteSwiftTypes + +@main +class Main { + static func main() { + let incompleteFoo = returnAFoo()! + // CHECK: incomplete_definition.swift:{{[0-9]+}}:{{[0-9]+}}: error: cannot find 'returnAFoo' in scope + // CHECK-NEXT: let incompleteFoo = returnAFoo()! + // CHECK-NEXT: ^~~~~~~~~~ + // CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: function 'returnAFoo' unavailable (cannot import) + // CHECK-NEXT: Foo *returnAFoo(); + // CHECK-NEXT: ^ + // CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: return type unavailable (cannot import) + // CHECK-NEXT: Foo *returnAFoo(); + // CHECK-NEXT: ^ + // CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: interface 'Foo' is incomplete + // CHECK-NEXT: Foo *returnAFoo(); + // CHECK-NEXT: ^ + // CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: interface 'Foo' is incomplete and cannot be imported as a stub; its name conflicts with a class in module CompleteSwiftTypes + // CHECK-NEXT: @class Foo; + // CHECK-NEXT: ^ + // CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: interface 'Foo' forward declared here + // CHECK-NEXT: @class Foo; + // CHECK-NEXT: ^ + } +} diff --git a/test/ClangImporter/incomplete_objc_types_compatibility_incomplete_incomplete.swift b/test/ClangImporter/incomplete_objc_types_compatibility_incomplete_incomplete.swift new file mode 100644 index 0000000000000..8961cbb2f0ae5 --- /dev/null +++ b/test/ClangImporter/incomplete_objc_types_compatibility_incomplete_incomplete.swift @@ -0,0 +1,52 @@ +// RUN: %empty-directory(%t) +// RUN: %target-clang %S/Inputs/custom-modules/IncompleteTypes/incomplete-type-library-1.m -c -o %t/incomplete-type-library-1.o +// RUN: %target-clang %S/Inputs/custom-modules/IncompleteTypes/incomplete-type-library-2.m -c -o %t/incomplete-type-library-2.o +// RUN: %target-clang %S/Inputs/custom-modules/IncompleteTypes/complete-types.m -c -o %t/complete-types.o + +// RUN: %target-build-swift -Xfrontend -enable-import-objc-forward-declarations -Xfrontend -enable-objc-interop -I %S/Inputs/custom-modules/IncompleteTypes %s %t/incomplete-type-library-1.o %t/incomplete-type-library-2.o %t/complete-types.o -Xlinker -framework -Xlinker Foundation -o %t/a.out +// RUN: %target-run %t/a.out + +// RUN: %target-build-swift -swift-version 6 -Xfrontend -enable-objc-interop -I %S/Inputs/custom-modules/IncompleteTypes %s %t/incomplete-type-library-1.o %t/incomplete-type-library-2.o %t/complete-types.o -Xlinker -framework -Xlinker Foundation -o %t/a.out +// RUN: %target-run %t/a.out + +// REQUIRES: objc_interop +// REQUIRES: executable_test + +// Both libraries "IncompleteTypeConsumer1" and "IncompleteTypeConsumer2" forward declare an interface "ForwardDeclaredInterface" +// and a protocol "ForwardDeclaredProtocol". This test verifies that the synthesized Swift declaration created to represent +// these types are interchangeable (ie. You can pass an IncompleteTypeConsumer1.ForwardDeclaredProtocol instance to a +// function expecting an IncompleteTypeConsumer2.ForwardDeclaredInterface and vice versa) + +import IncompleteTypeLibrary1 +import IncompleteTypeLibrary2 + +let incompleteTypeConsumer1 = IncompleteTypeConsumer1()! +let incompleteTypeConsumer2 = IncompleteTypeConsumer2()! + +let incompleteInterface1 = incompleteTypeConsumer1.methodReturningForwardDeclaredInterface1()! +let incompleteInterface2 = incompleteTypeConsumer2.methodReturningForwardDeclaredInterface2()! + +incompleteTypeConsumer1.methodTakingAForwardDeclaredInterface1(incompleteInterface2) +incompleteTypeConsumer2.methodTakingAForwardDeclaredInterface2(incompleteInterface1) + +let interfacePropertyCopy1 = incompleteTypeConsumer1.propertyUsingAForwardDeclaredInterface1 +let interfacePropertyCopy2 = incompleteTypeConsumer2.propertyUsingAForwardDeclaredInterface2 +incompleteTypeConsumer1.propertyUsingAForwardDeclaredInterface1 = incompleteInterface2 +incompleteTypeConsumer2.propertyUsingAForwardDeclaredInterface2 = incompleteInterface1 + +CFunctionTakingAForwardDeclaredInterface1(incompleteInterface2) +CFunctionTakingAForwardDeclaredInterface2(incompleteInterface1) + +let incompleteProtocol1 = incompleteTypeConsumer1.methodReturningForwardDeclaredProtocol1()! +let incompleteProtocol2 = incompleteTypeConsumer2.methodReturningForwardDeclaredProtocol2()! + +incompleteTypeConsumer1.methodTakingAForwardDeclaredProtocol1(incompleteProtocol2) +incompleteTypeConsumer2.methodTakingAForwardDeclaredProtocol2(incompleteProtocol1) + +let protocolPropertyCopy1 = incompleteTypeConsumer1.propertyUsingAForwardDeclaredProtocol1 +let protocolPropertyCopy2 = incompleteTypeConsumer2.propertyUsingAForwardDeclaredProtocol2 +incompleteTypeConsumer1.propertyUsingAForwardDeclaredProtocol1 = incompleteProtocol2 +incompleteTypeConsumer2.propertyUsingAForwardDeclaredProtocol2 = incompleteProtocol1 + +CFunctionTakingAForwardDeclaredProtocol1(incompleteProtocol2) +CFunctionTakingAForwardDeclaredProtocol2(incompleteProtocol1) diff --git a/test/ClangImporter/incomplete_objc_types_full_availability.swift b/test/ClangImporter/incomplete_objc_types_full_availability.swift new file mode 100644 index 0000000000000..76c59ee21804a --- /dev/null +++ b/test/ClangImporter/incomplete_objc_types_full_availability.swift @@ -0,0 +1,41 @@ +// RUN: %empty-directory(%t) +// RUN: %target-clang %S/Inputs/custom-modules/IncompleteTypes/incomplete-type-library-1.m -c -o %t/incomplete-type-library-1.o +// RUN: %target-clang %S/Inputs/custom-modules/IncompleteTypes/complete-types.m -c -o %t/complete-types.o + +// RUN: %target-build-swift -Xfrontend -enable-import-objc-forward-declarations -Xfrontend -enable-objc-interop -I %S/Inputs/custom-modules/IncompleteTypes %s %t/incomplete-type-library-1.o %t/complete-types.o -Xlinker -framework -Xlinker Foundation -o %t/a.out +// RUN: %target-run %t/a.out + +// REQUIRES: objc_interop +// REQUIRES: executable_test + +import IncompleteTypeLibrary1 +import CompleteTypes + +class Dummy { + init() {} +} + +let dummy = Dummy() + +assert(!(dummy is ForwardDeclaredInterface)) +assert(!(dummy is ForwardDeclaredProtocol)) + +func interfaceTestFunc(param: ForwardDeclaredInterface) {} +func protocolTestFunc(param: ForwardDeclaredProtocol) {} + +class InterfaceTestClass : ForwardDeclaredInterface {} + +class ProtocolTestClass : ForwardDeclaredProtocol { + init() {} + func doSomethingForwardDeclaredProtocolsCan() { + + } +} + +let interfaceTestClassInstance = InterfaceTestClass()! +let interfaceTestInstance = ForwardDeclaredInterface()! +let protocolTestClassInstance = ProtocolTestClass() + +interfaceTestClassInstance.doSomethingForwardDeclaredInterfacesCan() +interfaceTestInstance.doSomethingForwardDeclaredInterfacesCan() +protocolTestClassInstance.doSomethingForwardDeclaredProtocolsCan() diff --git a/test/ClangImporter/incomplete_objc_types_full_availability_swift_6.swift b/test/ClangImporter/incomplete_objc_types_full_availability_swift_6.swift new file mode 100644 index 0000000000000..7add1e6b94973 --- /dev/null +++ b/test/ClangImporter/incomplete_objc_types_full_availability_swift_6.swift @@ -0,0 +1,41 @@ +// RUN: %empty-directory(%t) +// RUN: %target-clang %S/Inputs/custom-modules/IncompleteTypes/incomplete-type-library-1.m -c -o %t/incomplete-type-library-1.o +// RUN: %target-clang %S/Inputs/custom-modules/IncompleteTypes/complete-types.m -c -o %t/complete-types.o + +// RUN: %target-build-swift -swift-version 6 -Xfrontend -enable-objc-interop -I %S/Inputs/custom-modules/IncompleteTypes %s %t/incomplete-type-library-1.o %t/complete-types.o -Xlinker -framework -Xlinker Foundation -o %t/a.out +// RUN: %target-run %t/a.out + +// REQUIRES: objc_interop +// REQUIRES: executable_test + +import IncompleteTypeLibrary1 +import CompleteTypes + +class Dummy { + init() {} +} + +let dummy = Dummy() + +assert(!(dummy is ForwardDeclaredInterface)) +assert(!(dummy is any ForwardDeclaredProtocol)) + +func interfaceTestFunc(param: ForwardDeclaredInterface) {} +func protocolTestFunc(param: any ForwardDeclaredProtocol) {} + +class InterfaceTestClass : ForwardDeclaredInterface {} + +class ProtocolTestClass : ForwardDeclaredProtocol { + init() {} + func doSomethingForwardDeclaredProtocolsCan() { + + } +} + +let interfaceTestClassInstance = InterfaceTestClass()! +let interfaceTestInstance = ForwardDeclaredInterface()! +let protocolTestClassInstance = ProtocolTestClass() + +interfaceTestClassInstance.doSomethingForwardDeclaredInterfacesCan() +interfaceTestInstance.doSomethingForwardDeclaredInterfacesCan() +protocolTestClassInstance.doSomethingForwardDeclaredProtocolsCan() diff --git a/test/ClangImporter/incomplete_objc_types_importing_limitations_diagnostics.swift b/test/ClangImporter/incomplete_objc_types_importing_limitations_diagnostics.swift new file mode 100644 index 0000000000000..0a21381233ae9 --- /dev/null +++ b/test/ClangImporter/incomplete_objc_types_importing_limitations_diagnostics.swift @@ -0,0 +1,43 @@ +// RUN: not %target-swift-frontend -enable-import-objc-forward-declarations -enable-objc-interop -typecheck -I %S/Inputs/custom-modules/IncompleteTypes %s 2>&1 | %FileCheck %s +// RUN: not %target-swift-frontend -swift-version 6 -enable-objc-interop -typecheck -I %S/Inputs/custom-modules/IncompleteTypes %s 2>&1 | %FileCheck %s + +// REQUIRES: objc_interop + +import IncompleteTypeLibrary1 +import IncompleteNoRootTypeProtocolLibrary + +let incompleteInterface = CFunctionReturningAForwardDeclaredInterface1()! +let incompleteProtocol = CFunctionReturningAForwardDeclaredProtocol1()! +let incompleteNoRootTypeProtocol = CFunctionReturningAForwardDeclaredNoRootTypeProtocol()! + +incompleteInterface.doSomethingForwardDeclaredInterfacesCan() +// CHECK: incomplete_objc_types_importing_limitations_diagnostics.swift:{{[0-9]+}}:{{[0-9]+}}: error: value of type 'ForwardDeclaredInterface' has no member 'doSomethingForwardDeclaredInterfacesCan' +// CHECK: incompleteInterface.doSomethingForwardDeclaredInterfacesCan() +// CHECK: incomplete-type-library-1.h:{{[0-9]+}}:{{[0-9]+}}: note: class 'ForwardDeclaredInterface' will be imported as an opaque placeholder class and may be missing members; import the definition to access the complete interface +// CHECK: @class ForwardDeclaredInterface; +// CHECK: ^ +// CHECK: incomplete-type-library-1.h:{{[0-9]+}}:{{[0-9]+}}: note: interface 'ForwardDeclaredInterface' forward declared here +// CHECK: @class ForwardDeclaredInterface; +// CHECK: ^ + +incompleteProtocol.doSomethingForwardDeclaredProtocolsCan() +// CHECK: incomplete_objc_types_importing_limitations_diagnostics.swift:{{[0-9]+}}:{{[0-9]+}}: error: value of type 'any ForwardDeclaredProtocol & NSObjectProtocol' has no member 'doSomethingForwardDeclaredProtocolsCan' +// CHECK: incompleteProtocol.doSomethingForwardDeclaredProtocolsCan() +// CHECK: incomplete-type-library-1.h:{{[0-9]+}}:{{[0-9]+}}: note: protocol 'ForwardDeclaredProtocol' will be imported as an opaque placeholder protocol and may be missing members; import the definition to access the complete protocol +// CHECK: @protocol ForwardDeclaredProtocol; +// CHECK: ^ +// CHECK: incomplete-type-library-1.h:{{[0-9]+}}:{{[0-9]+}}: note: protocol 'ForwardDeclaredProtocol' forward declared here +// CHECK: @protocol ForwardDeclaredProtocol; +// CHECK: ^ + +incompleteNoRootTypeProtocol.doSomethingForwardDeclaredProtocolsCan() +// CHECK: incomplete_objc_types_importing_limitations_diagnostics.swift:{{[0-9]+}}:{{[0-9]+}}: error: value of type 'any NoRootTypeProtocol' has no member 'doSomethingForwardDeclaredProtocolsCan' +// CHECK: incompleteNoRootTypeProtocol.doSomethingForwardDeclaredProtocolsCan() +// CHECK: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK: incomplete-noroottype-protocol-library.h:{{[0-9]+}}:{{[0-9]+}}: note: protocol 'NoRootTypeProtocol' will be imported as an opaque placeholder protocol and may be missing members; import the definition to access the complete protocol +// CHECK: @protocol NoRootTypeProtocol; +// CHECK: ^ +// CHECK: incomplete-noroottype-protocol-library.h:{{[0-9]+}}:{{[0-9]+}}: note: protocol 'NoRootTypeProtocol' forward declared here +// CHECK: @protocol NoRootTypeProtocol; +// CHECK: ^ + diff --git a/test/ClangImporter/incomplete_objc_types_no_reference.swift b/test/ClangImporter/incomplete_objc_types_no_reference.swift new file mode 100644 index 0000000000000..5ee0f9b58575f --- /dev/null +++ b/test/ClangImporter/incomplete_objc_types_no_reference.swift @@ -0,0 +1,31 @@ +// RUN: not %target-swift-frontend -enable-import-objc-forward-declarations -enable-objc-interop -typecheck -I %S/Inputs/custom-modules/IncompleteTypes %s 2>&1 | %FileCheck %s +// RUN: not %target-swift-frontend -swift-version 6 -enable-objc-interop -typecheck -I %S/Inputs/custom-modules/IncompleteTypes %s 2>&1 | %FileCheck %s + +// REQUIRES: objc_interop + +import IncompleteTypeLibrary1 + +class Dummy { + init() {} +} + +let dummy = Dummy() + +// CHECK: error: 'ForwardDeclaredInterface' is unavailable: This Objective-C class has only been forward-declared; import its owning module to use it +assert(!(dummy is ForwardDeclaredInterface)) + +// CHECK: error: 'ForwardDeclaredProtocol' is unavailable: This Objective-C protocol has only been forward-declared; import its owning module to use it +assert(!(dummy is ForwardDeclaredProtocol)) + +// CHECK: error: 'ForwardDeclaredInterface' is unavailable: This Objective-C class has only been forward-declared; import its owning module to use it +func interfaceTestFunc(param: ForwardDeclaredInterface) {} +// CHECK: error: 'ForwardDeclaredProtocol' is unavailable: This Objective-C protocol has only been forward-declared; import its owning module to use it +func protocolTestFunc(param: ForwardDeclaredProtocol) {} + +// CHECK: error: 'ForwardDeclaredInterface' is unavailable: This Objective-C class has only been forward-declared; import its owning module to use it +class interfaceTestClass : ForwardDeclaredInterface {} +// CHECK: error: 'ForwardDeclaredProtocol' is unavailable: This Objective-C protocol has only been forward-declared; import its owning module to use it +class protocolTestClass : ForwardDeclaredProtocol {} + +// CHECK: error: 'ForwardDeclaredInterface' cannot be constructed because it has no accessible initializers +let interfaceTestInstance = ForwardDeclaredInterface() diff --git a/test/ClangImporter/incomplete_objc_types_no_root_protocol.swift b/test/ClangImporter/incomplete_objc_types_no_root_protocol.swift new file mode 100644 index 0000000000000..b0f30a6b1ff1b --- /dev/null +++ b/test/ClangImporter/incomplete_objc_types_no_root_protocol.swift @@ -0,0 +1,25 @@ +// RUN: %empty-directory(%t) +// RUN: %target-clang %S/Inputs/custom-modules/IncompleteTypes/incomplete-noroottype-protocol-library.m -c -o %t/incomplete-noroottype-protocol-library.o + +// RUN: %target-build-swift -Xfrontend -enable-import-objc-forward-declarations -Xfrontend -enable-objc-interop -I %S/Inputs/custom-modules/IncompleteTypes %s %t/incomplete-noroottype-protocol-library.o -Xlinker -framework -Xlinker Foundation -o %t/a.out +// RUN: %target-run %t/a.out + +// RUN: %target-build-swift -swift-version 6 -Xfrontend -enable-objc-interop -I %S/Inputs/custom-modules/IncompleteTypes %s %t/incomplete-noroottype-protocol-library.o -Xlinker -framework -Xlinker Foundation -o %t/a.out +// RUN: %target-run %t/a.out + +// REQUIRES: objc_interop +// REQUIRES: executable_test + +// Verify that a forward declared protocol not inheriting from NSObject is usable +// from Swift, if cumbersome + +import IncompleteNoRootTypeProtocolLibrary + +let consumer = NoRootTypeProtocolConsumer()! + +let incompleteNoRootTypeProtocol = consumer.methodReturningForwardDeclaredNoRootTypeProtocol()! +consumer.methodTakingAForwardDeclaredNoRootTypeProtocol(incompleteNoRootTypeProtocol) +let interfacePropertyCopy = consumer.propertyUsingAForwardDeclaredNoRootTypeProtocol +consumer.propertyUsingAForwardDeclaredNoRootTypeProtocol = incompleteNoRootTypeProtocol +_ = CFunctionReturningAForwardDeclaredNoRootTypeProtocol() +CFunctionTakingAForwardDeclaredNoRootTypeProtocol(incompleteNoRootTypeProtocol) diff --git a/test/ClangImporter/incomplete_objc_types_nsproxy.swift b/test/ClangImporter/incomplete_objc_types_nsproxy.swift new file mode 100644 index 0000000000000..548499078e09a --- /dev/null +++ b/test/ClangImporter/incomplete_objc_types_nsproxy.swift @@ -0,0 +1,30 @@ +// RUN: %empty-directory(%t) +// RUN: %target-clang %S/Inputs/custom-modules/IncompleteTypes/incomplete-nsproxy-library.m -c -o %t/incomplete-nsproxy-library.o + +// RUN: %target-build-swift -Xfrontend -enable-import-objc-forward-declarations -Xfrontend -enable-objc-interop -I %S/Inputs/custom-modules/IncompleteTypes %s %t/incomplete-nsproxy-library.o -Xlinker -framework -Xlinker Foundation -o %t/a.out +// RUN: %target-run %t/a.out + +// RUN: %target-build-swift -swift-version 6 -Xfrontend -enable-objc-interop -I %S/Inputs/custom-modules/IncompleteTypes %s %t/incomplete-nsproxy-library.o -Xlinker -framework -Xlinker Foundation -o %t/a.out +// RUN: %target-run %t/a.out + +// REQUIRES: objc_interop +// REQUIRES: executable_test + +// Verify that a forward declared interface for a type inheriting from NSProxy instead +// of NSObject is still usable from Swift. + +import IncompleteNSProxyLibrary +import Foundation + +let consumer = NSProxyConsumer()! + +let incompleteNSProxyInterface = consumer.methodReturningForwardDeclaredNSProxyInterface()! +consumer.methodTakingAForwardDeclaredNSProxyInterface(incompleteNSProxyInterface) +let interfacePropertyCopy = consumer.propertyUsingAForwardDeclaredNSProxyInterface +consumer.propertyUsingAForwardDeclaredNSProxyInterface = incompleteNSProxyInterface +_ = CFunctionReturningAForwardDeclaredNSProxyInterface() +CFunctionTakingAForwardDeclaredNSProxyInterface(incompleteNSProxyInterface) + +_ = incompleteNSProxyInterface.perform(#selector(NSObject.description)) +_ = incompleteNSProxyInterface.perform(#selector(NSObject.debugDescription)) +_ = incompleteNSProxyInterface.perform(#selector(NSObject.hash)) diff --git a/test/ClangImporter/incomplete_objc_types_swift_definition_imported.swift b/test/ClangImporter/incomplete_objc_types_swift_definition_imported.swift new file mode 100644 index 0000000000000..ae25cfc10cb35 --- /dev/null +++ b/test/ClangImporter/incomplete_objc_types_swift_definition_imported.swift @@ -0,0 +1,173 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift -parse-as-library %S/Inputs/custom-modules/IncompleteTypes/complete-swift-types.swift -module-name CompleteSwiftTypes -emit-module -emit-module-path %t/CompleteSwiftTypes.swiftmodule +// RUN: not %target-swift-frontend -enable-import-objc-forward-declarations -enable-objc-interop -typecheck -I %S/Inputs/custom-modules/IncompleteTypes -I %t %s 2>&1 | %FileCheck %s +// RUN: not %target-swift-frontend -swift-version 6 -enable-objc-interop -typecheck -I %S/Inputs/custom-modules/IncompleteTypes -I %t %s 2>&1 | %FileCheck %s + +// REQUIRES: objc_interop + +import CompleteSwiftTypes +import ObjCLibraryForwardDeclaringCompleteSwiftTypes + +let foo = Foo() +let bar = Bar() +let corge = Corge() + +takeAFoo(foo) +// CHECK: incomplete_objc_types_swift_definition_imported.swift:{{[0-9]+}}:{{[0-9]+}}: error: cannot find 'takeAFoo' in scope +// CHECK-NEXT: takeAFoo(foo) +// CHECK-NEXT: ^~~~~~~~ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: function 'takeAFoo' unavailable (cannot import) +// CHECK-NEXT: void takeAFoo(Foo *foo); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: parameter 'foo' unavailable (cannot import) +// CHECK-NEXT: void takeAFoo(Foo *foo); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: interface 'Foo' is incomplete +// CHECK-NEXT: void takeAFoo(Foo *foo); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: interface 'Foo' is incomplete and cannot be imported as a stub; its name conflicts with a class in module CompleteSwiftTypes +// CHECK-NEXT: @class Foo; +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: interface 'Foo' forward declared here +// CHECK-NEXT: @class Foo; +// CHECK-NEXT: ^ + +_ = returnAFoo() +// CHECK: incomplete_objc_types_swift_definition_imported.swift:{{[0-9]+}}:{{[0-9]+}}: error: cannot find 'returnAFoo' in scope +// CHECK-NEXT: _ = returnAFoo() +// CHECK-NEXT: ^~~~~~~~~~ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: function 'returnAFoo' unavailable (cannot import) +// CHECK-NEXT: Foo *returnAFoo(); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: return type unavailable (cannot import) +// CHECK-NEXT: Foo *returnAFoo(); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: interface 'Foo' is incomplete +// CHECK-NEXT: Foo *returnAFoo(); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: interface 'Foo' is incomplete and cannot be imported as a stub; its name conflicts with a class in module CompleteSwiftTypes +// CHECK-NEXT: @class Foo; +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: interface 'Foo' forward declared here +// CHECK-NEXT: @class Foo; +// CHECK-NEXT: ^ + +takeABaz(bar) +// CHECK: incomplete_objc_types_swift_definition_imported.swift:{{[0-9]+}}:{{[0-9]+}}: error: cannot find 'takeABaz' in scope +// CHECK-NEXT: takeABaz(bar) +// CHECK-NEXT: ^~~~~~~~ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: function 'takeABaz' unavailable (cannot import) +// CHECK-NEXT: void takeABaz(Baz *baz); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: parameter 'baz' unavailable (cannot import) +// CHECK-NEXT: void takeABaz(Baz *baz); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: interface 'Baz' is incomplete +// CHECK-NEXT: void takeABaz(Baz *baz); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: interface 'Baz' is incomplete and cannot be imported as a stub; its name conflicts with a class in module CompleteSwiftTypes +// CHECK-NEXT: @class Baz; +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: interface 'Baz' forward declared here +// CHECK-NEXT: @class Baz; +// CHECK-NEXT: ^ + +_ = returnABaz() +// CHECK: incomplete_objc_types_swift_definition_imported.swift:{{[0-9]+}}:{{[0-9]+}}: error: cannot find 'returnABaz' in scope +// CHECK-NEXT: _ = returnABaz() +// CHECK-NEXT: ^~~~~~~~~~ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: function 'returnABaz' unavailable (cannot import) +// CHECK-NEXT: Baz *returnABaz(); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: return type unavailable (cannot import) +// CHECK-NEXT: Baz *returnABaz(); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: interface 'Baz' is incomplete +// CHECK-NEXT: Baz *returnABaz(); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: interface 'Baz' is incomplete and cannot be imported as a stub; its name conflicts with a class in module CompleteSwiftTypes +// CHECK-NEXT: @class Baz; +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: interface 'Baz' forward declared here +// CHECK-NEXT: @class Baz; +// CHECK-NEXT: ^ + +takeASubscript(corge) +// CHECK: incomplete_objc_types_swift_definition_imported.swift:{{[0-9]+}}:{{[0-9]+}}: error: cannot find 'takeASubscript' in scope +// CHECK-NEXT: takeASubscript(corge) +// CHECK-NEXT: ^~~~~~~~~~~~~~ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: function 'takeASubscript' unavailable (cannot import) +// CHECK-NEXT: void takeASubscript(subscript *param); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: parameter 'param' unavailable (cannot import) +// CHECK-NEXT: void takeASubscript(subscript *param); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: interface 'subscript' is incomplete +// CHECK-NEXT: void takeASubscript(subscript *param); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: interface 'subscript' is incomplete and cannot be imported as a stub; its name conflicts with a class in module CompleteSwiftTypes +// CHECK-NEXT: @class subscript; +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: interface 'subscript' forward declared here +// CHECK-NEXT: @class subscript; +// CHECK-NEXT: ^ + +_ = returnASubscript() +// CHECK: incomplete_objc_types_swift_definition_imported.swift:{{[0-9]+}}:{{[0-9]+}}: error: cannot find 'returnASubscript' in scope +// CHECK-NEXT: _ = returnASubscript() +// CHECK-NEXT: ^~~~~~~~~~~~~~~~ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: function 'returnASubscript' unavailable (cannot import) +// CHECK-NEXT: subscript* returnASubscript(); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: return type unavailable (cannot import) +// CHECK-NEXT: subscript* returnASubscript(); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: interface 'subscript' is incomplete +// CHECK-NEXT: subscript* returnASubscript(); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: interface 'subscript' is incomplete and cannot be imported as a stub; its name conflicts with a class in module CompleteSwiftTypes +// CHECK-NEXT: @class subscript; +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: interface 'subscript' forward declared here +// CHECK-NEXT: @class subscript; +// CHECK-NEXT: ^ + +_ = returnAProtocolFoo() +// CHECK: incomplete_objc_types_swift_definition_imported.swift:{{[0-9]+}}:{{[0-9]+}}: error: cannot find 'returnAProtocolFoo' in scope +// CHECK-NEXT: _ = returnAProtocolFoo() +// CHECK-NEXT: ^~~~~~~~~~~~~~~~~~ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: function 'returnAProtocolFoo' unavailable (cannot import) +// CHECK-NEXT: id returnAProtocolFoo(); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: return type unavailable (cannot import) +// CHECK-NEXT: id returnAProtocolFoo(); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: protocol 'ProtocolFoo' is incomplete +// CHECK-NEXT: id returnAProtocolFoo(); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: protocol 'ProtocolFoo' is incomplete and cannot be imported as a stub; its name conflicts with a protocol in module CompleteSwiftTypes +// CHECK-NEXT: @protocol ProtocolFoo; +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: protocol 'ProtocolFoo' forward declared here +// CHECK-NEXT: @protocol ProtocolFoo; +// CHECK-NEXT: ^ + +_ = returnAProtocolBaz() +// CHECK: incomplete_objc_types_swift_definition_imported.swift:{{[0-9]+}}:{{[0-9]+}}: error: cannot find 'returnAProtocolBaz' in scope +// CHECK-NEXT: _ = returnAProtocolBaz() +// CHECK-NEXT: ^~~~~~~~~~~~~~~~~~ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: function 'returnAProtocolBaz' unavailable (cannot import) +// CHECK-NEXT: id returnAProtocolBaz(); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: return type unavailable (cannot import) +// CHECK-NEXT: id returnAProtocolBaz(); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: protocol 'ProtocolBaz' is incomplete +// CHECK-NEXT: id returnAProtocolBaz(); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: protocol 'ProtocolBaz' is incomplete and cannot be imported as a stub; its name conflicts with a protocol in module CompleteSwiftTypes +// CHECK-NEXT: @protocol ProtocolBaz; +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: protocol 'ProtocolBaz' forward declared here +// CHECK-NEXT: @protocol ProtocolBaz; +// CHECK-NEXT: ^ diff --git a/test/ClangImporter/incomplete_objc_types_swift_definition_imported_implementationOnly.swift b/test/ClangImporter/incomplete_objc_types_swift_definition_imported_implementationOnly.swift new file mode 100644 index 0000000000000..435f7db02f312 --- /dev/null +++ b/test/ClangImporter/incomplete_objc_types_swift_definition_imported_implementationOnly.swift @@ -0,0 +1,29 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift -parse-as-library %S/Inputs/custom-modules/IncompleteTypes/complete-swift-types.swift -module-name CompleteSwiftTypes -emit-module -emit-module-path %t/CompleteSwiftTypes.swiftmodule +// RUN: not %target-swift-frontend -enable-import-objc-forward-declarations -enable-objc-interop -typecheck -I %S/Inputs/custom-modules/IncompleteTypes -I %t %s 2>&1 | %FileCheck %s +// RUN: not %target-swift-frontend -swift-version 6 -enable-objc-interop -typecheck -I %S/Inputs/custom-modules/IncompleteTypes -I %t %s 2>&1 | %FileCheck %s + +// REQUIRES: objc_interop + +@_implementationOnly import CompleteSwiftTypes +import ObjCLibraryForwardDeclaringCompleteSwiftTypes + +_ = returnAFoo() +// CHECK: incomplete_objc_types_swift_definition_imported_implementationOnly.swift:{{[0-9]+}}:{{[0-9]+}}: error: cannot find 'returnAFoo' in scope +// CHECK-NEXT: _ = returnAFoo() +// CHECK-NEXT: ^~~~~~~~~~ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: function 'returnAFoo' unavailable (cannot import) +// CHECK-NEXT: Foo *returnAFoo(); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: return type unavailable (cannot import) +// CHECK-NEXT: Foo *returnAFoo(); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: interface 'Foo' is incomplete +// CHECK-NEXT: Foo *returnAFoo(); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: interface 'Foo' is incomplete and cannot be imported as a stub; its name conflicts with a class in module CompleteSwiftTypes +// CHECK-NEXT: @class Foo; +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: interface 'Foo' forward declared here +// CHECK-NEXT: @class Foo; +// CHECK-NEXT: ^ diff --git a/test/ClangImporter/incomplete_objc_types_swift_definition_imported_name_conflict.swift b/test/ClangImporter/incomplete_objc_types_swift_definition_imported_name_conflict.swift new file mode 100644 index 0000000000000..34c4056ee05d0 --- /dev/null +++ b/test/ClangImporter/incomplete_objc_types_swift_definition_imported_name_conflict.swift @@ -0,0 +1,71 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift -parse-as-library %S/Inputs/custom-modules/IncompleteTypes/complete-swift-types.swift -module-name CompleteSwiftTypes -emit-module -emit-module-path %t/CompleteSwiftTypes.swiftmodule +// RUN: not %target-swift-frontend -enable-import-objc-forward-declarations -enable-objc-interop -typecheck -I %S/Inputs/custom-modules/IncompleteTypes -I %t %s 2>&1 | %FileCheck %s +// RUN: not %target-swift-frontend -swift-version 6 -enable-objc-interop -typecheck -I %S/Inputs/custom-modules/IncompleteTypes -I %t %s 2>&1 | %FileCheck %s + +// REQUIRES: objc_interop + +import CompleteSwiftTypes +import ObjCLibraryForwardDeclaringCompleteSwiftTypes + +let qux = Qux() + +takeAConflictingTypeName(qux) +// CHECK: incomplete_objc_types_swift_definition_imported_name_conflict.swift:{{[0-9]+}}:{{[0-9]+}}: error: cannot find 'takeAConflictingTypeName' in scope +// CHECK-NEXT: takeAConflictingTypeName(qux) +// CHECK-NEXT: ^~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: function 'takeAConflictingTypeName' unavailable (cannot import) +// CHECK-NEXT: void takeAConflictingTypeName(ConflictingTypeName *param); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: parameter 'param' unavailable (cannot import) +// CHECK-NEXT: void takeAConflictingTypeName(ConflictingTypeName *param); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: interface 'ConflictingTypeName' is incomplete +// CHECK-NEXT: void takeAConflictingTypeName(ConflictingTypeName *param); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: interface 'ConflictingTypeName' is incomplete and cannot be imported as a stub; its name conflicts with a class in module CompleteSwiftTypes +// CHECK-NEXT: @class ConflictingTypeName; +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: interface 'ConflictingTypeName' forward declared here +// CHECK-NEXT: @class ConflictingTypeName; +// CHECK-NEXT: ^ + +_ = returnAConflictingTypeName() +// CHECK: incomplete_objc_types_swift_definition_imported_name_conflict.swift:{{[0-9]+}}:{{[0-9]+}}: error: cannot find 'returnAConflictingTypeName' in scope +// CHECK-NEXT: _ = returnAConflictingTypeName() +// CHECK-NEXT: ^~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: function 'returnAConflictingTypeName' unavailable (cannot import) +// CHECK-NEXT: ConflictingTypeName *returnAConflictingTypeName(); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: return type unavailable (cannot import) +// CHECK-NEXT: ConflictingTypeName *returnAConflictingTypeName(); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: interface 'ConflictingTypeName' is incomplete +// CHECK-NEXT: ConflictingTypeName *returnAConflictingTypeName(); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: interface 'ConflictingTypeName' is incomplete and cannot be imported as a stub; its name conflicts with a class in module CompleteSwiftTypes +// CHECK-NEXT: @class ConflictingTypeName; +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: interface 'ConflictingTypeName' forward declared here +// CHECK-NEXT: @class ConflictingTypeName; +// CHECK-NEXT: ^ + +_ = returnAProtocolConflictingTypeName() +// CHECK: incomplete_objc_types_swift_definition_imported_name_conflict.swift:{{[0-9]+}}:{{[0-9]+}}: error: cannot find 'returnAProtocolConflictingTypeName' in scope +// CHECK-NEXT: _ = returnAProtocolConflictingTypeName() +// CHECK-NEXT: ^~~~~~~~~~~~~~~~~~ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: function 'returnAProtocolConflictingTypeName' unavailable (cannot import) +// CHECK-NEXT: id returnAProtocolConflictingTypeName(); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: return type unavailable (cannot import) +// CHECK-NEXT: id returnAProtocolConflictingTypeName(); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: protocol 'ProtocolConflictingTypeName' is incomplete +// CHECK-NEXT: id returnAProtocolConflictingTypeName(); +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: protocol 'ProtocolConflictingTypeName' is incomplete and cannot be imported as a stub; its name conflicts with a protocol in module CompleteSwiftTypes +// CHECK-NEXT: @protocol ProtocolConflictingTypeName; +// CHECK-NEXT: ^ +// CHECK-NEXT: objc-library-forward-declaring-complete-swift-types.h:{{[0-9]+}}:{{[0-9]+}}: note: protocol 'ProtocolConflictingTypeName' forward declared here +// CHECK-NEXT: @protocol ProtocolConflictingTypeName; +// CHECK-NEXT: ^ diff --git a/test/ClangImporter/incomplete_objc_types_swift_definition_imported_shadow_type_mismatch.swift b/test/ClangImporter/incomplete_objc_types_swift_definition_imported_shadow_type_mismatch.swift new file mode 100644 index 0000000000000..488790f63de6e --- /dev/null +++ b/test/ClangImporter/incomplete_objc_types_swift_definition_imported_shadow_type_mismatch.swift @@ -0,0 +1,13 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift -parse-as-library %S/Inputs/custom-modules/IncompleteTypes/complete-swift-types.swift -emit-module -emit-module-path %t/CompleteSwiftTypes.swiftmodule -emit-objc-header -emit-objc-header-path %t/CompleteSwiftTypes-Swift.h -emit-library -o %t/libCompleteSwiftTypes.dylib +// RUN: %target-clang -framework Foundation -dynamiclib %S/Inputs/custom-modules/IncompleteTypes/objc-library-forward-declaring-complete-swift-types.m -I %t -L %t -lCompleteSwiftTypes -o %t/libObjCLibraryForwardDeclaringCompleteSwiftTypes.dylib +// RUN: %target-build-swift -Xfrontend -enable-import-objc-forward-declarations -Xfrontend -enable-objc-interop %s -I %S/Inputs/custom-modules/IncompleteTypes -I %t -L %t -lCompleteSwiftTypes -lObjCLibraryForwardDeclaringCompleteSwiftTypes -o %t/a.out +// RUN: %target-run %t/a.out + +// REQUIRES: objc_interop +// REQUIRES: executable_test + +import CompleteSwiftTypes +import ObjCLibraryForwardDeclaringCompleteSwiftTypes + +let placeholderInstanceForNativeObjCInterfaceShadowedProtocol = returnANativeObjCClassShadowedProtocol() diff --git a/test/IDE/print_clang_ObjectiveC.swift b/test/IDE/print_clang_ObjectiveC.swift index a903207110ce1..aa7a2eb15a9a7 100644 --- a/test/IDE/print_clang_ObjectiveC.swift +++ b/test/IDE/print_clang_ObjectiveC.swift @@ -1,6 +1,6 @@ // RUN: %empty-directory(%t) -// RUN: %target-swift-ide-test -print-module -source-filename %s -module-to-print=ObjectiveC.NSObject -function-definitions=false > %t/ObjectiveC.NSObject.printed.txt +// RUN: %target-swift-ide-test -swift-version 5 -print-module -source-filename %s -module-to-print=ObjectiveC.NSObject -function-definitions=false > %t/ObjectiveC.NSObject.printed.txt // RUN: %FileCheck -input-file %t/ObjectiveC.NSObject.printed.txt %s // RUN: %FileCheck -input-file %t/ObjectiveC.NSObject.printed.txt -check-prefix=NEGATIVE -check-prefix=NEGATIVE-WITHOUT-FORWARD-DECLS %s diff --git a/test/SourceKit/CursorInfo/Inputs/custom-modules/ForwardDeclarations/ForwardDeclaredInterfaceFoo.h b/test/SourceKit/CursorInfo/Inputs/custom-modules/ForwardDeclarations/ForwardDeclaredInterfaceFoo.h new file mode 100644 index 0000000000000..4f6c975b8e2f7 --- /dev/null +++ b/test/SourceKit/CursorInfo/Inputs/custom-modules/ForwardDeclarations/ForwardDeclaredInterfaceFoo.h @@ -0,0 +1 @@ +@class Foo diff --git a/test/SourceKit/CursorInfo/Inputs/custom-modules/ForwardDeclarations/ProtocolFoo.h b/test/SourceKit/CursorInfo/Inputs/custom-modules/ForwardDeclarations/ProtocolFoo.h new file mode 100644 index 0000000000000..51a36cc673f76 --- /dev/null +++ b/test/SourceKit/CursorInfo/Inputs/custom-modules/ForwardDeclarations/ProtocolFoo.h @@ -0,0 +1,2 @@ +@protocol Foo +{ -(void)sayHello; } diff --git a/test/SourceKit/CursorInfo/Inputs/custom-modules/ForwardDeclarations/module.modulemap b/test/SourceKit/CursorInfo/Inputs/custom-modules/ForwardDeclarations/module.modulemap new file mode 100644 index 0000000000000..2ea4cc841ef7a --- /dev/null +++ b/test/SourceKit/CursorInfo/Inputs/custom-modules/ForwardDeclarations/module.modulemap @@ -0,0 +1,7 @@ +module ProtocolFoo { + header "ProtocolFoo.h" +} + +module ForwardDeclaredInterfaceFoo { + header "ForwardDeclaredInterfaceFoo.h" +} diff --git a/test/SourceKit/Misc/importing_objc_forward_declarations.swift b/test/SourceKit/Misc/importing_objc_forward_declarations.swift new file mode 100644 index 0000000000000..0e4dbe8985d93 --- /dev/null +++ b/test/SourceKit/Misc/importing_objc_forward_declarations.swift @@ -0,0 +1,13 @@ +// RUN: %sourcekitd-test -req=diags %s -- -Xfrontend -enable-objc-interop -swift-version 6 -I %S/Inputs/custom-modules/ForwardDeclarations/ %s + +import ProtocolFoo +import ForwardDeclaredInterfaceFoo + +class Bar : Foo { + func sayHello() { + print("Say hello") + } +} + +let bar = Bar() +bar.sayHello()