diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index f6392dfbc7fe9..6e5123b586655 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -2286,32 +2286,32 @@ ERROR(pattern_type_not_usable_from_inline,none, "type referenced from a '@usableFromInline' " "%select{%select{variable|constant}0|property}1 " "must be '@usableFromInline' or public", - (bool, bool)) + (bool, bool, /*ignored*/bool)) WARNING(pattern_type_not_usable_from_inline_warn,none, "type referenced from a '@usableFromInline' " "%select{%select{variable|constant}0|property}1 " "should be '@usableFromInline' or public", - (bool, bool)) + (bool, bool, /*ignored*/bool)) ERROR(pattern_type_not_usable_from_inline_frozen,none, - "type referenced from a stored property in a '@frozen' struct must " - "be '@usableFromInline' or public", - (/*ignored*/bool, /*ignored*/bool)) + "type referenced from a stored property in a '@frozen%select{| package}2' struct must " + "be '@usableFromInline'%select{ or public|, public, or package}2", + (/*ignored*/bool, /*ignored*/bool, bool)) ERROR(pattern_type_not_usable_from_inline_inferred,none, "type referenced from a '@usableFromInline' " "%select{%select{variable|constant}0|property}1 " "with inferred type %2 " "must be '@usableFromInline' or public", - (bool, bool, Type)) + (bool, bool, Type, /*ignored*/bool)) WARNING(pattern_type_not_usable_from_inline_inferred_warn,none, "type referenced from a '@usableFromInline' " "%select{%select{variable|constant}0|property}1 " "with inferred type %2 " "should be '@usableFromInline' or public", - (bool, bool, Type)) + (bool, bool, Type, /*ignored*/bool)) ERROR(pattern_type_not_usable_from_inline_inferred_frozen,none, "type referenced from a stored property with inferred type %2 in a " - "'@frozen' struct must be '@usableFromInline' or public", - (/*ignored*/bool, /*ignored*/bool, Type)) + "'@frozen%select{| package}3' struct must be '@usableFromInline'%select{ or public|, public, or package}3", + (/*ignored*/bool, /*ignored*/bool, Type, bool)) ERROR(pattern_binds_no_variables,none, "%select{property|global variable}0 declaration does not bind any " @@ -3626,6 +3626,8 @@ ERROR(decl_from_hidden_module,none, "cannot use %kind0 %select{here|as property wrapper here|" "as result builder here|" "in an extension with public or '@usableFromInline' members|" + "in an extension with conditional conformances|" + "in an extension with public, package, or '@usableFromInline' members|" "in an extension with conditional conformances}1; " "%select{%2 has been imported as implementation-only|" "it is an SPI imported from %2|" @@ -3633,7 +3635,9 @@ ERROR(decl_from_hidden_module,none, "%2 was imported for SPI only|" "%2 was not imported by this file|" "C++ types from imported module %2 do not support library evolution|" - "%2 was not imported publicly}3", + "%2 was not imported publicly|" + "%2 was imported as package}3" + "%select{||||| or as package| or as package}1", (const Decl *, unsigned, Identifier, unsigned)) ERROR(typealias_desugars_to_type_from_hidden_module,none, "%0 aliases '%1.%2' and cannot be used %select{here|" @@ -3647,7 +3651,8 @@ ERROR(typealias_desugars_to_type_from_hidden_module,none, "%4 was imported for SPI only|" "%4 was not imported by this file|" "C++ types from imported module %4 do not support library evolution|" - "%4 was not imported publicly}5", + "%4 was not imported publicly|" + "%4 was imported as package}5", (const TypeAliasDecl *, StringRef, StringRef, unsigned, Identifier, unsigned)) ERROR(conformance_from_implementation_only_module,none, "cannot use conformance of %0 to %1 %select{here|as property wrapper here|" @@ -3660,7 +3665,8 @@ ERROR(conformance_from_implementation_only_module,none, "%3 was imported for SPI only|" "%3 was not imported by this file|" "C++ types from imported module %3 do not support library evolution|" - "%3 was not imported publicly}4", + "%3 was not imported publicly|" + "%3 was imported as package}4", (Type, Identifier, unsigned, Identifier, unsigned)) NOTE(assoc_conformance_from_implementation_only_module,none, "in associated type %0 (inferred as %1)", (Type, Type)) @@ -6884,7 +6890,8 @@ ERROR(inlinable_decl_ref_from_hidden_module, "%2 was imported for SPI only|" "%2 was not imported by this file|" "C++ APIs from imported module %2 do not support library evolution|" - "%2 was not imported publicly}3", + "%2 was not imported publicly|" + "%2 was imported as package}3", (const ValueDecl *, unsigned, Identifier, unsigned)) WARNING(inlinable_decl_ref_from_hidden_module_warn, @@ -6902,7 +6909,8 @@ ERROR(inlinable_typealias_desugars_to_type_from_hidden_module, "%4 was imported for SPI only|" "%4 was not imported by this file|" "C++ types from imported module %4 do not support library evolution|" - "%4 was not imported publicly}5", + "%4 was not imported publicly|" + "%4 was imported as package}5", (const TypeAliasDecl *, StringRef, StringRef, unsigned, Identifier, unsigned)) NOTE(missing_import_inserted, @@ -6916,8 +6924,8 @@ ERROR(availability_macro_in_inlinable, none, #undef FRAGILE_FUNC_KIND NOTE(resilience_decl_declared_here, - none, "%kind0 is not '@usableFromInline' or public", - (const ValueDecl *)) + none, "%kind0 is not '@usableFromInline'%select{ or public|, public, or package}1", + (const ValueDecl *, bool)) ERROR(class_designated_init_inlinable_resilient,none, "initializer for class %0 is " diff --git a/include/swift/AST/SourceFile.h b/include/swift/AST/SourceFile.h index 81fea1f60b5aa..30679e23fea8a 100644 --- a/include/swift/AST/SourceFile.h +++ b/include/swift/AST/SourceFile.h @@ -431,6 +431,10 @@ class SourceFile final : public FileUnit { void setImportUsedPreconcurrency( AttributedImport import); + /// True if the highest access level of the declarations referencing + /// this import in signature or inlinable code is internal or less. + bool isMaxAccessLevelUsingImportInternal(AttributedImport import) const; + /// Return the highest access level of the declarations referencing /// this import in signature or inlinable code. AccessLevel diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 7731ad34312c0..46263924ce01c 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -2324,7 +2324,7 @@ bool VarDecl::isLayoutExposedToClients() const { auto nominalAccess = parent->getFormalAccessScope(/*useDC=*/nullptr, /*treatUsableFromInlineAsPublic=*/true); - if (!nominalAccess.isPublic()) return false; + if (!nominalAccess.isPublicOrPackage()) return false; if (!parent->getAttrs().hasAttribute() && !parent->getAttrs().hasAttribute()) @@ -4571,8 +4571,10 @@ bool ValueDecl::isMoreVisibleThan(ValueDecl *other) const { if (scope.isPublic()) return !otherScope.isPublic(); + else if (scope.isPackage()) + return !otherScope.isPublicOrPackage(); else if (scope.isInternal()) - return !otherScope.isPublic() && !otherScope.isInternal(); + return !otherScope.isPublicOrPackage() && !otherScope.isInternal(); else return false; } diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp index 0139a4b16a97d..52d0f09ab0fc6 100644 --- a/lib/AST/DeclContext.cpp +++ b/lib/AST/DeclContext.cpp @@ -467,7 +467,7 @@ swift::FragileFunctionKindRequest::evaluate(Evaluator &evaluator, auto effectiveAccess = VD->getFormalAccessScope(/*useDC=*/nullptr, /*treatUsableFromInlineAsPublic=*/true); - if (effectiveAccess.isPublic()) { + if (effectiveAccess.isPublicOrPackage()) { return {FragileFunctionKind::DefaultArgument}; } @@ -499,7 +499,7 @@ swift::FragileFunctionKindRequest::evaluate(Evaluator &evaluator, // If the function is not externally visible, we will not be serializing // its body. - if (!funcAccess.isPublic()) { + if (!funcAccess.isPublicOrPackage()) { return {FragileFunctionKind::None}; } diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp index fda4b7b32ee49..3dde45c0d7d92 100644 --- a/lib/AST/Module.cpp +++ b/lib/AST/Module.cpp @@ -2623,6 +2623,12 @@ void SourceFile::setImportUsedPreconcurrency( PreconcurrencyImportsUsed.insert(import); } +bool SourceFile::isMaxAccessLevelUsingImportInternal( + AttributedImport import) const { + auto maxLevel = getMaxAccessLevelUsingImport(import.module.importedModule); + return maxLevel < AccessLevel::Package; +} + AccessLevel SourceFile::getMaxAccessLevelUsingImport( const ModuleDecl *mod) const { diff --git a/lib/Sema/ResilienceDiagnostics.cpp b/lib/Sema/ResilienceDiagnostics.cpp index d3915ad77a3bf..681d1e0ee4c48 100644 --- a/lib/Sema/ResilienceDiagnostics.cpp +++ b/lib/Sema/ResilienceDiagnostics.cpp @@ -66,17 +66,22 @@ bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc, ImportAccessLevel problematicImport = D->getImportAccessFrom(DC); if (problematicImport.has_value()) { auto SF = DC->getParentSourceFile(); - if (SF) - SF->registerAccessLevelUsingImport(problematicImport.value(), - AccessLevel::Public); - - if (Context.LangOpts.EnableModuleApiImportRemarks) { - ModuleDecl *importedVia = problematicImport->module.importedModule, - *sourceModule = D->getModuleContext(); - Context.Diags.diagnose(loc, diag::module_api_import, - D, importedVia, sourceModule, - importedVia == sourceModule, - /*isImplicit*/false); + if (SF) { + // The max used access level previously registered might be Package, + // in which case, don't reset it to Public here; this ensures proper + // diags between public and package. + if (SF->isMaxAccessLevelUsingImportInternal(problematicImport.value())) + SF->registerAccessLevelUsingImport(problematicImport.value(), + AccessLevel::Public); + + if (Context.LangOpts.EnableModuleApiImportRemarks) { + ModuleDecl *importedVia = problematicImport->module.importedModule, + *sourceModule = D->getModuleContext(); + Context.Diags.diagnose(loc, diag::module_api_import, + D, importedVia, sourceModule, + importedVia == sourceModule, + /*isImplicit*/false); + } } } @@ -100,6 +105,16 @@ bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc, } DowngradeToWarning downgradeToWarning = DowngradeToWarning::No; + // Don't change the order of the getDisallowedOriginKind call; + // it can reset downgradeToWarning to NO so needs to be called here. + auto originKind = getDisallowedOriginKind(D, where, downgradeToWarning); + // For a default argument or property initializer, package type is + // allowed at the use site with package access scope. + auto allowedForPkgCtx = false; + if (originKind == DisallowedOriginKind::None || + originKind == DisallowedOriginKind::PackageImport) { + allowedForPkgCtx = where.isPackage() && declAccessScope.isPackage(); + } // Swift 4.2 did not perform any checks for type aliases. if (isa(D)) { @@ -119,15 +134,17 @@ bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc, if (isa(DC) && !Context.isSwiftVersionAtLeast(6)) downgradeToWarning = DowngradeToWarning::Yes; - auto diagID = diag::resilience_decl_unavailable; - if (downgradeToWarning == DowngradeToWarning::Yes) - diagID = diag::resilience_decl_unavailable_warn; + if (!allowedForPkgCtx) { + auto diagID = diag::resilience_decl_unavailable; + if (downgradeToWarning == DowngradeToWarning::Yes) + diagID = diag::resilience_decl_unavailable_warn; - AccessLevel diagAccessLevel = declAccessScope.accessLevelForDiagnostics(); - Context.Diags.diagnose(loc, diagID, D, diagAccessLevel, - fragileKind.getSelector()); + AccessLevel diagAccessLevel = declAccessScope.accessLevelForDiagnostics(); + Context.Diags.diagnose(loc, diagID, D, diagAccessLevel, + fragileKind.getSelector()); - Context.Diags.diagnose(D, diag::resilience_decl_declared_here, D); + Context.Diags.diagnose(D, diag::resilience_decl_declared_here, D, allowedForPkgCtx); + } if (problematicImport.has_value() && problematicImport->accessLevel < D->getFormalAccess()) { @@ -156,10 +173,14 @@ static bool diagnoseTypeAliasDeclRefExportability(SourceLoc loc, where.getDeclContext()); if (problematicImport.has_value()) { auto SF = where.getDeclContext()->getParentSourceFile(); - if (SF) - SF->registerAccessLevelUsingImport(problematicImport.value(), - AccessLevel::Public); - + if (SF) { + // The max used access level previously registered might be Package, + // in which case, don't reset it to Public here; this ensures proper + // diags between public and package. + if (SF->isMaxAccessLevelUsingImportInternal(problematicImport.value())) + SF->registerAccessLevelUsingImport(problematicImport.value(), + AccessLevel::Public); + } if (ctx.LangOpts.EnableModuleApiImportRemarks) { ModuleDecl *importedVia = problematicImport->module.importedModule, *sourceModule = D->getModuleContext(); @@ -186,7 +207,8 @@ static bool diagnoseTypeAliasDeclRefExportability(SourceLoc loc, auto definingModule = D->getModuleContext(); auto fragileKind = where.getFragileFunctionKind(); bool warnPreSwift6 = originKind != DisallowedOriginKind::SPIOnly && - originKind != DisallowedOriginKind::NonPublicImport; + originKind != DisallowedOriginKind::PackageImport && + originKind != DisallowedOriginKind::InternalOrLessImport; if (fragileKind.kind == FragileFunctionKind::None) { auto reason = where.getExportabilityReason(); ctx.Diags @@ -211,7 +233,8 @@ static bool diagnoseTypeAliasDeclRefExportability(SourceLoc loc, addMissingImport(loc, D, where); // If limited by an import, note which one. - if (originKind == DisallowedOriginKind::NonPublicImport) { + if (originKind == DisallowedOriginKind::InternalOrLessImport || + originKind == DisallowedOriginKind::PackageImport) { const DeclContext *DC = where.getDeclContext(); ImportAccessLevel limitImport = D->getImportAccessFrom(DC); assert(limitImport.has_value() && @@ -242,22 +265,31 @@ static bool diagnoseValueDeclRefExportability(SourceLoc loc, const ValueDecl *D, ImportAccessLevel import = D->getImportAccessFrom(DC); if (import.has_value() && reason.has_value()) { auto SF = DC->getParentSourceFile(); - if (SF) - SF->registerAccessLevelUsingImport(import.value(), - AccessLevel::Public); + if (SF) { + // The max used access level previously registered might be Package, + // in which case, don't reset it to Public here; this ensures proper + // diags between public and package. + if (SF->isMaxAccessLevelUsingImportInternal(import.value())) + SF->registerAccessLevelUsingImport(import.value(), + AccessLevel::Public); + } } // Access levels from imports are reported with the others access levels. // Except for extensions, we report them here. - if (originKind == DisallowedOriginKind::NonPublicImport && - reason != ExportabilityReason::ExtensionWithPublicMembers && - reason != ExportabilityReason::ExtensionWithConditionalConformances) - return false; + if (originKind == DisallowedOriginKind::InternalOrLessImport || + originKind == DisallowedOriginKind::PackageImport) { + if (reason != ExportabilityReason::ExtensionWithPublicMembers && + reason != ExportabilityReason::ExtensionWithPackageMembers && + reason != ExportabilityReason::ExtensionWithConditionalConformances && + reason != ExportabilityReason::ExtensionWithPackageConditionalConformances) + return false; + } if (ctx.LangOpts.EnableModuleApiImportRemarks && import.has_value() && where.isExported() && reason != ExportabilityReason::General && - originKind != DisallowedOriginKind::NonPublicImport) { + originKind != DisallowedOriginKind::InternalOrLessImport) { // These may be reported twice, for the Type and for the TypeRepr. ModuleDecl *importedVia = import->module.importedModule, *sourceModule = D->getModuleContext(); @@ -270,6 +302,14 @@ static bool diagnoseValueDeclRefExportability(SourceLoc loc, const ValueDecl *D, if (originKind == DisallowedOriginKind::None) return false; + // No diags needed for extensions with package members or + // conformance to types with package access scope. + if (originKind == DisallowedOriginKind::PackageImport) { + if (reason == ExportabilityReason::ExtensionWithPackageMembers || + reason == ExportabilityReason::ExtensionWithPackageConditionalConformances) + return false; + } + auto diagName = D->getName(); if (auto accessor = dyn_cast(D)) { // Only diagnose accessors if their disallowed origin kind differs from @@ -313,7 +353,8 @@ static bool diagnoseValueDeclRefExportability(SourceLoc loc, const ValueDecl *D, } // If limited by an import, note which one. - if (originKind == DisallowedOriginKind::NonPublicImport) { + if (originKind == DisallowedOriginKind::InternalOrLessImport || + originKind == DisallowedOriginKind::PackageImport) { assert(import.has_value() && import->accessLevel < AccessLevel::Public && "The import should still be non-public"); @@ -362,10 +403,14 @@ TypeChecker::diagnoseConformanceExportability(SourceLoc loc, ImportAccessLevel problematicImport = ext->getImportAccessFrom(where.getDeclContext()); if (problematicImport.has_value()) { auto SF = where.getDeclContext()->getParentSourceFile(); - if (SF) - SF->registerAccessLevelUsingImport(problematicImport.value(), - AccessLevel::Public); - + if (SF) { + // The max used access level previously registered might be Package, + // in which case, don't reset it to Public here; this ensures proper + // diags between public and package. + if (SF->isMaxAccessLevelUsingImportInternal(problematicImport.value())) + SF->registerAccessLevelUsingImport(problematicImport.value(), + AccessLevel::Public); + } if (ctx.LangOpts.EnableModuleApiImportRemarks) { ModuleDecl *importedVia = problematicImport->module.importedModule, *sourceModule = ext->getModuleContext(); @@ -392,7 +437,8 @@ TypeChecker::diagnoseConformanceExportability(SourceLoc loc, static_cast(originKind)) .warnUntilSwiftVersionIf((warnIfConformanceUnavailablePreSwift6 && originKind != DisallowedOriginKind::SPIOnly && - originKind != DisallowedOriginKind::NonPublicImport) || + originKind != DisallowedOriginKind::PackageImport && + originKind != DisallowedOriginKind::InternalOrLessImport) || originKind == DisallowedOriginKind::MissingImport, 6); @@ -401,7 +447,8 @@ TypeChecker::diagnoseConformanceExportability(SourceLoc loc, addMissingImport(loc, ext, where); // If limited by an import, note which one. - if (originKind == DisallowedOriginKind::NonPublicImport) { + if (originKind == DisallowedOriginKind::InternalOrLessImport || + originKind == DisallowedOriginKind::PackageImport) { const DeclContext *DC = where.getDeclContext(); ImportAccessLevel limitImport = ext->getImportAccessFrom(DC); assert(limitImport.has_value() && diff --git a/lib/Sema/TypeCheckAccess.cpp b/lib/Sema/TypeCheckAccess.cpp index db37064b5feec..91361a33c6b61 100644 --- a/lib/Sema/TypeCheckAccess.cpp +++ b/lib/Sema/TypeCheckAccess.cpp @@ -1424,13 +1424,16 @@ class UsableFromInlineChecker : public AccessControlCheckerBase, ImportAccessLevel importLimit) { auto &Ctx = theVar->getASTContext(); auto diagID = diag::pattern_type_not_usable_from_inline_inferred; + auto hasPackageScope = false; if (fixedLayoutStructContext) { diagID = diag::pattern_type_not_usable_from_inline_inferred_frozen; + hasPackageScope = fixedLayoutStructContext->getFormalAccessScope(nullptr, true).isPackage(); } else if (!Ctx.isSwiftVersionAtLeast(5)) { diagID = diag::pattern_type_not_usable_from_inline_inferred_warn; } Ctx.Diags.diagnose(NP->getLoc(), diagID, theVar->isLet(), - isTypeContext, theVar->getInterfaceType()); + isTypeContext, theVar->getInterfaceType(), + hasPackageScope); noteLimitingImport(theVar, importLimit, complainRepr); }); } @@ -1463,12 +1466,14 @@ class UsableFromInlineChecker : public AccessControlCheckerBase, ImportAccessLevel importLimit) { auto &Ctx = anyVar->getASTContext(); auto diagID = diag::pattern_type_not_usable_from_inline; - if (fixedLayoutStructContext) + auto hasPackageScope = false; + if (fixedLayoutStructContext) { diagID = diag::pattern_type_not_usable_from_inline_frozen; - else if (!Ctx.isSwiftVersionAtLeast(5)) + hasPackageScope = fixedLayoutStructContext->getFormalAccessScope(nullptr, true).isPackage(); + } else if (!Ctx.isSwiftVersionAtLeast(5)) diagID = diag::pattern_type_not_usable_from_inline_warn; auto diag = Ctx.Diags.diagnose(TP->getLoc(), diagID, anyVar->isLet(), - isTypeContext); + isTypeContext, hasPackageScope); highlightOffendingType(diag, complainRepr); noteLimitingImport(anyVar, importLimit, complainRepr); }); @@ -2011,9 +2016,20 @@ swift::getDisallowedOriginKind(const Decl *decl, // Report non-public import last as it can be ignored by the caller. // See \c diagnoseValueDeclRefExportability. auto importSource = decl->getImportAccessFrom(where.getDeclContext()); - if (importSource.has_value() && - importSource->accessLevel < AccessLevel::Public) - return DisallowedOriginKind::NonPublicImport; + if (importSource.has_value()) { + if (importSource->accessLevel == AccessLevel::Package) { + auto kind = where.getFragileFunctionKind().kind; + if (where.isPackage() && + (kind == FragileFunctionKind::None || + kind == FragileFunctionKind::DefaultArgument || + kind == FragileFunctionKind::PropertyInitializer)) + return DisallowedOriginKind::None; + return DisallowedOriginKind::PackageImport; + } + + if (importSource->accessLevel < AccessLevel::Package) + return DisallowedOriginKind::InternalOrLessImport; + } return DisallowedOriginKind::None; } @@ -2336,13 +2352,19 @@ class DeclAvailabilityChecker : public DeclVisitor { } void checkConstrainedExtensionRequirements(ExtensionDecl *ED, - bool hasExportedMembers) { + bool hasExportedPublicMembers, + bool hasExportedPackageMembers, + bool hasPackageInheritance) { if (!ED->getTrailingWhereClause()) return; - ExportabilityReason reason = - hasExportedMembers ? ExportabilityReason::ExtensionWithPublicMembers - : ExportabilityReason::ExtensionWithConditionalConformances; + ExportabilityReason reason = ExportabilityReason::ExtensionWithConditionalConformances; + if (hasExportedPublicMembers) + reason = ExportabilityReason::ExtensionWithPublicMembers; + else if (hasExportedPackageMembers) + reason = ExportabilityReason::ExtensionWithPackageMembers; + else if (hasPackageInheritance) + reason = ExportabilityReason::ExtensionWithPackageConditionalConformances; forAllRequirementTypes(ED, [&](Type type, TypeRepr *typeRepr) { checkType(type, typeRepr, ED, reason); @@ -2369,23 +2391,61 @@ class DeclAvailabilityChecker : public DeclVisitor { // 2) If the extension contains exported members, the as-written // extended type should be exportable. - bool hasExportedMembers = llvm::any_of(ED->getMembers(), + bool hasExportedPublicMembers = llvm::any_of(ED->getMembers(), + [](const Decl *member) -> bool { + auto *valueMember = dyn_cast(member); + if (!valueMember) + return false; + return isExported(valueMember) && + !valueMember->getFormalAccessScope(nullptr, true).isPackage(); + + }); + + // Keep track of package (exported) members separately from public + // members for diags purposes. + bool hasExportedPackageMembers = llvm::any_of(ED->getMembers(), [](const Decl *member) -> bool { auto *valueMember = dyn_cast(member); if (!valueMember) return false; - return isExported(valueMember); + return isExported(valueMember) && + valueMember->getFormalAccessScope(nullptr, true).isPackage(); + }); + + bool hasExportedMembers = hasExportedPublicMembers || hasExportedPackageMembers; + + // Keep track of inheritance with package access level for diags purposes. + bool hasPackageInheritance = llvm::any_of(ED->getInherited().getEntries(), + [](const InheritedEntry entry) -> bool { + if (!entry.wasValidated()) + return false; + auto enType = entry.getType(); + if (enType) { + if (const auto *ProtoD = dyn_cast_or_null(enType->getAnyNominal())) { + if (ProtoD && isExported(ProtoD) && + ProtoD->getFormalAccessScope(nullptr, true).isPackage()) + return true; + } + } + return false; }); Where = wasWhere.withExported(hasExportedMembers); - checkType(ED->getExtendedType(), ED->getExtendedTypeRepr(), ED, - ExportabilityReason::ExtensionWithPublicMembers); + + ExportabilityReason reason = ExportabilityReason::ExtensionWithPublicMembers; + if (!hasExportedPublicMembers && hasExportedPackageMembers) + reason = ExportabilityReason::ExtensionWithPackageMembers; + + checkType(ED->getExtendedType(), ED->getExtendedTypeRepr(), + ED, reason); // 3) If the extension contains exported members or defines conformances, // the 'where' clause must only name exported types. Where = wasWhere.withExported(hasExportedMembers || !ED->getInherited().empty()); - checkConstrainedExtensionRequirements(ED, hasExportedMembers); + checkConstrainedExtensionRequirements(ED, hasExportedPublicMembers, + hasExportedPackageMembers, + hasPackageInheritance); if (!hasExportedMembers && !ED->getInherited().empty()) { @@ -2397,10 +2457,11 @@ class DeclAvailabilityChecker : public DeclVisitor { ImportAccessLevel import = extendedType->getImportAccessFrom(DC); if (import.has_value()) { auto SF = DC->getParentSourceFile(); - if (SF) - SF->registerAccessLevelUsingImport(import.value(), - AccessLevel::Public); - + if (SF) { + if (SF->isMaxAccessLevelUsingImportInternal(import.value())) + SF->registerAccessLevelUsingImport(import.value(), + AccessLevel::Public); + } auto &ctx = DC->getASTContext(); if (ctx.LangOpts.EnableModuleApiImportRemarks) { ModuleDecl *importedVia = import->module.importedModule, @@ -2550,49 +2611,6 @@ void swift::diagnoseUnnecessaryPublicImports(SourceFile &SF) { } } -/// Register the type extended by \p ED as being used in a package decl if -/// any member is a package decl. This patches a hole in the warnings on -/// superfluously public imports which usually relies on exportability checking -/// that is not currently executed for package decls. -void registerPackageAccessForPackageExtendedType(ExtensionDecl *ED) { - auto extendedType = ED->getExtendedNominal(); - if (!extendedType) - return; - - bool hasPackageMembers = llvm::any_of(ED->getMembers(), - [](const Decl *member) -> bool { - auto *VD = dyn_cast(member); - if (!VD) - return false; - - AccessScope accessScope = - VD->getFormalAccessScope(nullptr, - /*treatUsableFromInlineAsPublic*/true); - return accessScope.isPackage(); - }); - if (!hasPackageMembers) - return; - - DeclContext *DC = ED->getDeclContext(); - ImportAccessLevel import = extendedType->getImportAccessFrom(DC); - if (import.has_value()) { - auto SF = DC->getParentSourceFile(); - if (SF) - SF->registerAccessLevelUsingImport(import.value(), - AccessLevel::Package); - - auto &ctx = DC->getASTContext(); - if (ctx.LangOpts.EnableModuleApiImportRemarks) { - ModuleDecl *importedVia = import->module.importedModule, - *sourceModule = ED->getModuleContext(); - ED->diagnose(diag::module_api_import, - ED, importedVia, sourceModule, - importedVia == sourceModule, - /*isImplicit*/false); - } - } -} - void swift::checkAccessControl(Decl *D) { if (isa(D) || isa(D)) { bool allowInlineable = @@ -2601,7 +2619,6 @@ void swift::checkAccessControl(Decl *D) { UsableFromInlineChecker().visit(D); } else if (auto *ED = dyn_cast(D)) { checkExtensionGenericParamAccess(ED); - registerPackageAccessForPackageExtendedType(ED); } if (isa(D)) diff --git a/lib/Sema/TypeCheckAccess.h b/lib/Sema/TypeCheckAccess.h index 6291c1de9d419..b448da2fac608 100644 --- a/lib/Sema/TypeCheckAccess.h +++ b/lib/Sema/TypeCheckAccess.h @@ -47,7 +47,8 @@ enum class DisallowedOriginKind : uint8_t { SPIOnly, MissingImport, FragileCxxAPI, - NonPublicImport, + InternalOrLessImport, + PackageImport, None }; diff --git a/lib/Sema/TypeCheckAvailability.cpp b/lib/Sema/TypeCheckAvailability.cpp index a6ab196393e04..2ae5c6333c10a 100644 --- a/lib/Sema/TypeCheckAvailability.cpp +++ b/lib/Sema/TypeCheckAvailability.cpp @@ -44,10 +44,12 @@ using namespace swift; ExportContext::ExportContext( DeclContext *DC, AvailabilityContext runningOSVersion, - FragileFunctionKind kind, bool spi, bool exported, bool implicit, - bool deprecated, std::optional unavailablePlatformKind) + FragileFunctionKind kind, bool spi, bool isPackage, + bool exported, bool implicit, bool deprecated, + std::optional unavailablePlatformKind) : DC(DC), RunningOSVersion(runningOSVersion), FragileKind(kind) { SPI = spi; + IsPackage = isPackage; Exported = exported; Implicit = implicit; Deprecated = deprecated; @@ -72,7 +74,7 @@ bool swift::isExported(const ValueDecl *VD) { AccessScope accessScope = VD->getFormalAccessScope(nullptr, /*treatUsableFromInlineAsPublic*/true); - if (accessScope.isPublic()) + if (accessScope.isPublicOrPackage()) return true; // Is this a stored property in a @frozen struct or class? @@ -83,13 +85,13 @@ bool swift::isExported(const ValueDecl *VD) { return false; } -static bool hasConformancesToPublicProtocols(const ExtensionDecl *ED) { +static bool hasConformancesToPublicOrPackageProtocols(const ExtensionDecl *ED) { auto protocols = ED->getLocalProtocols(ConformanceLookupKind::OnlyExplicit); for (const ProtocolDecl *PD : protocols) { AccessScope scope = PD->getFormalAccessScope(/*useDC*/ nullptr, /*treatUsableFromInlineAsPublic*/ true); - if (scope.isPublic()) + if (scope.isPublicOrPackage()) return true; } @@ -111,7 +113,7 @@ bool swift::isExported(const ExtensionDecl *ED) { // If the extension declares a conformance to a public protocol then the // extension is exported. - if (hasConformancesToPublicProtocols(ED)) + if (hasConformancesToPublicOrPackageProtocols(ED)) return true; return false; @@ -184,13 +186,20 @@ static void forEachOuterDecl(DeclContext *DC, Fn fn) { } static void -computeExportContextBits(ASTContext &Ctx, Decl *D, bool *spi, bool *implicit, - bool *deprecated, +computeExportContextBits(ASTContext &Ctx, Decl *D, + bool *spi, bool *isPackage, + bool *implicit, bool *deprecated, std::optional *unavailablePlatformKind) { if (D->isSPI() || D->isAvailableAsSPI()) *spi = true; + if (auto VD = dyn_cast(D)) { + *isPackage = VD->getFormalAccessScope(nullptr, true).isPackage(); + } else if (auto ED = dyn_cast(D)) { + *isPackage = ED->getDefaultAccessLevel() == AccessLevel::Package; + } + // Defer bodies are desugared to an implicit closure expression. We need to // dilute the meaning of "implicit" to make sure we're still checking // availability inside of defer statements. @@ -208,8 +217,8 @@ computeExportContextBits(ASTContext &Ctx, Decl *D, bool *spi, bool *implicit, if (auto *PBD = dyn_cast(D)) { for (unsigned i = 0, e = PBD->getNumPatternEntries(); i < e; ++i) { if (auto *VD = PBD->getAnchoringVarDecl(i)) - computeExportContextBits(Ctx, VD, spi, implicit, deprecated, - unavailablePlatformKind); + computeExportContextBits(Ctx, VD, spi, isPackage, implicit, + deprecated, unavailablePlatformKind); } } } @@ -224,23 +233,25 @@ ExportContext ExportContext::forDeclSignature(Decl *D) { ? AvailabilityContext::alwaysAvailable() : TypeChecker::overApproximateAvailabilityAtLocation(D->getLoc(), DC)); bool spi = Ctx.LangOpts.LibraryLevel == LibraryLevel::SPI; + bool isPackage = false; bool implicit = false; bool deprecated = false; std::optional unavailablePlatformKind; - computeExportContextBits(Ctx, D, &spi, &implicit, &deprecated, - &unavailablePlatformKind); + computeExportContextBits(Ctx, D, &spi, &isPackage, &implicit, + &deprecated, &unavailablePlatformKind); + forEachOuterDecl(D->getDeclContext(), [&](Decl *D) { computeExportContextBits(Ctx, D, - &spi, &implicit, &deprecated, - &unavailablePlatformKind); + &spi, &isPackage, &implicit, + &deprecated, &unavailablePlatformKind); }); bool exported = ::isExported(D); return ExportContext(DC, runningOSVersion, fragileKind, - spi, exported, implicit, deprecated, - unavailablePlatformKind); + spi, isPackage, exported, implicit, + deprecated, unavailablePlatformKind); } ExportContext ExportContext::forFunctionBody(DeclContext *DC, SourceLoc loc) { @@ -255,19 +266,20 @@ ExportContext ExportContext::forFunctionBody(DeclContext *DC, SourceLoc loc) { bool spi = Ctx.LangOpts.LibraryLevel == LibraryLevel::SPI; bool implicit = false; bool deprecated = false; + bool isPackage = false; std::optional unavailablePlatformKind; forEachOuterDecl(DC, [&](Decl *D) { computeExportContextBits(Ctx, D, - &spi, &implicit, &deprecated, - &unavailablePlatformKind); + &spi, &isPackage, &implicit, + &deprecated, &unavailablePlatformKind); }); bool exported = false; return ExportContext(DC, runningOSVersion, fragileKind, - spi, exported, implicit, deprecated, - unavailablePlatformKind); + spi, isPackage, exported, implicit, + deprecated, unavailablePlatformKind); } ExportContext ExportContext::forConformance(DeclContext *DC, @@ -276,7 +288,7 @@ ExportContext ExportContext::forConformance(DeclContext *DC, auto where = forDeclSignature(DC->getInnermostDeclarationDeclContext()); where.Exported &= proto->getFormalAccessScope( - DC, /*usableFromInlineAsPublic*/true).isPublic(); + DC, /*usableFromInlineAsPublic*/true).isPublicOrPackage(); return where; } @@ -4466,7 +4478,7 @@ void swift::checkExplicitAvailability(Decl *decl) { return false; }); - auto hasProtocols = hasConformancesToPublicProtocols(extension); + auto hasProtocols = hasConformancesToPublicOrPackageProtocols(extension); if (!hasMembers && !hasProtocols) return; diff --git a/lib/Sema/TypeCheckAvailability.h b/lib/Sema/TypeCheckAvailability.h index c4e6fddfd57d2..6a527918c0231 100644 --- a/lib/Sema/TypeCheckAvailability.h +++ b/lib/Sema/TypeCheckAvailability.h @@ -72,7 +72,11 @@ enum class ExportabilityReason : unsigned { PropertyWrapper, ResultBuilder, ExtensionWithPublicMembers, - ExtensionWithConditionalConformances + ExtensionWithConditionalConformances, + // Exported members of extension can be `package`. + ExtensionWithPackageMembers, + // Exported inheritance type can be `package`. + ExtensionWithPackageConditionalConformances }; /// A description of the restrictions on what declarations can be referenced @@ -80,9 +84,12 @@ enum class ExportabilityReason : unsigned { /// /// We say a declaration is "exported" if all of the following holds: /// -/// - the declaration is `public` or `@usableFromInline` +/// - the declaration is `public` or `@usableFromInline` /// - the declaration is not `@_spi` /// - the declaration was not imported from an `@_implementationOnly` import +/// - the declaration is `package`; while treated as exported, the +/// scope is limited compared to `public` or `@usableFromInline`; +/// the `IsPackage` bit is set to track the scope. /// /// The "signature" of a declaration is the set of all types written in the /// declaration (such as function parameter and return types), but not @@ -105,6 +112,7 @@ class ExportContext { AvailabilityContext RunningOSVersion; FragileFunctionKind FragileKind; unsigned SPI : 1; + unsigned IsPackage : 1; unsigned Exported : 1; unsigned Deprecated : 1; unsigned Implicit : 1; @@ -113,7 +121,7 @@ class ExportContext { unsigned Reason : 3; ExportContext(DeclContext *DC, AvailabilityContext runningOSVersion, - FragileFunctionKind kind, bool spi, bool exported, + FragileFunctionKind kind, bool spi, bool isPackage, bool exported, bool implicit, bool deprecated, std::optional unavailablePlatformKind); @@ -168,6 +176,9 @@ class ExportContext { /// If true, the context is SPI and can reference SPI declarations. bool isSPI() const { return SPI; } + /// If true, the context has a package access scope. + bool isPackage() const { return IsPackage; } + /// If true, the context is exported and cannot reference SPI declarations /// or declarations from `@_implementationOnly` imports. bool isExported() const { return Exported; } diff --git a/test/Sema/access-level-import-classic-exportability.swift b/test/Sema/access-level-import-classic-exportability.swift index b08b900cb0e03..47857813a423c 100644 --- a/test/Sema/access-level-import-classic-exportability.swift +++ b/test/Sema/access-level-import-classic-exportability.swift @@ -52,9 +52,9 @@ public struct PrivateImportType { //--- Client.swift public import PublicLib package import PackageLib // expected-note 2 {{struct 'PackageImportType' imported as 'package' from 'PackageLib' here}} -internal import InternalLib // expected-note 2 {{struct 'InternalImportType' imported as 'internal' from 'InternalLib' here}} -fileprivate import FileprivateLib // expected-note 2 {{struct 'FileprivateImportType' imported as 'fileprivate' from 'FileprivateLib' here}} -private import PrivateLib // expected-note 2 {{struct 'PrivateImportType' imported as 'private' from 'PrivateLib' here}} +internal import InternalLib // expected-note 4 {{struct 'InternalImportType' imported as 'internal' from 'InternalLib' here}} +fileprivate import FileprivateLib // expected-note 4 {{struct 'FileprivateImportType' imported as 'fileprivate' from 'FileprivateLib' here}} +private import PrivateLib // expected-note 4 {{struct 'PrivateImportType' imported as 'private' from 'PrivateLib' here}} public protocol PublicConstrainedExtensionProto {} extension Array: PublicConstrainedExtensionProto where Element == PublicImportType {} @@ -87,8 +87,8 @@ extension PublicImportType { } public protocol PackageConstrainedExtensionProto {} -extension Array: PackageConstrainedExtensionProto where Element == PackageImportType {} // expected-error {{cannot use struct 'PackageImportType' in an extension with conditional conformances; 'PackageLib' was not imported publicly}} -extension PackageImportType { // expected-error {{cannot use struct 'PackageImportType' in an extension with public or '@usableFromInline' members; 'PackageLib' was not imported publicly}} +extension Array: PackageConstrainedExtensionProto where Element == PackageImportType {} // expected-error {{cannot use struct 'PackageImportType' in an extension with conditional conformances; 'PackageLib' was imported as package}} +extension PackageImportType { // expected-error {{cannot use struct 'PackageImportType' in an extension with public or '@usableFromInline' members; 'PackageLib' was imported as package}} public func publicMethod() {} } @@ -123,8 +123,8 @@ extension InternalImportType { // expected-error {{cannot use struct 'InternalIm } package protocol InternalConstrainedExtensionProtoInPackage {} -extension Array: InternalConstrainedExtensionProtoInPackage where Element == InternalImportType {} -extension InternalImportType { +extension Array: InternalConstrainedExtensionProtoInPackage where Element == InternalImportType {} // expected-error {{cannot use struct 'InternalImportType' in an extension with conditional conformances; 'InternalLib' was not imported publicly or as package}} +extension InternalImportType { // expected-error {{cannot use struct 'InternalImportType' in an extension with public, package, or '@usableFromInline' members; 'InternalLib' was not imported publicly or as package}} package func packageMethod() {} } @@ -153,8 +153,8 @@ extension FileprivateImportType { // expected-error {{cannot use struct 'Filepri } package protocol FileprivateConstrainedExtensionProtoInPackage {} -extension Array: FileprivateConstrainedExtensionProtoInPackage where Element == FileprivateImportType {} -extension FileprivateImportType { +extension Array: FileprivateConstrainedExtensionProtoInPackage where Element == FileprivateImportType {} // expected-error {{cannot use struct 'FileprivateImportType' in an extension with conditional conformances; 'FileprivateLib' was not imported publicly or as package}} +extension FileprivateImportType { // expected-error {{cannot use struct 'FileprivateImportType' in an extension with public, package, or '@usableFromInline' members; 'FileprivateLib' was not imported publicly or as package}} package func packageMethod() {} } @@ -183,8 +183,8 @@ extension PrivateImportType { // expected-error {{cannot use struct 'PrivateImpo } package protocol PrivateConstrainedExtensionProtoInPackage {} -extension Array: PrivateConstrainedExtensionProtoInPackage where Element == PrivateImportType {} -extension PrivateImportType { +extension Array: PrivateConstrainedExtensionProtoInPackage where Element == PrivateImportType {} // expected-error {{cannot use struct 'PrivateImportType' in an extension with conditional conformances; 'PrivateLib' was not imported publicly or as package}} +extension PrivateImportType { // expected-error {{cannot use struct 'PrivateImportType' in an extension with public, package, or '@usableFromInline' members; 'PrivateLib' was not imported publicly or as package}} package func packageMethod() {} } diff --git a/test/Sema/access-level-import-conformances.swift b/test/Sema/access-level-import-conformances.swift index 59026f41608db..b2d974885d534 100644 --- a/test/Sema/access-level-import-conformances.swift +++ b/test/Sema/access-level-import-conformances.swift @@ -2,29 +2,82 @@ // RUN: split-file --leading-lines %s %t /// Build the libraries. -// RUN: %target-swift-frontend -emit-module %t/ConformanceBaseTypes.swift -o %t -// RUN: %target-swift-frontend -emit-module %t/ConformanceDefinition.swift -o %t -I %t +// RUN: %target-swift-frontend -emit-module %t/ConformanceBaseTypes.swift -o %t -package-name pkg +// RUN: %target-swift-frontend -emit-module %t/ConformanceDefinition1.swift -o %t -I %t -package-name pkg +// RUN: %target-swift-frontend -emit-module %t/ConformanceDefinition2.swift -o %t -I %t -package-name pkg /// Check diagnostics. -// RUN: %target-swift-frontend -typecheck -verify %t/Client.swift -I %t +// RUN: %target-swift-frontend -typecheck -verify %t/ClientA.swift -I %t -package-name pkg +// RUN: %target-swift-frontend -typecheck -verify %t/ClientB.swift -I %t -package-name pkg //--- ConformanceBaseTypes.swift public protocol Proto {} public struct ConformingType { - public init () {} + public init () {} } -//--- ConformanceDefinition.swift +package protocol PkgProto {} // expected-note 2 {{protocol 'PkgProto' is not '@usableFromInline' or public}} +package struct PkgConformingType { // expected-note 4 {{struct 'PkgConformingType' is not '@usableFromInline' or public}} + package init () {} // expected-note 4 {{initializer 'init()' is not '@usableFromInline' or public}} +} + +//--- ConformanceDefinition1.swift import ConformanceBaseTypes extension ConformingType : Proto {} -//--- Client.swift +//--- ConformanceDefinition2.swift +import ConformanceBaseTypes +extension PkgConformingType : PkgProto {} + +//--- ClientA.swift public import ConformanceBaseTypes -internal import ConformanceDefinition // expected-note 2 {{extension of struct 'ConformingType' imported as 'internal' from 'ConformanceDefinition' here}} +internal import ConformanceDefinition1 // expected-note 2 {{extension of struct 'ConformingType' imported as 'internal' from 'ConformanceDefinition1' here}} +internal import ConformanceDefinition2 // expected-note 3 {{extension of struct 'PkgConformingType' imported as 'internal' from 'ConformanceDefinition2' here}} -public func useInAPI(a: any Proto = ConformingType()) { // expected-error {{cannot use conformance of 'ConformingType' to 'Proto' here; 'ConformanceDefinition' was not imported publicly}} +public func useInAPI(a: any Proto = ConformingType()) { // expected-error {{cannot use conformance of 'ConformingType' to 'Proto' here; 'ConformanceDefinition1' was not imported publicly}} +} +public func useInAPI(b: any PkgProto = PkgConformingType()) { + // expected-error@-1 {{cannot use conformance of 'PkgConformingType' to 'PkgProto' here; 'ConformanceDefinition2' was not imported publicly}} + // expected-error@-2 {{function cannot be declared public because its parameter uses a package type}} + // expected-error@-3 {{struct 'PkgConformingType' is package and cannot be referenced from a default argument value}} + // expected-error@-4 {{initializer 'init()' is package and cannot be referenced from a default argument value}} +} +package func useInPkgAPI(a: any PkgProto = PkgConformingType()) { + // expected-error@-1 {{cannot use conformance of 'PkgConformingType' to 'PkgProto' here; 'ConformanceDefinition2' was not imported publicly}} } @inlinable public func inlinableFunc() { - let _: any Proto = ConformingType() // expected-error {{cannot use conformance of 'ConformingType' to 'Proto' here; 'ConformanceDefinition' was not imported publicly}} + let _: any Proto = ConformingType() // expected-error {{cannot use conformance of 'ConformingType' to 'Proto' here; 'ConformanceDefinition1' was not imported publicly}} + + let _: any PkgProto = PkgConformingType() + // expected-error@-1 {{cannot use conformance of 'PkgConformingType' to 'PkgProto' here; 'ConformanceDefinition2' was not imported publicly}} + // expected-error@-2 {{protocol 'PkgProto' is package and cannot be referenced from an '@inlinable' function}} + // expected-error@-3 {{struct 'PkgConformingType' is package and cannot be referenced from an '@inlinable' function}} + // expected-error@-4 {{initializer 'init()' is package and cannot be referenced from an '@inlinable' function}} +} + +//--- ClientB.swift +public import ConformanceBaseTypes +package import ConformanceDefinition1 // expected-note 2 {{extension of struct 'ConformingType' imported as 'package' from 'ConformanceDefinition1' here}} +package import ConformanceDefinition2 // expected-note 2 {{extension of struct 'PkgConformingType' imported as 'package' from 'ConformanceDefinition2' here}} + +public func useInAPI(a: any Proto = ConformingType()) { // expected-error {{cannot use conformance of 'ConformingType' to 'Proto' here; 'ConformanceDefinition1' was imported as package}} +} +public func useInAPI(b: any PkgProto = PkgConformingType()) { + // expected-error@-1 {{cannot use conformance of 'PkgConformingType' to 'PkgProto' here; 'ConformanceDefinition2' was imported as package}} + // expected-error@-2 {{function cannot be declared public because its parameter uses a package type}} + // expected-error@-3 {{struct 'PkgConformingType' is package and cannot be referenced from a default argument value}} + // expected-error@-4 {{initializer 'init()' is package and cannot be referenced from a default argument value}} +} +package func useInPkgAPI(a: any PkgProto = PkgConformingType()) { // no-error +} + +@inlinable public func inlinableFunc() { + let _: any Proto = ConformingType() // expected-error {{cannot use conformance of 'ConformingType' to 'Proto' here; 'ConformanceDefinition1' was imported as package}} + + let _: any PkgProto = PkgConformingType() + // expected-error@-1 {{cannot use conformance of 'PkgConformingType' to 'PkgProto' here; 'ConformanceDefinition2' was imported as package}} + // expected-error@-2 {{protocol 'PkgProto' is package and cannot be referenced from an '@inlinable' function}} + // expected-error@-3 {{struct 'PkgConformingType' is package and cannot be referenced from an '@inlinable' function}} + // expected-error@-4 {{initializer 'init()' is package and cannot be referenced from an '@inlinable' function}} } diff --git a/test/Sema/access-level-import-inlinable.swift b/test/Sema/access-level-import-inlinable.swift index 5ce02e71e90ac..22d7ddfa22c05 100644 --- a/test/Sema/access-level-import-inlinable.swift +++ b/test/Sema/access-level-import-inlinable.swift @@ -43,6 +43,20 @@ public struct PackageImportType { public init() {} } +public protocol PackageImportProto { + associatedtype T +} + +public func PackageFunc() {} + +@propertyWrapper +public struct PackageImportWrapper { + public var wrappedValue: T + public init(wrappedValue: T) { + self.wrappedValue = wrappedValue + } +} + //--- InternalLib.swift public protocol InternalImportProto { associatedtype T @@ -76,7 +90,12 @@ public struct PrivateImportType { public import PublicLib package import PackageLib -// expected-note@-1 4 {{struct 'PackageImportType' imported as 'package' from 'PackageLib' here}} +// expected-note@-1 9 {{struct 'PackageImportType' imported as 'package' from 'PackageLib' here}} +// expected-note@-2 2 {{global function 'PackageFunc()' imported as 'package' from 'PackageLib' here}} +// expected-note@-3 2 {{protocol 'PackageImportProto' imported as 'package' from 'PackageLib' here}} +// expected-note@-4 2 {{initializer 'init()' imported as 'package' from 'PackageLib' here}} +// expected-note@-5 2 {{generic struct 'PackageImportWrapper' imported as 'package' from 'PackageLib' here}} +// expected-note@-6 2 {{initializer 'init(wrappedValue:)' imported as 'package' from 'PackageLib' here}} internal import InternalLib // expected-note@-1 9 {{struct 'InternalImportType' imported as 'internal' from 'InternalLib' here}} @@ -90,24 +109,29 @@ fileprivate import FileprivateLib // expected-note@-3 2 {{protocol 'FileprivateImportProto' imported as 'fileprivate' from 'FileprivateLib' here}} private import PrivateLib -// expected-note@-1 10 {{struct 'PrivateImportType' imported as 'private' from 'PrivateLib' here}} - // expected-note@-2 2 {{initializer 'init()' imported as 'private' from 'PrivateLib' here}} +// expected-note@-1 12 {{struct 'PrivateImportType' imported as 'private' from 'PrivateLib' here}} +// expected-note@-2 2 {{initializer 'init()' imported as 'private' from 'PrivateLib' here}} public struct GenericType {} @inlinable public func inlinable() { PublicFunc() + PackageFunc() // expected-error {{global function 'PackageFunc()' is package and cannot be referenced from an '@inlinable' function}} InternalFunc() // expected-error {{global function 'InternalFunc()' is internal and cannot be referenced from an '@inlinable' function}} let _: PublicImportType + let _: PackageImportType // expected-error {{struct 'PackageImportType' is package and cannot be referenced from an '@inlinable' function}} let _: InternalImportType // expected-error {{struct 'InternalImportType' is internal and cannot be referenced from an '@inlinable' function}} let _ = PublicImportType() + let _ = PackageImportType() // expected-error {{struct 'PackageImportType' is package and cannot be referenced from an '@inlinable' function}} + // expected-error @-1 {{initializer 'init()' is package and cannot be referenced from an '@inlinable' function}} let _ = PrivateImportType() // expected-error {{struct 'PrivateImportType' is private and cannot be referenced from an '@inlinable' function}} // expected-error @-1 {{initializer 'init()' is private and cannot be referenced from an '@inlinable' function}} let _: any PublicImportProto + let _: any PackageImportProto // expected-error {{protocol 'PackageImportProto' is package and cannot be referenced from an '@inlinable' function}} let _: any InternalImportProto // expected-error {{protocol 'InternalImportProto' is internal and cannot be referenced from an '@inlinable' function}} let _: any FileprivateImportProto & InternalImportProto // expected-error {{protocol 'FileprivateImportProto' is fileprivate and cannot be referenced from an '@inlinable' function}} @@ -126,6 +150,10 @@ public struct GenericType {} @PublicImportWrapper var wrappedPublic: PublicImportType + @PackageImportWrapper // expected-error {{initializer 'init(wrappedValue:)' is package and cannot be referenced from an '@inlinable' function}} + // expected-error @-1 {{generic struct 'PackageImportWrapper' is package and cannot be referenced from an '@inlinable' function}} + var wrappedPackage: PublicImportType + @FileprivateImportWrapper // expected-error {{initializer 'init(wrappedValue:)' is fileprivate and cannot be referenced from an '@inlinable' function}} // expected-error @-1 {{generic struct 'FileprivateImportWrapper' is fileprivate and cannot be referenced from an '@inlinable' function}} var wrappedFileprivate: PublicImportType @@ -138,16 +166,21 @@ public struct GenericType {} @_alwaysEmitIntoClient public func alwaysEmitIntoClient() { PublicFunc() + PackageFunc() // expected-error {{global function 'PackageFunc()' is package and cannot be referenced from an '@_alwaysEmitIntoClient' function}} InternalFunc() // expected-error {{global function 'InternalFunc()' is internal and cannot be referenced from an '@_alwaysEmitIntoClient' function}} let _: PublicImportType + let _: PackageImportType // expected-error {{struct 'PackageImportType' is package and cannot be referenced from an '@_alwaysEmitIntoClient' function}} let _: InternalImportType // expected-error {{struct 'InternalImportType' is internal and cannot be referenced from an '@_alwaysEmitIntoClient' function}} let _ = PublicImportType() + let _ = PackageImportType() // expected-error {{struct 'PackageImportType' is package and cannot be referenced from an '@_alwaysEmitIntoClient' function}} + // expected-error @-1 {{initializer 'init()' is package and cannot be referenced from an '@_alwaysEmitIntoClient' function}} let _ = PrivateImportType() // expected-error {{struct 'PrivateImportType' is private and cannot be referenced from an '@_alwaysEmitIntoClient' function}} // expected-error @-1 {{initializer 'init()' is private and cannot be referenced from an '@_alwaysEmitIntoClient' function}} let _: any PublicImportProto + let _: any PackageImportProto // expected-error {{protocol 'PackageImportProto' is package and cannot be referenced from an '@_alwaysEmitIntoClient' function}} let _: any InternalImportProto // expected-error {{protocol 'InternalImportProto' is internal and cannot be referenced from an '@_alwaysEmitIntoClient' function}} let _: any FileprivateImportProto & InternalImportProto // expected-error {{protocol 'FileprivateImportProto' is fileprivate and cannot be referenced from an '@_alwaysEmitIntoClient' function}} @@ -166,6 +199,10 @@ public struct GenericType {} @PublicImportWrapper var wrappedPublic: PublicImportType + @PackageImportWrapper // expected-error {{initializer 'init(wrappedValue:)' is package and cannot be referenced from an '@_alwaysEmitIntoClient' function}} + // expected-error @-1 {{generic struct 'PackageImportWrapper' is package and cannot be referenced from an '@_alwaysEmitIntoClient' function}} + var wrappedPackage: PublicImportType + @FileprivateImportWrapper // expected-error {{initializer 'init(wrappedValue:)' is fileprivate and cannot be referenced from an '@_alwaysEmitIntoClient' function}} // expected-error @-1 {{generic struct 'FileprivateImportWrapper' is fileprivate and cannot be referenced from an '@_alwaysEmitIntoClient' function}} var wrappedFileprivate: PublicImportType @@ -180,12 +217,23 @@ public struct GenericType {} // expected-note @-1 {{struct 'PrivateImportType' is imported by this file as 'private' from 'PrivateLib'}} } +@frozen package struct PkgBadFields1 { + private var field: PrivateImportType // expected-error {{type referenced from a stored property in a '@frozen package' struct must be '@usableFromInline', public, or package}} + // expected-note @-1 {{struct 'PrivateImportType' is imported by this file as 'private' from 'PrivateLib'}} +} + @_fixed_layout public struct FixedBadFields1 { // expected-warning@-1 {{'@frozen' attribute is now used for fixed-layout structs}} private var field: PrivateImportType // expected-error {{type referenced from a stored property in a '@frozen' struct must be '@usableFromInline' or public}} // expected-note @-1 {{struct 'PrivateImportType' is imported by this file as 'private' from 'PrivateLib'}} } +@_fixed_layout package struct PkgFixedBadFields1 { + // expected-warning@-1 {{'@frozen' attribute is now used for fixed-layout structs}} + private var field: PrivateImportType // expected-error {{type referenced from a stored property in a '@frozen package' struct must be '@usableFromInline', public, or package}} + // expected-note @-1 {{struct 'PrivateImportType' is imported by this file as 'private' from 'PrivateLib'}} +} + @frozen public struct BadFields2 { private var field: PrivateImportType? // expected-error {{type referenced from a stored property in a '@frozen' struct must be '@usableFromInline' or public}} // expected-note @-1 {{struct 'PrivateImportType' is imported by this file as 'private' from 'PrivateLib'}} @@ -249,6 +297,17 @@ public struct GenericType {} } } +// expected-error@+1 {{the result of a '@usableFromInline' function must be '@usableFromInline' or public}} +@usableFromInline func notReallyUsableFromInlinePkg() -> PackageImportType? { return nil } +// expected-note @-1 {{struct 'PackageImportType' is imported by this file as 'package' from 'PackageLib'}} +@frozen public struct BadFieldsPkg7 { + private var field = notReallyUsableFromInlinePkg() // expected-error {{type referenced from a stored property with inferred type 'PackageImportType?' in a '@frozen' struct must be '@usableFromInline' or public}} +} +@_fixed_layout public struct FrozenBadFieldsPkg7 { + // expected-warning@-1 {{'@frozen' attribute is now used for fixed-layout structs}} + private var field = notReallyUsableFromInlinePkg() // expected-error {{type referenced from a stored property with inferred type 'PackageImportType?' in a '@frozen' struct must be '@usableFromInline' or public}} +} + // expected-error@+1 {{the result of a '@usableFromInline' function must be '@usableFromInline' or public}} @usableFromInline func notReallyUsableFromInline() -> InternalImportType? { return nil } // expected-note @-1 {{struct 'InternalImportType' is imported by this file as 'internal' from 'InternalLib'}} @@ -261,13 +320,36 @@ public struct GenericType {} private var field = notReallyUsableFromInline() // expected-error {{type referenced from a stored property with inferred type 'InternalImportType?' in a '@frozen' struct must be '@usableFromInline' or public}} } +@frozen package struct PkgBadFields7 { + private var field = notReallyUsableFromInline() // expected-error {{type referenced from a stored property with inferred type 'InternalImportType?' in a '@frozen package' struct must be '@usableFromInline', public, or package}} +} +@_fixed_layout package struct PkgFrozenBadFields7 { + // expected-warning@-1 {{'@frozen' attribute is now used for fixed-layout structs}} + private var field = notReallyUsableFromInline() // expected-error {{type referenced from a stored property with inferred type 'InternalImportType?' in a '@frozen package' struct must be '@usableFromInline', public, or package}} +} + @frozen public struct OKFields { + public var field: PublicImportType internal static var staticProp: InternalImportType? private var computed: PrivateImportType? { return nil } } @_fixed_layout public struct FixedOKFields { // expected-warning@-1 {{'@frozen' attribute is now used for fixed-layout structs}} + public var field: PublicImportType + internal static var staticProp: InternalImportType? + private var computed: PrivateImportType? { return nil } +} + +@frozen package struct PkgOKFields { + package var field: PackageImportType + internal static var staticProp: InternalImportType? + private var computed: PrivateImportType? { return nil } +} + +@_fixed_layout package struct PkgFixedOKFields { + // expected-warning@-1 {{'@frozen' attribute is now used for fixed-layout structs}} + package var field: PackageImportType internal static var staticProp: InternalImportType? private var computed: PrivateImportType? { return nil } } diff --git a/test/Sema/access-level-import-package-exportability.swift b/test/Sema/access-level-import-package-exportability.swift new file mode 100644 index 0000000000000..48d5e6a4b10cd --- /dev/null +++ b/test/Sema/access-level-import-package-exportability.swift @@ -0,0 +1,108 @@ +// RUN: %empty-directory(%t) +// RUN: split-file %s %t + +// RUN: %target-swift-frontend -emit-module %t/Lib.swift \ +// RUN: -module-name Lib -swift-version 6 -I %t \ +// RUN: -package-name mypkg \ +// RUN: -enable-library-evolution \ +// RUN: -emit-module -emit-module-path %t/Lib.swiftmodule + +// RUN: %target-swift-frontend -typecheck %t/ClientA.swift -I %t -swift-version 6 -package-name mypkg -enable-library-evolution -verify +// RUN: %target-swift-frontend -typecheck %t/ClientB.swift -I %t -swift-version 6 -package-name mypkg -enable-library-evolution -verify +// RUN: %target-swift-frontend -typecheck %t/ClientC.swift -I %t -swift-version 6 -package-name mypkg -enable-library-evolution -verify +// RUN: %target-swift-frontend -typecheck %t/ClientD.swift -I %t -swift-version 6 -package-name mypkg -enable-library-evolution -verify +// RUN: %target-swift-frontend -typecheck %t/ClientE.swift -I %t -swift-version 6 -package-name mypkg -enable-library-evolution -verify +// RUN: %target-swift-frontend -typecheck %t/ClientF.swift -I %t -swift-version 6 -package-name mypkg -enable-library-evolution -verify + +//--- ClientA.swift + +@_implementationOnly import Lib // expected-warning {{'@_implementationOnly' is deprecated, use 'internal import' instead}} + +public func f() -> PubProto? { // expected-error {{cannot use protocol 'PubProto' here; 'Lib' has been imported as implementation-only}} + return nil +} +package func g() -> PkgProto? { // expected-error {{cannot use protocol 'PkgProto' here; 'Lib' has been imported as implementation-only}} + return nil +} + +//--- ClientB.swift +package import Lib // no-warning + +extension PkgStruct { + package static var v: Self { + fatalError() + } +} + +//--- ClientC.swift +package import Lib // no-warning + +extension PkgStruct { + package func f() {} +} + +//--- ClientD.swift +package import Lib // no-warning + +package extension PubStruct { + func f() {} +} + +//--- ClientE.swift +package import Lib + +package enum FeatureFlag: PubProto { // no-warning + case myFeatureFlag + + package var domain: StaticString { "MyDomain" } + package var feature: StaticString { "MyFeature" } + + package var someVar: String { "" } +} + +package struct MyStruct: PubProto { // no-warning + package var someVar: String { "" } +} + +//--- ClientF.swift +package struct PkgStruct {} +public protocol PubProto { + associatedtype CodeUnit +} + +extension PkgStruct { + @frozen + package enum ASCII {} +} + +extension PkgStruct.ASCII: PubProto { + package typealias CodeUnit = UInt8 +} + +//--- Lib.swift + +// expected-note@+1 1{{type declared here}} +public protocol PubProto { + var someVar: String { get } +} + +// expected-note@+1 1{{type declared here}} +package protocol PkgProto { + var someVar: String { get } +} + +public struct PubStruct { + public init() {} +} + +package struct PkgStruct { + package init() {} +} + +public class PubKlass { + public init() {} +} + +package class PkgKlass { + package init() {} +} diff --git a/test/Sema/access-level-import-typealias.swift b/test/Sema/access-level-import-typealias.swift index 95f30887c737d..ec7e72eb441ce 100644 --- a/test/Sema/access-level-import-typealias.swift +++ b/test/Sema/access-level-import-typealias.swift @@ -13,6 +13,22 @@ // RUN: -swift-version 5 -enable-library-evolution \ // RUN: -enable-upcoming-feature InternalImportsByDefault +// RUN: %target-swift-frontend -emit-module %t/Original.swift -o %t \ +// RUN: -swift-version 6 -enable-library-evolution -package-name pkg + +// RUN: %target-swift-frontend -emit-module %t/AliasesPkg.swift -o %t \ +// RUN: -swift-version 6 -enable-library-evolution -I %t -package-name pkg + +// RUN: %target-swift-frontend -typecheck -verify %t/UsesAliasesPkg1.swift -I %t \ +// RUN: -swift-version 5 -enable-library-evolution -package-name pkg +// RUN: %target-swift-frontend -typecheck -verify %t/UsesAliasesPkg1.swift -I %t \ +// RUN: -swift-version 6 -enable-library-evolution -package-name pkg + +// RUN: %target-swift-frontend -typecheck -verify %t/UsesAliasesPkg2.swift -I %t \ +// RUN: -swift-version 5 -enable-library-evolution -package-name pkg +// RUN: %target-swift-frontend -typecheck -verify %t/UsesAliasesPkg2.swift -I %t \ +// RUN: -swift-version 6 -enable-library-evolution -package-name pkg + //--- Original.swift open class Clazz {} @@ -32,3 +48,46 @@ public class InheritsFromClazzAlias: ClazzAlias {} _ = ClazzAlias.self } + +//--- AliasesPkg.swift +public import Original // expected-warning {{public import of 'Original' was not used in public declarations or inlinable code}} +package typealias PkgClazzAlias = Clazz // expected-note 2 {{type alias 'PkgClazzAlias' is not '@usableFromInline' or public}} + +//--- UsesAliasesPkg1.swift +public import AliasesPkg // expected-warning {{public import of 'AliasesPkg' was not used in public declarations or inlinable code}} +internal import Original // expected-note 1 {{class 'Clazz' imported as 'internal' from 'Original' here}} + +// expected-error@+1 {{'PkgClazzAlias' aliases 'Original.Clazz' and cannot be used here because 'Original' was not imported publicly}} +package class InheritsFromPkgClazzAlias: PkgClazzAlias {} + +@inlinable public func inlinableFunc() { + // expected-error@+1 {{type alias 'PkgClazzAlias' is package and cannot be referenced from an '@inlinable' function}} + _ = PkgClazzAlias.self +} + +@inlinable package func inlinableFuncPkg() { + // expected-error@+1 {{type alias 'PkgClazzAlias' is package and cannot be referenced from an '@inlinable' function}} + _ = PkgClazzAlias.self +} + + +//--- UsesAliasesPkg2.swift +public import AliasesPkg // expected-warning {{public import of 'AliasesPkg' was not used in public declarations or inlinable code}} +package import Original + +package class InheritsFromPkgClazzAlias: PkgClazzAlias {} // no-error + +package func usePkgClazzAlias() { + _ = PkgClazzAlias.self // no-error +} + +@inlinable public func inlinableFunc() { + // expected-error@+1 {{type alias 'PkgClazzAlias' is package and cannot be referenced from an '@inlinable' function}} + _ = PkgClazzAlias.self +} + +@inlinable package func inlinableFuncPkg() { + // expected-error@+1 {{type alias 'PkgClazzAlias' is package and cannot be referenced from an '@inlinable' function}} + _ = PkgClazzAlias.self +} + diff --git a/test/Sema/superfluously-public-imports.swift b/test/Sema/superfluously-public-imports.swift index 61e1ea0775914..db3cfee2d23f2 100644 --- a/test/Sema/superfluously-public-imports.swift +++ b/test/Sema/superfluously-public-imports.swift @@ -237,7 +237,9 @@ internal func internalFunc(a: NotAnAPIType = notAnAPIFunc()) {} func implicitlyInternalFunc(a: NotAnAPIType = notAnAPIFunc()) {} // For package decls we only remark on types used in signatures, not for inlinable code. -package func packageFunc(a: PackageType = packageFunc()) {} // expected-remark {{struct 'PackageType' is imported via 'ImportUsedInPackage'}} +package func packageFunc(a: PackageType = packageFunc()) {} +// expected-remark@-1 {{struct 'PackageType' is imported via 'ImportUsedInPackage'}} +// expected-remark@-2 {{global function 'packageFunc()' is imported via 'ImportUsedInPackage'}} @_spi(X) public func spiFunc(a: ToUseFromSPI) {} // expected-remark {{struct 'ToUseFromSPI' is imported via 'SPIOnlyUsedInSPI'}} @@ -249,7 +251,7 @@ public protocol Countable { extension Extended: Countable { // expected-remark {{struct 'Extended' is imported via 'RetroactiveConformance'}} } -extension ExtendedPackageType { // expected-remark {{struct 'ExtendedPackageType' is imported via 'ExtendedPackageTypeImport'}} +extension ExtendedPackageType { // expected-remark 2 {{struct 'ExtendedPackageType' is imported via 'ExtendedPackageTypeImport'}} package func useExtendedPackageType() { } } diff --git a/test/attr/attr_fixed_layout_property_wrapper.swift b/test/attr/attr_fixed_layout_property_wrapper.swift index 643e207837e4e..f3cf1ae60bfce 100644 --- a/test/attr/attr_fixed_layout_property_wrapper.swift +++ b/test/attr/attr_fixed_layout_property_wrapper.swift @@ -1,8 +1,9 @@ // RUN: %target-typecheck-verify-swift -swift-version 5 -package-name myPkg -private class PrivateType {} // expected-note {{class 'PrivateType' is not '@usableFromInline' or public}} -// expected-note@-1 {{initializer 'init()' is not '@usableFromInline' or public}} -// expected-note@-2 {{type declared here}} +private class PrivateType {} +// expected-note@-1 2 {{class 'PrivateType' is not '@usableFromInline' or public}} +// expected-note@-2 2 {{initializer 'init()' is not '@usableFromInline' or public}} +// expected-note@-3 2 {{type declared here}} package class PackageType { // expected-note@-1 {{class 'PackageType' is not '@usableFromInline' or public}} @@ -44,3 +45,20 @@ public struct Wrapper { @Wrapper private var z1: PackageTypeForInline @Wrapper private var z2 = PackageTypeForInline() } + + +@frozen package struct FrozenPackageStruct { + @Wrapper private var p1: PrivateType + // expected-error@-1 {{type referenced from a stored property in a '@frozen package' struct must be '@usableFromInline', public, or package}} + + @Wrapper private var p2 = PrivateType() + // expected-error@-1 {{class 'PrivateType' is private and cannot be referenced from a property initializer in a '@frozen' type}} + // expected-error@-2 {{initializer 'init()' is private and cannot be referenced from a property initializer in a '@frozen' type}} + // expected-error@-3 {{type referenced from a stored property with inferred type 'PrivateType' in a '@frozen package' struct must be '@usableFromInline', public, or package}} + + // no-errors below + @Wrapper private var q1: PackageType + @Wrapper private var q2 = PackageType() + @Wrapper private var r1: PackageTypeForInline + @Wrapper private var r2 = PackageTypeForInline() +}