diff --git a/README.md b/README.md index a7dbf3a70630d..838b5c96eaa39 100644 --- a/README.md +++ b/README.md @@ -252,7 +252,7 @@ various products. These incremental builds are a big timesaver when developing and debugging. cd ${SWIFT_BUILD_DIR} - ninja swift + ninja swift-frontend This will build the Swift compiler, but will not rebuild the standard library or any other target. Building the `swift-stdlib` target as an additional layer of @@ -269,7 +269,7 @@ To open the Swift project in Xcode, open `${SWIFT_BUILD_DIR}/Swift.xcodeproj`. It will auto-create a *lot* of schemes for all of the available targets. A common debug flow would involve: - - Select the 'swift' scheme. + - Select the 'swift-frontend' scheme. - Pull up the scheme editor (⌘⇧<). - Select the 'Arguments' tab and click the '+'. - Add the command line options. diff --git a/cmake/modules/AddSwift.cmake b/cmake/modules/AddSwift.cmake index 3dd1d7f0901b7..5e3f14cc700fc 100644 --- a/cmake/modules/AddSwift.cmake +++ b/cmake/modules/AddSwift.cmake @@ -121,6 +121,7 @@ function(_add_host_variant_c_compile_link_flags name) _compute_lto_flag("${SWIFT_TOOLS_ENABLE_LTO}" _lto_flag_out) if (_lto_flag_out) target_compile_options(${name} PRIVATE ${_lto_flag_out}) + target_link_options(${name} PRIVATE ${_lto_flag_out}) endif() endfunction() diff --git a/docs/StdlibRationales.rst b/docs/StdlibRationales.rst index 3b8503b5a92c8..1a13f5a8109c4 100644 --- a/docs/StdlibRationales.rst +++ b/docs/StdlibRationales.rst @@ -174,21 +174,6 @@ call an API with a different name, say ``lazyEnumerate()`` to opt into laziness. The problem is that the eager API, which would have a shorter and less obscure name, would be less efficient for the common case. -Use of ``BooleanType`` in library APIs --------------------------------------- - -Use ``Bool`` instead of a generic function over a ``BooleanType``, unless there -are special circumstances (for example, ``func &&`` is designed to work on all -boolean values so that ``&&`` feels like a part of the language). - -``BooleanType`` is a protocol to which only ``Bool`` and ``ObjCBool`` conform. -Users don't usually interact ``ObjCBool`` instances, except when using certain -specific APIs (for example, APIs that operate on pointers to ``BOOL``). If -someone already has an ``ObjCBool`` instance for whatever strange reason, they -can just convert it to ``Bool``. We think this is the right tradeoff: -simplifying function signatures is more important than making a marginal -usecase a bit more convenient. - Possible future directions ========================== diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index f6f51cd11ea10..2ab5a7a338234 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1801,11 +1801,11 @@ ERROR(type_cannot_conform_to_nsobject,none, ERROR(use_of_equal_instead_of_equality,none, "use of '=' in a boolean context, did you mean '=='?", ()) - ERROR(type_cannot_conform, none, - "%select{|value of protocol }0type %1 cannot conform to %2; " - "only struct/enum/class types can conform to protocols", - (bool, Type, Type)) + "%select{type %1|protocol %1 as a type}0 cannot conform to " + "%select{%3|the protocol itself}2; " + "only concrete types such as structs, enums and classes can conform to protocols", + (bool, Type, bool, Type)) NOTE(required_by_opaque_return,none, "required by opaque return type of %0 %1", (DescriptiveDeclKind, DeclName)) NOTE(required_by_decl,none, diff --git a/include/swift/AST/EducationalNotes.def b/include/swift/AST/EducationalNotes.def index ca30032f17a5f..e4e0ec2a3bd89 100644 --- a/include/swift/AST/EducationalNotes.def +++ b/include/swift/AST/EducationalNotes.def @@ -59,11 +59,23 @@ EDUCATIONAL_NOTES(property_wrapper_failable_init, EDUCATIONAL_NOTES(property_wrapper_type_requirement_not_accessible, "property-wrapper-requirements.md") +EDUCATIONAL_NOTES(opaque_type_var_no_init, "opaque-type-inference.md") +EDUCATIONAL_NOTES(opaque_type_no_underlying_type_candidates, + "opaque-type-inference.md") +EDUCATIONAL_NOTES(opaque_type_mismatched_underlying_type_candidates, + "opaque-type-inference.md") +EDUCATIONAL_NOTES(opaque_type_self_referential_underlying_type, + "opaque-type-inference.md") +EDUCATIONAL_NOTES(opaque_type_var_no_underlying_type, + "opaque-type-inference.md") + + EDUCATIONAL_NOTES(missing_append_interpolation, "string-interpolation-conformance.md") EDUCATIONAL_NOTES(append_interpolation_static, "string-interpolation-conformance.md") EDUCATIONAL_NOTES(append_interpolation_void_or_discardable, "string-interpolation-conformance.md") +EDUCATIONAL_NOTES(type_cannot_conform, "protocol-type-non-conformance.md") #undef EDUCATIONAL_NOTES diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 4eec20e76b166..34d48b6e27622 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -785,6 +785,10 @@ class alignas(1 << TypeAlignInBits) TypeBase { /// Check if this is a nominal type defined at the top level of the Swift module bool isStdlibType(); + + /// Check if this is either an Array, Set or Dictionary collection type defined + /// at the top level of the Swift module + bool isKnownStdlibCollectionType(); /// If this is a class type or a bound generic class type, returns the /// (possibly generic) class. @@ -5571,25 +5575,7 @@ class ArchetypeType : public SubstitutableType, /// find a particular nested type by name, directly, or look at the /// protocols to which this archetype conforms. ArrayRef> - getKnownNestedTypes(bool resolveTypes = true) const { - return getAllNestedTypes(/*resolveTypes=*/false); - } - - /// Retrieve the nested types of this archetype. - /// - /// \param resolveTypes Whether to eagerly resolve the nested types - /// (defaults to \c true). Otherwise, the nested types might be - /// null. - /// - /// FIXME: This operation should go away, because it breaks recursive - /// protocol constraints. - ArrayRef> - getAllNestedTypes(bool resolveTypes = true) const; - - /// Set the nested types to a copy of the given array of - /// archetypes. - void setNestedTypes(ASTContext &Ctx, - ArrayRef> Nested); + getKnownNestedTypes() const; /// Register a nested type with the given name. void registerNestedType(Identifier name, Type nested); diff --git a/include/swift/SIL/AbstractionPattern.h b/include/swift/SIL/AbstractionPattern.h index 22f550d39a741..ca64fd6022f14 100644 --- a/include/swift/SIL/AbstractionPattern.h +++ b/include/swift/SIL/AbstractionPattern.h @@ -179,15 +179,26 @@ class AbstractionPattern { /// type. ObjCMethod is valid. OtherData is an encoded foreign /// error index. ObjCMethodType, - /// The uncurried imported type of a C++ method. OrigType is valid and is a - /// function type. CXXMethod is valid. + /// The uncurried imported type of a C++ non-operator non-static member + /// function. OrigType is valid and is a function type. CXXMethod is valid. CXXMethodType, - /// The curried imported type of a C++ method. OrigType is valid and is a - /// function type. CXXMethod is valid. + /// The curried imported type of a C++ non-operator non-static member + /// function. OrigType is valid and is a function type. CXXMethod is valid. CurriedCXXMethodType, - /// The partially-applied curried imported type of a C++ method. OrigType is - /// valid and is a function type. CXXMethod is valid. + /// The partially-applied curried imported type of a C++ non-operator + /// non-static member function. OrigType is valid and is a function type. + /// CXXMethod is valid. PartialCurriedCXXMethodType, + /// The uncurried imported type of a C++ operator non-static member + /// function. OrigType is valid and is a function type. CXXMethod is valid. + CXXOperatorMethodType, + /// The curried imported type of a C++ operator non-static member function. + /// OrigType is valid and is a function type. CXXMethod is valid. + CurriedCXXOperatorMethodType, + /// The partially-applied curried imported type of a C++ operator non-static + /// member function. OrigType is valid and is a function type. CXXMethod is + /// valid. + PartialCurriedCXXOperatorMethodType, /// A Swift function whose parameters and results are opaque. This is /// like `AP::Type((T) -> T)`, except that the number of parameters is /// unspecified. @@ -341,6 +352,9 @@ class AbstractionPattern { case Kind::CXXMethodType: case Kind::CurriedCXXMethodType: case Kind::PartialCurriedCXXMethodType: + case Kind::CXXOperatorMethodType: + case Kind::CurriedCXXOperatorMethodType: + case Kind::PartialCurriedCXXOperatorMethodType: return true; default: @@ -465,6 +479,9 @@ class AbstractionPattern { case Kind::CXXMethodType: case Kind::CurriedCXXMethodType: case Kind::PartialCurriedCXXMethodType: + case Kind::CXXOperatorMethodType: + case Kind::CurriedCXXOperatorMethodType: + case Kind::PartialCurriedCXXOperatorMethodType: return true; case Kind::Invalid: case Kind::Opaque: @@ -541,6 +558,10 @@ class AbstractionPattern { static AbstractionPattern getCurriedCXXMethod(CanType origType, const AbstractFunctionDecl *function); + static AbstractionPattern + getCurriedCXXOperatorMethod(CanType origType, + const AbstractFunctionDecl *function); + /// Return an abstraction pattern for the uncurried type of a C++ method. /// /// For example, if the original function is: @@ -556,6 +577,15 @@ class AbstractionPattern { return pattern; } + static AbstractionPattern + getCXXOperatorMethod(CanType origType, const clang::CXXMethodDecl *method) { + assert(isa(origType)); + AbstractionPattern pattern; + pattern.initCXXMethod(nullptr, origType, method, + Kind::CXXOperatorMethodType); + return pattern; + } + /// Return an abstraction pattern for the curried type of a C++ method. /// /// For example, if the original function is: @@ -572,6 +602,16 @@ class AbstractionPattern { return pattern; } + static AbstractionPattern + getCurriedCXXOperatorMethod(CanType origType, + const clang::CXXMethodDecl *method) { + assert(isa(origType)); + AbstractionPattern pattern; + pattern.initCXXMethod(nullptr, origType, method, + Kind::CurriedCXXOperatorMethodType); + return pattern; + } + /// For a C-function-as-method pattern, /// get the index of the C function parameter that was imported as the /// `self` parameter of the imported method, or None if this is a static @@ -678,6 +718,17 @@ class AbstractionPattern { return pattern; } + static AbstractionPattern + getPartialCurriedCXXOperatorMethod(CanGenericSignature signature, + CanType origType, + const clang::CXXMethodDecl *method) { + assert(isa(origType)); + AbstractionPattern pattern; + pattern.initCXXMethod(signature, origType, method, + Kind::PartialCurriedCXXOperatorMethodType); + return pattern; + } + public: /// Return an abstraction pattern for the type of an Objective-C method. static AbstractionPattern @@ -813,6 +864,9 @@ class AbstractionPattern { case Kind::CXXMethodType: case Kind::CurriedCXXMethodType: case Kind::PartialCurriedCXXMethodType: + case Kind::CXXOperatorMethodType: + case Kind::CurriedCXXOperatorMethodType: + case Kind::PartialCurriedCXXOperatorMethodType: case Kind::Type: case Kind::Discard: return OrigType; @@ -849,6 +903,9 @@ class AbstractionPattern { case Kind::CXXMethodType: case Kind::CurriedCXXMethodType: case Kind::PartialCurriedCXXMethodType: + case Kind::CXXOperatorMethodType: + case Kind::CurriedCXXOperatorMethodType: + case Kind::PartialCurriedCXXOperatorMethodType: case Kind::Type: case Kind::Discard: assert(signature || !type->hasTypeParameter()); @@ -886,6 +943,9 @@ class AbstractionPattern { case Kind::CXXMethodType: case Kind::CurriedCXXMethodType: case Kind::PartialCurriedCXXMethodType: + case Kind::CXXOperatorMethodType: + case Kind::CurriedCXXOperatorMethodType: + case Kind::PartialCurriedCXXOperatorMethodType: return true; } llvm_unreachable("bad kind"); @@ -923,7 +983,9 @@ class AbstractionPattern { /// If so, it is legal to call getCXXMethod(). bool isCXXMethod() const { return (getKind() == Kind::CXXMethodType || - getKind() == Kind::CurriedCXXMethodType); + getKind() == Kind::CurriedCXXMethodType || + getKind() == Kind::CXXOperatorMethodType || + getKind() == Kind::CurriedCXXOperatorMethodType); } const clang::CXXMethodDecl *getCXXMethod() const { @@ -958,6 +1020,9 @@ class AbstractionPattern { case Kind::CXXMethodType: case Kind::CurriedCXXMethodType: case Kind::PartialCurriedCXXMethodType: + case Kind::CXXOperatorMethodType: + case Kind::CurriedCXXOperatorMethodType: + case Kind::PartialCurriedCXXOperatorMethodType: case Kind::OpaqueFunction: case Kind::OpaqueDerivativeFunction: return false; @@ -994,6 +1059,9 @@ class AbstractionPattern { case Kind::CXXMethodType: case Kind::CurriedCXXMethodType: case Kind::PartialCurriedCXXMethodType: + case Kind::CXXOperatorMethodType: + case Kind::CurriedCXXOperatorMethodType: + case Kind::PartialCurriedCXXOperatorMethodType: case Kind::Type: case Kind::Discard: return dyn_cast(getType()); @@ -1022,6 +1090,9 @@ class AbstractionPattern { case Kind::CXXMethodType: case Kind::CurriedCXXMethodType: case Kind::PartialCurriedCXXMethodType: + case Kind::CXXOperatorMethodType: + case Kind::CurriedCXXOperatorMethodType: + case Kind::PartialCurriedCXXOperatorMethodType: case Kind::OpaqueFunction: case Kind::OpaqueDerivativeFunction: // We assume that the Clang type might provide additional structure. @@ -1051,6 +1122,9 @@ class AbstractionPattern { case Kind::CXXMethodType: case Kind::CurriedCXXMethodType: case Kind::PartialCurriedCXXMethodType: + case Kind::CXXOperatorMethodType: + case Kind::CurriedCXXOperatorMethodType: + case Kind::PartialCurriedCXXOperatorMethodType: case Kind::OpaqueFunction: case Kind::OpaqueDerivativeFunction: return false; @@ -1078,6 +1152,9 @@ class AbstractionPattern { case Kind::CXXMethodType: case Kind::CurriedCXXMethodType: case Kind::PartialCurriedCXXMethodType: + case Kind::CXXOperatorMethodType: + case Kind::CurriedCXXOperatorMethodType: + case Kind::PartialCurriedCXXOperatorMethodType: case Kind::OpaqueFunction: case Kind::OpaqueDerivativeFunction: llvm_unreachable("pattern is not a tuple"); diff --git a/include/swift/SIL/SILType.h b/include/swift/SIL/SILType.h index f151ad217ed4d..f36f27177223c 100644 --- a/include/swift/SIL/SILType.h +++ b/include/swift/SIL/SILType.h @@ -18,7 +18,6 @@ #ifndef SWIFT_SIL_SILTYPE_H #define SWIFT_SIL_SILTYPE_H -#include "swift/AST/CanTypeVisitor.h" #include "swift/AST/SILLayout.h" #include "swift/AST/Types.h" #include "llvm/ADT/PointerIntPair.h" @@ -622,10 +621,19 @@ template<> Can##ID##Type SILType::getAs() const = delete; \ template<> Can##ID##Type SILType::castTo() const = delete; \ template<> bool SILType::is() const = delete; NON_SIL_TYPE(Function) +NON_SIL_TYPE(GenericFunction) NON_SIL_TYPE(AnyFunction) NON_SIL_TYPE(LValue) +NON_SIL_TYPE(InOut) #undef NON_SIL_TYPE +#define TYPE(ID, PARENT) +#define UNCHECKED_TYPE(ID, PARENT) \ +template<> Can##ID##Type SILType::getAs() const = delete; \ +template<> Can##ID##Type SILType::castTo() const = delete; \ +template<> bool SILType::is() const = delete; +#include "swift/AST/TypeNodes.def" + inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, SILType T) { T.print(OS); return OS; diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index ac5d26304f91d..4c59a9f812fa5 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -760,6 +760,16 @@ bool TypeBase::isStdlibType() { return false; } +bool TypeBase::isKnownStdlibCollectionType() { + if (auto *structType = getAs()) { + auto &ctx = getASTContext(); + auto *decl = structType->getDecl(); + return decl == ctx.getArrayDecl() || decl == ctx.getDictionaryDecl() || + decl == ctx.getSetDecl(); + } + return false; +} + /// Remove argument labels from the function type. Type TypeBase::removeArgumentLabels(unsigned numArgumentLabels) { // If there is nothing to remove, don't. @@ -3210,7 +3220,11 @@ void ArchetypeType::populateNestedTypes() const { // Record the nested types. auto mutableThis = const_cast(this); - mutableThis->setNestedTypes(mutableThis->getASTContext(), nestedTypes); + + std::sort(nestedTypes.begin(), nestedTypes.end(), OrderArchetypeByName()); + auto &Ctx = mutableThis->getASTContext(); + mutableThis->NestedTypes = Ctx.AllocateCopy(nestedTypes); + mutableThis->Bits.ArchetypeType.ExpandedNestedTypes = true; } Type ArchetypeType::getNestedType(Identifier Name) const { @@ -3250,28 +3264,11 @@ bool ArchetypeType::hasNestedType(Identifier Name) const { } ArrayRef> -ArchetypeType::getAllNestedTypes(bool resolveTypes) const { +ArchetypeType::getKnownNestedTypes() const { populateNestedTypes(); - - if (resolveTypes) { - for (auto &nested : NestedTypes) { - if (!nested.second) - resolveNestedType(nested); - } - } - return NestedTypes; } -void ArchetypeType::setNestedTypes( - ASTContext &Ctx, - ArrayRef> Nested) { - assert(!Bits.ArchetypeType.ExpandedNestedTypes && "Already expanded"); - NestedTypes = Ctx.AllocateCopy(Nested); - std::sort(NestedTypes.begin(), NestedTypes.end(), OrderArchetypeByName()); - Bits.ArchetypeType.ExpandedNestedTypes = true; -} - void ArchetypeType::registerNestedType(Identifier name, Type nested) { populateNestedTypes(); diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index d1976abfe1adb..53575b567fe8d 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -3595,6 +3595,18 @@ void ClangImporter::Implementation::lookupValue( auto &clangCtx = getClangASTContext(); auto clangTU = clangCtx.getTranslationUnitDecl(); + // For operators we have to look up static member functions in addition to the + // top-level function lookup below. + if (name.isOperator()) { + for (auto entry : table.lookupMemberOperators(name.getBaseName())) { + if (isVisibleClangEntry(entry)) { + if (auto decl = dyn_cast( + importDeclReal(entry->getMostRecentDecl(), CurrentVersion))) + consumer.foundDecl(decl, DeclVisibilityKind::VisibleAtTopLevel); + } + } + } + for (auto entry : table.lookup(name.getBaseName(), clangTU)) { // If the entry is not visible, skip it. if (!isVisibleClangEntry(entry)) continue; diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index c2ef408111f93..bddc7536ba997 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -3801,14 +3801,20 @@ namespace { decl->isVariadic(), isInSystemModule(dc), name, bodyParams); if (auto *mdecl = dyn_cast(decl)) { - if (!mdecl->isStatic()) { + if (mdecl->isStatic() || + // C++ operators that are implemented as non-static member + // functions get imported into Swift as static member functions + // that use an additional parameter for the left-hand side operand + // instead of the receiver object. + mdecl->getDeclName().getNameKind() == + clang::DeclarationName::CXXOperatorName) { + selfIdx = None; + } else { selfIdx = 0; // Workaround until proper const support is handled: Force // everything to be mutating. This implicitly makes the parameter // indirect. selfIsInOut = true; - } else { - selfIdx = None; } } } diff --git a/lib/ClangImporter/ImportName.cpp b/lib/ClangImporter/ImportName.cpp index 3641f2b40236d..1611d20507369 100644 --- a/lib/ClangImporter/ImportName.cpp +++ b/lib/ClangImporter/ImportName.cpp @@ -32,6 +32,7 @@ #include "swift/ClangImporter/ClangImporterOptions.h" #include "swift/Parse/Parser.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/DeclCXX.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/Module.h" #include "clang/Basic/OperatorKinds.h" @@ -1439,7 +1440,13 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D, if (auto FD = dyn_cast(D)) { baseName = clang::getOperatorSpelling(op); isFunction = true; - argumentNames.resize(FD->param_size()); + argumentNames.resize( + FD->param_size() + + // C++ operators that are implemented as non-static member functions + // get imported into Swift as static member functions that use an + // additional parameter for the left-hand side operand instead of + // the receiver object. + (isa(D) ? 1 : 0)); } else { // This can happen for example for templated operators functions. // We don't support those, yet. diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index 8b9fbe3034fe8..3994a67166018 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -27,11 +27,13 @@ #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" #include "swift/AST/ParameterList.h" +#include "swift/AST/Type.h" #include "swift/AST/Types.h" #include "swift/ClangImporter/ClangModule.h" #include "swift/Parse/Token.h" #include "swift/Strings.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/TypeVisitor.h" #include "clang/Basic/Builtins.h" #include "clang/Lex/Preprocessor.h" @@ -1708,6 +1710,30 @@ ParameterList *ClangImporter::Implementation::importFunctionParameterList( unsigned index = 0; SmallBitVector nonNullArgs = getNonNullArgs(clangDecl, params); + // C++ operators that are implemented as non-static member functions get + // imported into Swift as static methods that have an additional + // parameter for the left-hand side operand instead of the receiver object. + if (auto CMD = dyn_cast(clangDecl)) { + if (clangDecl->isOverloadedOperator()) { + auto param = new (SwiftContext) + ParamDecl(SourceLoc(), SourceLoc(), Identifier(), SourceLoc(), + SwiftContext.getIdentifier("lhs"), dc); + + auto parent = CMD->getParent(); + auto parentType = importType( + parent->getASTContext().getRecordType(parent), + ImportTypeKind::Parameter, allowNSUIntegerAsInt, Bridgeability::None); + + param->setInterfaceType(parentType.getType()); + + // Workaround until proper const support is handled: Force everything to + // be mutating. This implicitly makes the parameter indirect. + param->setSpecifier(ParamSpecifier::InOut); + + parameters.push_back(param); + } + } + for (auto param : params) { auto paramTy = param->getType(); if (paramTy->isVoidType()) { diff --git a/lib/ClangImporter/SwiftLookupTable.cpp b/lib/ClangImporter/SwiftLookupTable.cpp index fa034ee544627..74a64dcb025d5 100644 --- a/lib/ClangImporter/SwiftLookupTable.cpp +++ b/lib/ClangImporter/SwiftLookupTable.cpp @@ -20,6 +20,7 @@ #include "swift/AST/DiagnosticsClangImporter.h" #include "swift/Basic/STLExtras.h" #include "swift/Basic/Version.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/Preprocessor.h" @@ -795,6 +796,35 @@ SwiftLookupTable::lookupObjCMembers(SerializedSwiftName baseName) { return result; } +SmallVector +SwiftLookupTable::lookupMemberOperators(SerializedSwiftName baseName) { + SmallVector result; + + // Find the lookup table entry for this base name. + auto known = findOrCreate(LookupTable, baseName, + [](auto &results, auto &Reader, auto Name) { + return (void)Reader.lookup(Name, results); + }); + if (known == LookupTable.end()) + return result; + + // Walk each of the entries. + for (auto &entry : known->second) { + // We're only looking for C++ operators + if (entry.Context.first != ContextKind::Tag) { + continue; + } + + // Map each of the declarations. + for (auto &stored : entry.DeclsOrMacros) { + assert(isDeclEntry(stored) && "Not a declaration?"); + result.push_back(mapStoredDecl(stored)); + } + } + + return result; +} + ArrayRef SwiftLookupTable::categories() { if (!Categories.empty() || !Reader) return Categories; diff --git a/lib/ClangImporter/SwiftLookupTable.h b/lib/ClangImporter/SwiftLookupTable.h index fe980625c0ff8..0a5afe26e0d4d 100644 --- a/lib/ClangImporter/SwiftLookupTable.h +++ b/lib/ClangImporter/SwiftLookupTable.h @@ -528,6 +528,10 @@ class SwiftLookupTable { SmallVector lookupObjCMembers(SerializedSwiftName baseName); + /// Lookup member operators with the given base name, regardless of context. + SmallVector + lookupMemberOperators(SerializedSwiftName baseName); + /// Retrieve the set of Objective-C categories and extensions. ArrayRef categories(); diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp index c22f154e969e1..812890d7aec58 100644 --- a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp +++ b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp @@ -102,8 +102,6 @@ bool ArgsToFrontendOptionsConverter::convert( Opts.RemarkOnRebuildFromModuleInterface |= Args.hasArg(OPT_Rmodule_interface_rebuild); - Opts.DisableInterfaceFileLock |= Args.hasArg(OPT_disable_interface_lockfile); - computePrintStatsOptions(); computeDebugTimeOptions(); computeTBDOptions(); @@ -149,6 +147,15 @@ bool ArgsToFrontendOptionsConverter::convert( Opts.RequestedAction = determineRequestedAction(Args); } + if (Opts.RequestedAction == FrontendOptions::ActionType::CompileModuleFromInterface) { + // The situations where we use this action, e.g. explicit module building and + // generating prebuilt module cache, don't need synchronization. We should avoid + // using lock files for them. + Opts.DisableInterfaceFileLock = true; + } else { + Opts.DisableInterfaceFileLock |= Args.hasArg(OPT_disable_interface_lockfile); + } + if (Opts.RequestedAction == FrontendOptions::ActionType::Immediate && Opts.InputsAndOutputs.hasPrimaryInputs()) { Diags.diagnose(SourceLoc(), diag::error_immediate_mode_primary_file); diff --git a/lib/IRGen/MetadataRequest.cpp b/lib/IRGen/MetadataRequest.cpp index 30ae9a1beadc0..1748aca08918e 100644 --- a/lib/IRGen/MetadataRequest.cpp +++ b/lib/IRGen/MetadataRequest.cpp @@ -33,6 +33,7 @@ #include "IRGenMangler.h" #include "IRGenModule.h" #include "swift/AST/ASTContext.h" +#include "swift/AST/CanTypeVisitor.h" #include "swift/AST/ExistentialLayout.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/IRGenOptions.h" diff --git a/lib/SIL/IR/AbstractionPattern.cpp b/lib/SIL/IR/AbstractionPattern.cpp index 4e58d38f021bf..98b35f470a549 100644 --- a/lib/SIL/IR/AbstractionPattern.cpp +++ b/lib/SIL/IR/AbstractionPattern.cpp @@ -168,6 +168,12 @@ AbstractionPattern::getCurriedCXXMethod(CanType origType, return getCurriedCXXMethod(origType, clangMethod); } +AbstractionPattern AbstractionPattern::getCurriedCXXOperatorMethod( + CanType origType, const AbstractFunctionDecl *function) { + auto clangMethod = cast(function->getClangDecl()); + return getCurriedCXXOperatorMethod(origType, clangMethod); +} + AbstractionPattern AbstractionPattern::getOptional(AbstractionPattern object) { switch (object.getKind()) { @@ -183,6 +189,9 @@ AbstractionPattern::getOptional(AbstractionPattern object) { case Kind::CXXMethodType: case Kind::CurriedCXXMethodType: case Kind::PartialCurriedCXXMethodType: + case Kind::CXXOperatorMethodType: + case Kind::CurriedCXXOperatorMethodType: + case Kind::PartialCurriedCXXOperatorMethodType: case Kind::OpaqueFunction: case Kind::OpaqueDerivativeFunction: llvm_unreachable("cannot add optionality to non-type abstraction"); @@ -290,6 +299,9 @@ bool AbstractionPattern::matchesTuple(CanTupleType substType) { case Kind::CXXMethodType: case Kind::CurriedCXXMethodType: case Kind::PartialCurriedCXXMethodType: + case Kind::CXXOperatorMethodType: + case Kind::CurriedCXXOperatorMethodType: + case Kind::PartialCurriedCXXOperatorMethodType: case Kind::OpaqueFunction: case Kind::OpaqueDerivativeFunction: return false; @@ -364,6 +376,9 @@ AbstractionPattern::getTupleElementType(unsigned index) const { case Kind::CXXMethodType: case Kind::CurriedCXXMethodType: case Kind::PartialCurriedCXXMethodType: + case Kind::CXXOperatorMethodType: + case Kind::CurriedCXXOperatorMethodType: + case Kind::PartialCurriedCXXOperatorMethodType: case Kind::OpaqueFunction: case Kind::OpaqueDerivativeFunction: llvm_unreachable("function types are not tuples"); @@ -470,6 +485,8 @@ AbstractionPattern AbstractionPattern::getFunctionResultType() const { } case Kind::CXXMethodType: case Kind::PartialCurriedCXXMethodType: + case Kind::CXXOperatorMethodType: + case Kind::PartialCurriedCXXOperatorMethodType: return AbstractionPattern(getGenericSignatureForFunctionComponent(), getResultType(getType()), getCXXMethod()->getReturnType().getTypePtr()); @@ -488,6 +505,10 @@ AbstractionPattern AbstractionPattern::getFunctionResultType() const { case Kind::CurriedCXXMethodType: return getPartialCurriedCXXMethod(getGenericSignatureForFunctionComponent(), getResultType(getType()), getCXXMethod()); + case Kind::CurriedCXXOperatorMethodType: + return getPartialCurriedCXXOperatorMethod( + getGenericSignatureForFunctionComponent(), getResultType(getType()), + getCXXMethod()); case Kind::PartialCurriedObjCMethodType: case Kind::ObjCMethodType: return AbstractionPattern(getGenericSignatureForFunctionComponent(), @@ -525,6 +546,16 @@ AbstractionPattern::getFunctionParamType(unsigned index) const { assert(params.size() == 1); return getCXXMethodSelfPattern(params[0].getParameterType()); } + case Kind::CurriedCXXOperatorMethodType: { + auto params = cast(getType()).getParams(); + assert(params.size() == 1); + + // The formal metatype parameter to a C++ member operator function imported + // as a static method is dropped on the floor. Leave it untransformed. + return AbstractionPattern::getDiscard( + getGenericSignatureForFunctionComponent(), + params[0].getParameterType()); + } case Kind::CFunctionAsMethodType: case Kind::PartialCurriedCFunctionAsMethodType: { auto params = cast(getType()).getParams(); @@ -579,6 +610,26 @@ AbstractionPattern::getFunctionParamType(unsigned index) const { paramType, getClangFunctionParameterType(methodType, index)); } + case Kind::CXXOperatorMethodType: + case Kind::PartialCurriedCXXOperatorMethodType: { + auto params = cast(getType()).getParams(); + auto paramType = params[index].getParameterType(); + + // The first parameter holds the left-hand-side operand, which gets passed + // to the C++ function as the this pointer. + if (index == 0) + return getCXXMethodSelfPattern(paramType); + + // A parameter of type () does not correspond to a Clang parameter. + if (paramType->isVoid()) + return AbstractionPattern(paramType); + + // Otherwise, we're talking about the formal parameter clause. + auto methodType = getCXXMethod()->getType().getTypePtr(); + return AbstractionPattern( + getGenericSignatureForFunctionComponent(), paramType, + getClangFunctionParameterType(methodType, index - 1)); + } case Kind::CurriedObjCMethodType: { auto params = cast(getType()).getParams(); assert(params.size() == 1); @@ -660,6 +711,9 @@ AbstractionPattern AbstractionPattern::getOptionalObjectType() const { case Kind::CXXMethodType: case Kind::CurriedCXXMethodType: case Kind::PartialCurriedCXXMethodType: + case Kind::CXXOperatorMethodType: + case Kind::CurriedCXXOperatorMethodType: + case Kind::PartialCurriedCXXOperatorMethodType: case Kind::Tuple: case Kind::OpaqueFunction: case Kind::OpaqueDerivativeFunction: @@ -703,6 +757,9 @@ AbstractionPattern AbstractionPattern::getReferenceStorageReferentType() const { case Kind::CXXMethodType: case Kind::CurriedCXXMethodType: case Kind::PartialCurriedCXXMethodType: + case Kind::CXXOperatorMethodType: + case Kind::CurriedCXXOperatorMethodType: + case Kind::PartialCurriedCXXOperatorMethodType: case Kind::Tuple: case Kind::OpaqueFunction: case Kind::OpaqueDerivativeFunction: @@ -795,7 +852,16 @@ void AbstractionPattern::print(raw_ostream &out) const { case Kind::CXXMethodType: case Kind::CurriedCXXMethodType: case Kind::PartialCurriedCXXMethodType: - out << (getKind() == Kind::CXXMethodType + case Kind::CXXOperatorMethodType: + case Kind::CurriedCXXOperatorMethodType: + case Kind::PartialCurriedCXXOperatorMethodType: + out << (getKind() == Kind::CXXOperatorMethodType + ? "AP::CXXOperatorMethodType(" : + getKind() == Kind::CurriedCXXOperatorMethodType + ? "AP::CurriedCXXOperatorMethodType(" : + getKind() == Kind::PartialCurriedCXXOperatorMethodType + ? "AP::PartialCurriedCXXOperatorMethodType(" : + getKind() == Kind::CXXMethodType ? "AP::CXXMethodType(" : getKind() == Kind::CurriedCXXMethodType ? "AP::CurriedCXXMethodType(" @@ -927,6 +993,9 @@ const { case Kind::CXXMethodType: case Kind::CurriedCXXMethodType: case Kind::PartialCurriedCXXMethodType: + case Kind::CXXOperatorMethodType: + case Kind::CurriedCXXOperatorMethodType: + case Kind::PartialCurriedCXXOperatorMethodType: case Kind::ClangType: case Kind::Type: case Kind::Discard: diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index 0091d35779c08..b18402a549b7c 100644 --- a/lib/SIL/IR/SILFunctionType.cpp +++ b/lib/SIL/IR/SILFunctionType.cpp @@ -18,6 +18,7 @@ #define DEBUG_TYPE "libsil" #include "swift/AST/AnyFunctionRef.h" +#include "swift/AST/CanTypeVisitor.h" #include "swift/AST/Decl.h" #include "swift/AST/DiagnosticsSIL.h" #include "swift/AST/ForeignInfo.h" @@ -2783,7 +2784,8 @@ getSILFunctionTypeForClangDecl(TypeConverter &TC, const clang::Decl *clangDecl, } if (auto method = dyn_cast(clangDecl)) { - AbstractionPattern origPattern = + AbstractionPattern origPattern = method->isOverloadedOperator() ? + AbstractionPattern::getCXXOperatorMethod(origType, method): AbstractionPattern::getCXXMethod(origType, method); auto conventions = CXXMethodConventions(method); return getSILFunctionType(TC, TypeExpansionContext::minimal(), origPattern, @@ -4039,7 +4041,10 @@ getAbstractionPatternForConstant(ASTContext &ctx, SILDeclRef constant, assert(numParameterLists == 2); if (auto method = dyn_cast(clangDecl)) { // C++ method. - return AbstractionPattern::getCurriedCXXMethod(fnType, bridgedFn); + return method->isOverloadedOperator() + ? AbstractionPattern::getCurriedCXXOperatorMethod(fnType, + bridgedFn) + : AbstractionPattern::getCurriedCXXMethod(fnType, bridgedFn); } else { // C function imported as a method. return AbstractionPattern::getCurriedCFunctionAsMethod(fnType, @@ -4123,8 +4128,25 @@ TypeConverter::getLoweredFormalTypes(SILDeclRef constant, } auto partialFnPattern = bridgingFnPattern.getFunctionResultType(); - getBridgedParams(rep, partialFnPattern, methodParams, bridgedParams, - bridging); + for (unsigned i : indices(methodParams)) { + // C++ operators that are implemented as non-static member functions get + // imported into Swift as static methods that have an additional + // parameter for the left-hand-side operand instead of the receiver + // object. These are inout parameters and don't get bridged. + // TODO: Undo this if we stop using inout. + if (auto method = dyn_cast_or_null( + constant.getDecl()->getClangDecl())) { + if (i==0 && method->isOverloadedOperator()) { + bridgedParams.push_back(methodParams[0]); + continue; + } + } + + auto paramPattern = partialFnPattern.getFunctionParamType(i); + auto bridgedParam = + getBridgedParam(rep, paramPattern, methodParams[i], bridging); + bridgedParams.push_back(bridgedParam); + } bridgedResultType = getBridgedResultType(rep, diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index 92aa26eef1ff6..a45aaa0f3fb6c 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -28,6 +28,7 @@ #include "Varargs.h" #include "swift/AST/ASTContext.h" #include "swift/AST/ASTMangler.h" +#include "swift/AST/CanTypeVisitor.h" #include "swift/AST/Decl.h" #include "swift/AST/DiagnosticsCommon.h" #include "swift/AST/Expr.h" @@ -2108,7 +2109,8 @@ VarargsInfo Lowering::emitBeginVarargs(SILGenFunction &SGF, SILLocation loc, } ManagedValue Lowering::emitEndVarargs(SILGenFunction &SGF, SILLocation loc, - VarargsInfo &&varargs) { + VarargsInfo &&varargs, + unsigned numElements) { // Kill the abort cleanup. SGF.Cleanups.setCleanupState(varargs.getAbortCleanup(), CleanupState::Dead); @@ -2117,6 +2119,14 @@ ManagedValue Lowering::emitEndVarargs(SILGenFunction &SGF, SILLocation loc, if (array.hasCleanup()) SGF.Cleanups.setCleanupState(array.getCleanup(), CleanupState::Active); + // Array literals only need to be finalized, if the array is really allocated. + // In case of zero elements, no allocation is done, but the empty-array + // singleton is used. "Finalization" means to emit an end_cow_mutation + // instruction on the array. As the empty-array singleton is a read-only and + // shared object, it's not legal to do a end_cow_mutation on it. + if (numElements == 0) + return array; + return SGF.emitUninitializedArrayFinalization(loc, std::move(array)); } @@ -3900,7 +3910,7 @@ RValue RValueEmitter::visitCollectionExpr(CollectionExpr *E, SGFContext C) { SGF.Cleanups.setCleanupState(destCleanup, CleanupState::Dead); RValue array(SGF, loc, arrayType, - emitEndVarargs(SGF, loc, std::move(varargsInfo))); + emitEndVarargs(SGF, loc, std::move(varargsInfo), E->getNumElements())); array = scope.popPreservingValue(std::move(array)); diff --git a/lib/SILGen/SILGenProlog.cpp b/lib/SILGen/SILGenProlog.cpp index b6b564fa6a9d1..269c301fc3a14 100644 --- a/lib/SILGen/SILGenProlog.cpp +++ b/lib/SILGen/SILGenProlog.cpp @@ -15,6 +15,7 @@ #include "ManagedValue.h" #include "Scope.h" #include "swift/SIL/SILArgument.h" +#include "swift/AST/CanTypeVisitor.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/ParameterList.h" diff --git a/lib/SILGen/Varargs.h b/lib/SILGen/Varargs.h index 334b2baf9587c..0497c632101d2 100644 --- a/lib/SILGen/Varargs.h +++ b/lib/SILGen/Varargs.h @@ -68,7 +68,8 @@ VarargsInfo emitBeginVarargs(SILGenFunction &SGF, SILLocation loc, /// Successfully end a varargs emission sequence. ManagedValue emitEndVarargs(SILGenFunction &SGF, SILLocation loc, - VarargsInfo &&varargs); + VarargsInfo &&varargs, + unsigned numElements); } // end namespace Lowering } // end namespace swift diff --git a/lib/SILOptimizer/Mandatory/OSLogOptimization.cpp b/lib/SILOptimizer/Mandatory/OSLogOptimization.cpp index 9b0ded1b091ed..7f5551a01686c 100644 --- a/lib/SILOptimizer/Mandatory/OSLogOptimization.cpp +++ b/lib/SILOptimizer/Mandatory/OSLogOptimization.cpp @@ -540,13 +540,15 @@ static SILValue emitCodeForConstantArray(ArrayRef elements, assert(arrayAllocateFun); SILFunction *arrayFinalizeFun = nullptr; - if (FuncDecl *arrayFinalizeDecl = astContext.getFinalizeUninitializedArray()) { - std::string finalizeMangledName = - SILDeclRef(arrayFinalizeDecl, SILDeclRef::Kind::Func).mangle(); - arrayFinalizeFun = - module.findFunction(finalizeMangledName, SILLinkage::SharedExternal); - assert(arrayFinalizeFun); - module.linkFunction(arrayFinalizeFun); + if (numElements != 0) { + if (FuncDecl *arrayFinalizeDecl = astContext.getFinalizeUninitializedArray()) { + std::string finalizeMangledName = + SILDeclRef(arrayFinalizeDecl, SILDeclRef::Kind::Func).mangle(); + arrayFinalizeFun = + module.findFunction(finalizeMangledName, SILLinkage::SharedExternal); + assert(arrayFinalizeFun); + module.linkFunction(arrayFinalizeFun); + } } // Call the _allocateUninitializedArray function with numElementsSIL. The diff --git a/lib/SILOptimizer/SILCombiner/SILCombiner.h b/lib/SILOptimizer/SILCombiner/SILCombiner.h index cfd8207d089fe..6630010e5b7ae 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombiner.h +++ b/lib/SILOptimizer/SILCombiner/SILCombiner.h @@ -246,8 +246,11 @@ class SILCombiner : bool tryOptimizeKeypath(ApplyInst *AI); bool tryOptimizeInoutKeypath(BeginApplyInst *AI); bool tryOptimizeKeypathApplication(ApplyInst *AI, SILFunction *callee); - bool tryOptimizeKeypathKVCString(ApplyInst *AI, SILDeclRef callee); - + bool tryOptimizeKeypathOffsetOf(ApplyInst *AI, FuncDecl *calleeFn, + KeyPathInst *kp); + bool tryOptimizeKeypathKVCString(ApplyInst *AI, FuncDecl *calleeFn, + KeyPathInst *kp); + // Optimize concatenation of string literals. // Constant-fold concatenation of string literals known at compile-time. SILInstruction *optimizeConcatenationOfStringLiterals(ApplyInst *AI); diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp index 67090d1886a97..e71bba15b5f6c 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp +++ b/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp @@ -271,6 +271,130 @@ bool SILCombiner::tryOptimizeKeypathApplication(ApplyInst *AI, return true; } +/// Replaces a call of the getter of AnyKeyPath._storedInlineOffset with a +/// "constant" offset, in case of a keypath literal. +/// +/// "Constant" offset means a series of struct_element_addr and +/// tuple_element_addr instructions with a 0-pointer as base address. +/// These instructions can then be lowered to "real" constants in IRGen for +/// concrete types, or to metatype offset lookups for generic or resilient types. +/// +/// Replaces: +/// %kp = keypath ... +/// %offset = apply %_storedInlineOffset_method(%kp) +/// with: +/// %zero = integer_literal $Builtin.Word, 0 +/// %null_ptr = unchecked_trivial_bit_cast %zero to $Builtin.RawPointer +/// %null_addr = pointer_to_address %null_ptr +/// %projected_addr = struct_element_addr %null_addr +/// ... // other address projections +/// %offset_ptr = address_to_pointer %projected_addr +/// %offset_builtin_int = unchecked_trivial_bit_cast %offset_ptr +/// %offset_int = struct $Int (%offset_builtin_int) +/// %offset = enum $Optional, #Optional.some!enumelt, %offset_int +bool SILCombiner::tryOptimizeKeypathOffsetOf(ApplyInst *AI, + FuncDecl *calleeFn, + KeyPathInst *kp) { + auto *accessor = dyn_cast(calleeFn); + if (!accessor || !accessor->isGetter()) + return false; + + AbstractStorageDecl *storage = accessor->getStorage(); + DeclName name = storage->getName(); + if (!name.isSimpleName() || + (name.getBaseIdentifier().str() != "_storedInlineOffset")) + return false; + + KeyPathPattern *pattern = kp->getPattern(); + SubstitutionMap patternSubs = kp->getSubstitutions(); + CanType rootTy = pattern->getRootType().subst(patternSubs)->getCanonicalType(); + CanType parentTy = rootTy; + + // First check if _storedInlineOffset would return an offset or nil. Basically + // only stored struct and tuple elements produce an offset. Everything else + // (e.g. computed properties, class properties) result in nil. + bool hasOffset = true; + for (const KeyPathPatternComponent &component : pattern->getComponents()) { + switch (component.getKind()) { + case KeyPathPatternComponent::Kind::StoredProperty: { + + // Handle the special case of C tail-allocated arrays. IRGen would + // generate an undef offset for struct_element_addr of C tail-allocated + // arrays. + VarDecl *propDecl = component.getStoredPropertyDecl(); + if (propDecl->hasClangNode() && propDecl->getType()->isVoid()) + return false; + + if (!parentTy.getStructOrBoundGenericStruct()) + hasOffset = false; + break; + } + case KeyPathPatternComponent::Kind::TupleElement: + break; + case KeyPathPatternComponent::Kind::GettableProperty: + case KeyPathPatternComponent::Kind::SettableProperty: + // We cannot predict the offset of fields in resilient types, because it's + // unknown if a resilient field is a computed or stored property. + if (component.getExternalDecl()) + return false; + hasOffset = false; + break; + case KeyPathPatternComponent::Kind::OptionalChain: + case KeyPathPatternComponent::Kind::OptionalForce: + case KeyPathPatternComponent::Kind::OptionalWrap: + hasOffset = false; + break; + } + parentTy = component.getComponentType(); + } + + SILLocation loc = AI->getLoc(); + SILValue result; + + if (hasOffset) { + SILType rootAddrTy = SILType::getPrimitiveAddressType(rootTy); + SILValue rootAddr = Builder.createBaseAddrForOffset(loc, rootAddrTy); + + auto projector = KeyPathProjector::create(kp, rootAddr, loc, Builder); + if (!projector) + return false; + + // Create the address projections of the keypath. + SILType ptrType = SILType::getRawPointerType(Builder.getASTContext()); + SILValue offsetPtr; + projector->project(KeyPathProjector::AccessType::Get, [&](SILValue addr) { + offsetPtr = Builder.createAddressToPointer(loc, addr, ptrType); + }); + + // The result of the _storedInlineOffset call should be Optional. If + // not, something is wrong with the stdlib. Anyway, if it's not like we + // expect, bail. + SILType intType = AI->getType().getOptionalObjectType(); + if (!intType) + return false; + StructDecl *intDecl = intType.getStructOrBoundGenericStruct(); + if (!intDecl || intDecl->getStoredProperties().size() != 1) + return false; + VarDecl *member = intDecl->getStoredProperties()[0]; + CanType builtinIntTy = member->getType()->getCanonicalType(); + if (!isa(builtinIntTy)) + return false; + + // Convert the projected address back to an optional integer. + SILValue offset = Builder.createUncheckedBitCast(loc, offsetPtr, + SILType::getPrimitiveObjectType(builtinIntTy)); + SILValue offsetInt = Builder.createStruct(loc, intType, { offset }); + result = Builder.createOptionalSome(loc, offsetInt, AI->getType()); + } else { + // The keypath has no offset. + result = Builder.createOptionalNone(loc, AI->getType()); + } + AI->replaceAllUsesWith(result); + eraseInstFromFunction(*AI); + ++NumOptimizedKeypaths; + return true; +} + /// Try to optimize a keypath KVC string access on a literal key path. /// /// Replace: @@ -279,17 +403,8 @@ bool SILCombiner::tryOptimizeKeypathApplication(ApplyInst *AI, /// With: /// %string = string_literal "blah" bool SILCombiner::tryOptimizeKeypathKVCString(ApplyInst *AI, - SILDeclRef callee) { - if (AI->getNumArguments() != 1) { - return false; - } - if (!callee.hasDecl()) { - return false; - } - auto calleeFn = dyn_cast(callee.getDecl()); - if (!calleeFn) - return false; - + FuncDecl *calleeFn, + KeyPathInst *kp) { if (!calleeFn->getAttrs() .hasSemanticsAttr(semantics::KEYPATH_KVC_KEY_PATH_STRING)) return false; @@ -300,11 +415,6 @@ bool SILCombiner::tryOptimizeKeypathKVCString(ApplyInst *AI, if (!objTy || objTy.getStructOrBoundGenericStruct() != C.getStringDecl()) return false; - KeyPathInst *kp - = KeyPathProjector::getLiteralKeyPath(AI->getArgument(0)); - if (!kp || !kp->hasPattern()) - return false; - auto objcString = kp->getPattern()->getObjCString(); SILValue literalValue; @@ -357,10 +467,33 @@ bool SILCombiner::tryOptimizeKeypath(ApplyInst *AI) { return tryOptimizeKeypathApplication(AI, callee); } - if (auto method = dyn_cast(AI->getCallee())) { - return tryOptimizeKeypathKVCString(AI, method->getMember()); + // Try optimize keypath method calls. + auto *methodInst = dyn_cast(AI->getCallee()); + if (!methodInst) + return false; + + if (AI->getNumArguments() != 1) { + return false; + } + + SILDeclRef callee = methodInst->getMember(); + if (!callee.hasDecl()) { + return false; } + auto *calleeFn = dyn_cast(callee.getDecl()); + if (!calleeFn) + return false; + + KeyPathInst *kp = KeyPathProjector::getLiteralKeyPath(AI->getArgument(0)); + if (!kp || !kp->hasPattern()) + return false; + if (tryOptimizeKeypathOffsetOf(AI, calleeFn, kp)) + return true; + + if (tryOptimizeKeypathKVCString(AI, calleeFn, kp)) + return true; + return false; } diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp index 10b3a0d932eaa..a3e7ce416b79e 100644 --- a/lib/Sema/CSBindings.cpp +++ b/lib/Sema/CSBindings.cpp @@ -1035,7 +1035,7 @@ bool TypeVarBindingProducer::computeNext() { auto srcLocator = binding.getLocator(); if (srcLocator && srcLocator->isLastElement() && - !type->hasTypeVariable() && CS.isCollectionType(type)) { + !type->hasTypeVariable() && type->isKnownStdlibCollectionType()) { // If the type binding comes from the argument conversion, let's // instead of binding collection types directly, try to bind // using temporary type variables substituted for element diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 26a3d77a76f11..33551376f2312 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -500,7 +500,9 @@ bool MissingConformanceFailure::diagnoseTypeCannotConform( } emitDiagnostic(diag::type_cannot_conform, - nonConformingType->isExistentialType(), nonConformingType, + nonConformingType->isExistentialType(), + nonConformingType, + nonConformingType->isEqual(protocolType), protocolType); if (auto *OTD = dyn_cast(AffectedDecl)) { @@ -2087,7 +2089,8 @@ bool ContextualFailure::diagnoseAsError() { if (CTP == CTP_ForEachStmt) { if (fromType->isAnyExistentialType()) { emitDiagnostic(diag::type_cannot_conform, - /*isExistentialType=*/true, fromType, toType); + /*isExistentialType=*/true, fromType, + fromType->isEqual(toType), toType); return true; } @@ -3373,7 +3376,7 @@ bool MissingMemberFailure::diagnoseInLiteralCollectionContext() const { auto parentType = getType(parentExpr); - if (!isCollectionType(parentType) && !parentType->is()) + if (!parentType->isKnownStdlibCollectionType() && !parentType->is()) return false; if (isa(parentExpr)) { diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index 0c21f1de32997..16fa57735e282 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -208,11 +208,6 @@ class FailureDiagnostic { llvm::function_ref substitution = [](GenericTypeParamType *, Type) {}); - bool isCollectionType(Type type) const { - auto &cs = getConstraintSystem(); - return cs.isCollectionType(type); - } - bool isArrayType(Type type) const { auto &cs = getConstraintSystem(); return bool(cs.isArrayType(type)); diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 6341a41ea7237..e8a6e7091d2ca 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -3708,7 +3708,7 @@ bool ConstraintSystem::repairFailures( // func foo(_: [T]) {} // foo(1) // expected '[Int]', got 'Int' // ``` - if (isCollectionType(rhs)) { + if (rhs->isKnownStdlibCollectionType()) { std::function getArrayOrSetType = [&](Type type) -> Type { if (auto eltTy = isArrayType(type)) return getArrayOrSetType(*eltTy); diff --git a/lib/Sema/ConstraintGraph.cpp b/lib/Sema/ConstraintGraph.cpp index 7037e3b9c32c7..b85048cf9d255 100644 --- a/lib/Sema/ConstraintGraph.cpp +++ b/lib/Sema/ConstraintGraph.cpp @@ -442,24 +442,15 @@ llvm::TinyPtrVector ConstraintGraph::gatherConstraints( llvm::function_ref acceptConstraintFn) { llvm::TinyPtrVector constraints; // Whether we should consider this constraint at all. - auto rep = CS.getRepresentative(typeVar); auto shouldConsiderConstraint = [&](Constraint *constraint) { - // For a one-way constraint, only consider it when the type variable - // is on the right-hand side of the the binding, and the left-hand side of - // the binding is one of the type variables currently under consideration. + // For a one-way constraint, only consider it when the left-hand side of + // the binding is one of the type variables currently under consideration, + // as only such constraints need solving for this component. Note that we + // don't perform any other filtering, as the constraint system should be + // responsible for checking any other conditions. if (constraint->isOneWayConstraint()) { - auto lhsTypeVar = - constraint->getFirstType()->castTo(); - if (!CS.isActiveTypeVariable(lhsTypeVar)) - return false; - - SmallVector rhsTypeVars; - constraint->getSecondType()->getTypeVariables(rhsTypeVars); - for (auto rhsTypeVar : rhsTypeVars) { - if (CS.getRepresentative(rhsTypeVar) == rep) - return true; - } - return false; + auto lhsTypeVar = constraint->getFirstType()->castTo(); + return CS.isActiveTypeVariable(lhsTypeVar); } return true; diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 940a4deb6923f..701aeac560264 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -878,18 +878,6 @@ Optional ConstraintSystem::isSetType(Type type) { return None; } -bool ConstraintSystem::isCollectionType(Type type) { - if (auto *structType = type->getAs()) { - auto &ctx = type->getASTContext(); - auto *decl = structType->getDecl(); - if (decl == ctx.getArrayDecl() || decl == ctx.getDictionaryDecl() || - decl == ctx.getSetDecl()) - return true; - } - - return false; -} - bool ConstraintSystem::isAnyHashableType(Type type) { if (auto st = type->getAs()) { auto &ctx = type->getASTContext(); diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index 348fe54a66baa..e6370f4b260ca 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -3348,9 +3348,6 @@ class ConstraintSystem { /// element type of the set. static Optional isSetType(Type t); - /// Determine if the type in question is one of the known collection types. - static bool isCollectionType(Type t); - /// Determine if the type in question is AnyHashable. static bool isAnyHashableType(Type t); diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index 86fe5774348aa..5152ff23e24c8 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -3357,7 +3357,14 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType, const auto &fromElt = fromTuple->getElement(i); const auto &toElt = toTuple->getElement(i); - if (fromElt.getName() != toElt.getName()) + // We should only perform name validation if both element have a label, + // because unlabeled tuple elements can be converted to labeled ones + // e.g. + // + // let tup: (Any, Any) = (1, 1) + // _ = tup as! (a: Int, Int) + if ((!fromElt.getName().empty() && !toElt.getName().empty()) && + fromElt.getName() != toElt.getName()) return failed(); auto result = checkElementCast(fromElt.getType(), toElt.getType(), @@ -3527,8 +3534,9 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType, (toType->isAnyObject() || fromType->isAnyObject())) return CheckedCastKind::ValueCast; - // A cast from an existential type to a concrete type does not succeed. For - // example: + // If we have a cast from an existential type to a concrete type that we + // statically know doesn't conform to the protocol, mark the cast as always + // failing. For example: // // struct S {} // enum FooError: Error { case bar } @@ -3541,19 +3549,10 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType, // } // } // - // Note: we relax the restriction if the type we're casting to is a - // non-final class because it's possible that we might have a subclass - // that conforms to the protocol. - if (fromExistential && !toExistential) { - if (auto NTD = toType->getAnyNominal()) { - if (!toType->is() || NTD->isFinal()) { - auto protocolDecl = - dyn_cast_or_null(fromType->getAnyNominal()); - if (protocolDecl && - !conformsToProtocol(toType, protocolDecl, dc)) { - return failed(); - } - } + if (auto *protocolDecl = + dyn_cast_or_null(fromType->getAnyNominal())) { + if (!couldDynamicallyConformToProtocol(toType, protocolDecl, dc)) { + return failed(); } } @@ -3616,10 +3615,12 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType, return CheckedCastKind::ValueCast; } - // If the destination type can be a supertype of the source type, we are - // performing what looks like an upcast except it rebinds generic - // parameters. - if (fromType->isBindableTo(toType)) + // We perform an upcast while rebinding generic parameters if it's possible + // to substitute the generic arguments of the source type with the generic + // archetypes of the destination type. Or, if it's possible to substitute + // the generic arguments of the destination type with the generic archetypes + // of the source type, we perform a downcast instead. + if (toType->isBindableTo(fromType) || fromType->isBindableTo(toType)) return CheckedCastKind::ValueCast; // Objective-C metaclasses are subclasses of NSObject in the ObjC runtime, @@ -3636,8 +3637,8 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType, } } - // We can conditionally cast from NSError to an Error-conforming - // type. This is handled in the runtime, so it doesn't need a special cast + // We can conditionally cast from NSError to an Error-conforming type. + // This is handled in the runtime, so it doesn't need a special cast // kind. if (Context.LangOpts.EnableObjCInterop) { auto nsObject = Context.getNSObjectType(); diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index d73d8fe8408b0..f955e19b4d7a7 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -4312,7 +4312,8 @@ void swift::diagnoseConformanceFailure(Type T, if (!T->isObjCExistentialType()) { diags.diagnose(ComplainLoc, diag::type_cannot_conform, true, - T, Proto->getDeclaredType()); + T, T->isEqual(Proto->getDeclaredType()), + Proto->getDeclaredType()); return; } @@ -4526,6 +4527,40 @@ TypeChecker::conformsToProtocol(Type T, ProtocolDecl *Proto, DeclContext *DC, return lookupResult; } +bool +TypeChecker::couldDynamicallyConformToProtocol(Type type, ProtocolDecl *Proto, + DeclContext *DC) { + // An existential may have a concrete underlying type with protocol conformances + // we cannot know statically. + if (type->isExistentialType()) + return true; + + // A generic archetype may have protocol conformances we cannot know + // statically. + if (type->is()) + return true; + + // A non-final class might have a subclass that conforms to the protocol. + if (auto *classDecl = type->getClassOrBoundGenericClass()) { + if (!classDecl->isFinal()) + return true; + } + + ModuleDecl *M = DC->getParentModule(); + // For standard library collection types such as Array, Set or Dictionary + // which have custom casting machinery implemented in situations like: + // + // func encodable(_ value: Encodable) { + // _ = value as! [String : Encodable] + // } + // we are skipping checking conditional requirements using lookupConformance, + // as an intermediate collection cast can dynamically change if the conditions + // are met or not. + if (type->isKnownStdlibCollectionType()) + return !M->lookupConformance(type, Proto).isInvalid(); + return !conformsToProtocol(type, Proto, DC).isInvalid(); +} + /// Exposes TypeChecker functionality for querying protocol conformance. /// Returns a valid ProtocolConformanceRef only if all conditional /// requirements are successfully resolved. diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index f4c1c6ca61cf4..bfe306236c17d 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -884,6 +884,17 @@ ProtocolConformanceRef conformsToProtocol(Type T, ProtocolDecl *Proto, DeclContext *DC, SourceLoc ComplainLoc = SourceLoc()); +/// This is similar to \c conformsToProtocol, but returns \c true for cases where +/// the type \p T could be dynamically cast to \p Proto protocol, such as a non-final +/// class where a subclass conforms to \p Proto. +/// +/// \param DC The context in which to check conformance. This affects, for +/// example, extension visibility. +/// +/// +/// \returns True if \p T conforms to the protocol \p Proto, false otherwise. +bool couldDynamicallyConformToProtocol(Type T, ProtocolDecl *Proto, + DeclContext *DC); /// Completely check the given conformance. void checkConformance(NormalProtocolConformance *conformance); diff --git a/stdlib/public/Differentiation/TgmathDerivatives.swift.gyb b/stdlib/public/Differentiation/TgmathDerivatives.swift.gyb index dec835649ce5c..e5f40d3ce9335 100644 --- a/stdlib/public/Differentiation/TgmathDerivatives.swift.gyb +++ b/stdlib/public/Differentiation/TgmathDerivatives.swift.gyb @@ -14,9 +14,9 @@ import Swift -#if canImport(Darwin) +#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) import Darwin.C.tgmath -#elseif canImport(Glibc) +#elseif os(Linux) || os(FreeBSD) || os(OpenBSD) || os(PS4) || os(Android) || os(Cygwin) || os(Haiku) || os(WASI) import Glibc #elseif os(Windows) import MSVCRT diff --git a/stdlib/public/Platform/MachError.swift b/stdlib/public/Platform/MachError.swift index 8ab16b50d943c..5d506dcefcbc5 100644 --- a/stdlib/public/Platform/MachError.swift +++ b/stdlib/public/Platform/MachError.swift @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -#if canImport(Darwin) +#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) /// Enumeration describing Mach error codes. @objc public enum MachErrorCode : Int32 { @@ -202,4 +202,4 @@ public enum MachErrorCode : Int32 { /// The requested property cannot be changed at this time. case policyStatic = 51 } -#endif // canImport(Darwin) +#endif // os(macOS) || os(iOS) || os(tvOS) || os(watchOS) diff --git a/stdlib/public/Platform/POSIXError.swift b/stdlib/public/Platform/POSIXError.swift index 2e3b5fd333e9f..5e644ae7a7237 100644 --- a/stdlib/public/Platform/POSIXError.swift +++ b/stdlib/public/Platform/POSIXError.swift @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -#if canImport(Darwin) +#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) /// Enumeration describing POSIX error codes. @objc diff --git a/stdlib/public/Platform/Platform.swift b/stdlib/public/Platform/Platform.swift index f4f9b3236f560..5243b516379f9 100644 --- a/stdlib/public/Platform/Platform.swift +++ b/stdlib/public/Platform/Platform.swift @@ -17,7 +17,7 @@ import SwiftOverlayShims import ucrt #endif -#if canImport(Darwin) +#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) //===----------------------------------------------------------------------===// // MacTypes.h //===----------------------------------------------------------------------===// @@ -103,7 +103,7 @@ public var errno : Int32 { // stdio.h //===----------------------------------------------------------------------===// -#if canImport(Darwin) || os(FreeBSD) || os(PS4) +#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) || os(FreeBSD) || os(PS4) public var stdin : UnsafeMutablePointer { get { return __stdinp @@ -248,7 +248,7 @@ public var S_IFBLK: mode_t { return mode_t(0o060000) } public var S_IFREG: mode_t { return mode_t(0o100000) } public var S_IFLNK: mode_t { return mode_t(0o120000) } public var S_IFSOCK: mode_t { return mode_t(0o140000) } -#if canImport(Darwin) +#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) public var S_IFWHT: mode_t { return mode_t(0o160000) } #endif @@ -271,7 +271,7 @@ public var S_ISUID: mode_t { return mode_t(0o004000) } public var S_ISGID: mode_t { return mode_t(0o002000) } public var S_ISVTX: mode_t { return mode_t(0o001000) } -#if canImport(Darwin) +#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) public var S_ISTXT: mode_t { return S_ISVTX } public var S_IREAD: mode_t { return S_IRUSR } public var S_IWRITE: mode_t { return S_IWUSR } @@ -315,7 +315,7 @@ public func ioctl( // unistd.h //===----------------------------------------------------------------------===// -#if canImport(Darwin) +#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) @available(*, unavailable, message: "Please use threads or posix_spawn*()") public func fork() -> Int32 { fatalError("unavailable function can't be called") @@ -331,7 +331,7 @@ public func vfork() -> Int32 { // signal.h //===----------------------------------------------------------------------===// -#if canImport(Darwin) +#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) public var SIG_DFL: sig_t? { return nil } public var SIG_IGN: sig_t { return unsafeBitCast(1, to: sig_t.self) } public var SIG_ERR: sig_t { return unsafeBitCast(-1, to: sig_t.self) } @@ -395,10 +395,10 @@ public typealias Semaphore = UnsafeMutablePointer /// The value returned by `sem_open()` in the case of failure. public var SEM_FAILED: Semaphore? { -#if canImport(Darwin) - // The value is ABI. Value verified to be correct for macOS, iOS, watchOS, tvOS. +#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) + // The value is ABI. Value verified to be correct for OS X, iOS, watchOS, tvOS. return Semaphore(bitPattern: -1) -#elseif canImport(Glibc) +#elseif os(Linux) || os(FreeBSD) || os(OpenBSD) || os(PS4) || os(Android) || os(Cygwin) || os(Haiku) || os(WASI) // The value is ABI. Value verified to be correct on Glibc. return Semaphore(bitPattern: 0) #else @@ -429,7 +429,7 @@ public func sem_open( //===----------------------------------------------------------------------===// // Some platforms don't have `extern char** environ` imported from C. -#if canImport(Darwin) || os(FreeBSD) || os(OpenBSD) || os(PS4) +#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) || os(FreeBSD) || os(OpenBSD) || os(PS4) public var environ: UnsafeMutablePointer?> { return _swift_stdlib_getEnviron() } diff --git a/stdlib/public/Platform/TiocConstants.swift b/stdlib/public/Platform/TiocConstants.swift index 3bc51f955e93a..272f7e242e64d 100644 --- a/stdlib/public/Platform/TiocConstants.swift +++ b/stdlib/public/Platform/TiocConstants.swift @@ -13,7 +13,7 @@ // Tty ioctl request constants, needed only on Darwin and FreeBSD. // Constants available on all platforms, also available on Linux. -#if canImport(Darwin) || os(FreeBSD) || os(Haiku) +#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) || os(FreeBSD) || os(Haiku) /// Set exclusive use of tty. public var TIOCEXCL: UInt { return 0x2000740d } @@ -115,7 +115,7 @@ public var TIOCGLTC: UInt { return 0x40067474 } // Darwin only constants, also available on Linux. -#if canImport(Darwin) +#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) /// Get termios struct. public var TIOCGETA: UInt { return 0x40487413 } diff --git a/stdlib/public/Platform/tgmath.swift.gyb b/stdlib/public/Platform/tgmath.swift.gyb index 1a06f3b75503f..cf8c9fa88069b 100644 --- a/stdlib/public/Platform/tgmath.swift.gyb +++ b/stdlib/public/Platform/tgmath.swift.gyb @@ -234,7 +234,7 @@ public func ${ufunc}(_ x: ${T}) -> ${T} { % end -#if canImport(Darwin) +#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) // Unary intrinsic functions // Note these have a corresponding LLVM intrinsic % for T, ufunc in TypedUnaryIntrinsicFunctions(): diff --git a/stdlib/public/core/Availability.swift b/stdlib/public/core/Availability.swift index dd8b5f1d025af..55da2e8314a77 100644 --- a/stdlib/public/core/Availability.swift +++ b/stdlib/public/core/Availability.swift @@ -24,7 +24,7 @@ public func _stdlib_isOSVersionAtLeast( _ minor: Builtin.Word, _ patch: Builtin.Word ) -> Builtin.Int1 { -#if canImport(Darwin) +#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) if Int(major) == 9999 { return true._value } diff --git a/stdlib/public/core/CTypes.swift b/stdlib/public/core/CTypes.swift index a615263d77089..b1f2432f29adb 100644 --- a/stdlib/public/core/CTypes.swift +++ b/stdlib/public/core/CTypes.swift @@ -67,7 +67,7 @@ public typealias CFloat = Float public typealias CDouble = Double /// The C 'long double' type. -#if canImport(Darwin) +#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) // On Darwin, long double is Float80 on x86, and Double otherwise. #if arch(x86_64) || arch(i386) public typealias CLongDouble = Float80 @@ -231,7 +231,7 @@ extension UInt { } /// A wrapper around a C `va_list` pointer. -#if arch(arm64) && !(canImport(Darwin) || os(Windows)) +#if arch(arm64) && !(os(macOS) || os(iOS) || os(tvOS) || os(watchOS) || os(Windows)) @frozen public struct CVaListPointer { @usableFromInline // unsafe-performance diff --git a/stdlib/public/core/ContiguousArrayBuffer.swift b/stdlib/public/core/ContiguousArrayBuffer.swift index 0519e44821b95..4b6ac4a5ee6fc 100644 --- a/stdlib/public/core/ContiguousArrayBuffer.swift +++ b/stdlib/public/core/ContiguousArrayBuffer.swift @@ -454,18 +454,12 @@ internal struct _ContiguousArrayBuffer: _ArrayBufferProtocol { @_alwaysEmitIntoClient internal var isImmutable: Bool { get { -// TODO: Enable COW runtime checks by default (when INTERNAL_CHECKS_ENABLED -// is set). Currently there is a problem with remote AST which needs to be -// fixed. -#if ENABLE_COW_RUNTIME_CHECKS if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { return capacity == 0 || _swift_isImmutableCOWBuffer(_storage) } -#endif return true } nonmutating set { -#if ENABLE_COW_RUNTIME_CHECKS if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { if newValue { if capacity > 0 { @@ -481,17 +475,14 @@ internal struct _ContiguousArrayBuffer: _ArrayBufferProtocol { "re-setting mutable array buffer to mutable") } } -#endif } } @_alwaysEmitIntoClient internal var isMutable: Bool { -#if ENABLE_COW_RUNTIME_CHECKS if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { return !_swift_isImmutableCOWBuffer(_storage) } -#endif return true } #endif diff --git a/stdlib/public/core/UnicodeScalarProperties.swift b/stdlib/public/core/UnicodeScalarProperties.swift index e0f17727cb8c3..d0c39c2efee3b 100644 --- a/stdlib/public/core/UnicodeScalarProperties.swift +++ b/stdlib/public/core/UnicodeScalarProperties.swift @@ -590,7 +590,7 @@ extension Unicode.Scalar.Properties { return _hasBinaryProperty(__swift_stdlib_UCHAR_CHANGES_WHEN_NFKC_CASEFOLDED) } -#if canImport(Darwin) +#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) // FIXME: These properties were introduced in ICU 57, but Ubuntu 16.04 comes // with ICU 55 so the values won't be correct there. Exclude them on // non-Darwin platforms for now; bundling ICU with the toolchain would resolve diff --git a/stdlib/public/core/VarArgs.swift b/stdlib/public/core/VarArgs.swift index cc356bd2dae74..d6d9458e96f4a 100644 --- a/stdlib/public/core/VarArgs.swift +++ b/stdlib/public/core/VarArgs.swift @@ -91,7 +91,7 @@ internal let _countGPRegisters = 16 @usableFromInline internal let _registerSaveWords = _countGPRegisters -#elseif arch(arm64) && !(canImport(Darwin) || os(Windows)) +#elseif arch(arm64) && !(os(macOS) || os(iOS) || os(tvOS) || os(watchOS) || os(Windows)) // ARM Procedure Call Standard for aarch64. (IHI0055B) // The va_list type may refer to any parameter in a parameter list may be in one // of three memory locations depending on its type and position in the argument @@ -419,7 +419,7 @@ extension Float80: CVarArg, _CVarArgAligned { } #endif -#if (arch(x86_64) && !os(Windows)) || arch(s390x) || (arch(arm64) && !(canImport(Darwin) || os(Windows))) +#if (arch(x86_64) && !os(Windows)) || arch(s390x) || (arch(arm64) && !(os(macOS) || os(iOS) || os(tvOS) || os(watchOS) || os(Windows))) /// An object that can manage the lifetime of storage backing a /// `CVaListPointer`. diff --git a/stdlib/public/runtime/Casting.cpp b/stdlib/public/runtime/Casting.cpp index c5d33eb10e580..374d0dfe745bf 100644 --- a/stdlib/public/runtime/Casting.cpp +++ b/stdlib/public/runtime/Casting.cpp @@ -1183,13 +1183,6 @@ swift_dynamicCastMetatypeImpl(const Metadata *sourceType, } break; - case MetadataKind::Existential: { - auto targetTypeAsExistential = static_cast(targetType); - if (_conformsToProtocols(nullptr, sourceType, targetTypeAsExistential, nullptr)) - return origSourceType; - return nullptr; - } - default: return nullptr; } diff --git a/stdlib/public/runtime/HeapObject.cpp b/stdlib/public/runtime/HeapObject.cpp index 5357d5b30dd75..50177c633e933 100644 --- a/stdlib/public/runtime/HeapObject.cpp +++ b/stdlib/public/runtime/HeapObject.cpp @@ -901,6 +901,7 @@ WeakReference *swift::swift_weakTakeAssign(WeakReference *dest, /// Returns true if the "immutable" flag is set on \p object. /// /// Used for runtime consistency checking of COW buffers. +SWIFT_CC(swift) SWIFT_RUNTIME_EXPORT bool _swift_isImmutableCOWBuffer(HeapObject *object) { return object->refCounts.isImmutableCOWBuffer(); @@ -910,6 +911,7 @@ bool _swift_isImmutableCOWBuffer(HeapObject *object) { /// value of the flag. /// /// Used for runtime consistency checking of COW buffers. +SWIFT_CC(swift) SWIFT_RUNTIME_EXPORT bool _swift_setImmutableCOWBuffer(HeapObject *object, bool immutable) { return object->refCounts.setIsImmutableCOWBuffer(immutable); diff --git a/test/Constraints/casts.swift b/test/Constraints/casts.swift index 0c84b6cbf1b70..02d6a29224ac0 100644 --- a/test/Constraints/casts.swift +++ b/test/Constraints/casts.swift @@ -235,8 +235,8 @@ func test_tuple_casts_no_warn() { _ = arr as! [(Foo, Foo, Foo)] // expected-warning {{cast from '[(Any, Any)]' to unrelated type '[(Foo, Foo, Foo)]' always fails}} _ = tup as! (Foo, Foo, Foo) // expected-warning {{cast from '(Any, Any)' to unrelated type '(Foo, Foo, Foo)' always fails}} - _ = arr as! [(a: Foo, Foo)] // expected-warning {{cast from '[(Any, Any)]' to unrelated type '[(a: Foo, Foo)]' always fails}} - _ = tup as! (a: Foo, Foo) // expected-warning {{cast from '(Any, Any)' to unrelated type '(a: Foo, Foo)' always fails}} + _ = arr as! [(a: Foo, Foo)] // Ok + _ = tup as! (a: Foo, Foo) // Ok } infix operator ^^^ @@ -335,3 +335,71 @@ func test_compatibility_coercions(_ arr: [Int], _ optArr: [Int]?, _ dict: [Strin // The array can also be inferred to be [Any]. _ = ([] ?? []) as Array // expected-warning {{left side of nil coalescing operator '??' has non-optional type '[Any]', so the right side is never used}} } + +// SR-13088 +protocol JSON { } +protocol JSONLeaf: JSON {} +extension Int: JSONLeaf { } +extension Array: JSON where Element: JSON { } + +protocol SR13035Error: Error {} +class ChildError: SR13035Error {} + +protocol AnyC { + func foo() +} + +protocol AnyEvent {} + +protocol A { + associatedtype C: AnyC +} + +protocol EventA: A { + associatedtype Event +} + +typealias Container + = (event: Namespace.Event, c: Namespace.C) where Namespace: EventA + +enum ConcreteA: EventA { + struct C: AnyC { + func foo() {} + } + + enum Event: AnyEvent { + case test + } +} + +func tests_SR13088_false_positive_always_fail_casts() { + // SR-13081 + let x: JSON = [4] // [4] + _ = x as? [Any] // Ok + + // SR-13035 + func SR13035(_ child: Result, _: Result) { + let _ = child as? Result // Ok + } + + func SR13035_1(_ child: Result, parent: Result) { + _ = child as? Result // Ok + _ = parent as? Result // OK + } + + // SR-11434 and SR-12321 + func encodable(_ value: Encodable) { + _ = value as! [String : Encodable] // Ok + _ = value as? [String: Encodable] // Ok + } + + // SR-13025 + func coordinate(_ event: AnyEvent, from c: AnyC) { + switch (event, c) { + case let container as Container: // OK + container.c.foo() + default: + break + } + } +} diff --git a/test/Constraints/diagnostics.swift b/test/Constraints/diagnostics.swift index bb7c762e1212b..b4c4ce1f61839 100644 --- a/test/Constraints/diagnostics.swift +++ b/test/Constraints/diagnostics.swift @@ -51,9 +51,9 @@ f0(i, i, // expected-error@:7 {{cannot convert value of type 'Int' to expected a // Cannot conform to protocols. -f5(f4) // expected-error {{type '(Int) -> Int' cannot conform to 'P2'; only struct/enum/class types can conform to protocols}} -f5((1, "hello")) // expected-error {{type '(Int, String)' cannot conform to 'P2'; only struct/enum/class types can conform to protocols}} -f5(Int.self) // expected-error {{type 'Int.Type' cannot conform to 'P2'; only struct/enum/class types can conform to protocols}} +f5(f4) // expected-error {{type '(Int) -> Int' cannot conform to 'P2'; only concrete types such as structs, enums and classes can conform to protocols}} +f5((1, "hello")) // expected-error {{type '(Int, String)' cannot conform to 'P2'; only concrete types such as structs, enums and classes can conform to protocols}} +f5(Int.self) // expected-error {{type 'Int.Type' cannot conform to 'P2'; only concrete types such as structs, enums and classes can conform to protocols}} // Tuple element not convertible. f0(i, @@ -104,7 +104,7 @@ func f8(_ n: T, _ f: @escaping (T) -> T) {} // expected-note {{where 'T' f8(3, f4) // expected-error {{global function 'f8' requires that 'Int' conform to 'P2'}} typealias Tup = (Int, Double) func f9(_ x: Tup) -> Tup { return x } -f8((1,2.0), f9) // expected-error {{type 'Tup' (aka '(Int, Double)') cannot conform to 'P2'; only struct/enum/class types can conform to protocols}} +f8((1,2.0), f9) // expected-error {{type 'Tup' (aka '(Int, Double)') cannot conform to 'P2'; only concrete types such as structs, enums and classes can conform to protocols}} // QoI: Incorrect diagnostic for calling nonexistent members on literals 1.doesntExist(0) // expected-error {{value of type 'Int' has no member 'doesntExist'}} diff --git a/test/Constraints/function_builder_diags.swift b/test/Constraints/function_builder_diags.swift index 359fa6bdad05d..552b7a2a3088b 100644 --- a/test/Constraints/function_builder_diags.swift +++ b/test/Constraints/function_builder_diags.swift @@ -179,7 +179,7 @@ struct Label : P where L : P { // expected-note 2 {{'L' declared as parameter } func test_51167632() -> some P { - AnyP(G { // expected-error {{type 'Label<_>.Type' cannot conform to 'P'; only struct/enum/class types can conform to protocols}} + AnyP(G { // expected-error {{type 'Label<_>.Type' cannot conform to 'P'; only concrete types such as structs, enums and classes can conform to protocols}} Text("hello") Label // expected-error {{generic parameter 'L' could not be inferred}} // expected-note@-1 {{explicitly specify the generic arguments to fix this issue}} {{10-10=<<#L: P#>>}} diff --git a/test/Constraints/generics.swift b/test/Constraints/generics.swift index 450af7f1212bd..bb4ed1d14f0f1 100644 --- a/test/Constraints/generics.swift +++ b/test/Constraints/generics.swift @@ -188,7 +188,7 @@ func r22459135() { // QoI: Friendlier error message for "[] as Set" // QoI: "argument for generic parameter 'Element' could not be inferred" lacks context -_ = [] as Set // expected-error {{value of protocol type 'Any' cannot conform to 'Hashable'; only struct/enum/class types can conform to protocols}} +_ = [] as Set // expected-error {{protocol 'Any' as a type cannot conform to 'Hashable'; only concrete types such as structs, enums and classes can conform to protocols}} // expected-note@-1 {{required by generic struct 'Set' where 'Element' = 'Any'}} diff --git a/test/Constraints/rdar64890308.swift b/test/Constraints/rdar64890308.swift new file mode 100644 index 0000000000000..b745850068f5d --- /dev/null +++ b/test/Constraints/rdar64890308.swift @@ -0,0 +1,31 @@ +// RUN: %target-typecheck-verify-swift -parse-stdlib + +// rdar://64890308: Make sure we don't leave one-way constraints unsolved. + +import Swift + +@_functionBuilder +class ArrayBuilder { + static func buildBlock() -> [Element] { [] } + static func buildBlock(_ elt: Element) -> [Element] { [elt] } + static func buildBlock(_ elts: Element...) -> [Element] { elts } +} + +func foo(@ArrayBuilder fn: () -> [T]) {} + +// FIXME(SR-13132): This should compile. +foo { // expected-error {{type of expression is ambiguous without more context}} + "" +} + +struct S { + init(_: T.Type) {} + func overloaded() -> [T] { [] } + func overloaded(_ x: T) -> [T] { [x] } + func overloaded(_ x: T...) -> [T] { x } +} + +func bar(_ x: T, _ fn: (T, T.Type) -> [T]) {} +bar("") { x, ty in + (Builtin.one_way(S(ty).overloaded(x))) +} diff --git a/test/Generics/conditional_conformances_literals.swift b/test/Generics/conditional_conformances_literals.swift index 932a51aa76f76..37f4729f14d17 100644 --- a/test/Generics/conditional_conformances_literals.swift +++ b/test/Generics/conditional_conformances_literals.swift @@ -128,9 +128,9 @@ func combined() { // Needs self conforming protocols: let _: Conforms = [[0: [1 : [works]] as Conforms]] - // expected-error@-1 {{value of protocol type 'Conforms' cannot conform to 'Conforms'; only struct/enum/class types can conform to protocols}} + // expected-error@-1 {{protocol 'Conforms' as a type cannot conform to the protocol itself; only concrete types such as structs, enums and classes can conform to protocols}} let _: Conforms = [[0: [1 : [fails]] as Conforms]] // expected-error@-1 {{protocol 'Conforms' requires that 'Fails' conform to 'Conforms'}} - // expected-error@-2 {{value of protocol type 'Conforms' cannot conform to 'Conforms'; only struct/enum/class types can conform to protocols}} + // expected-error@-2 {{protocol 'Conforms' as a type cannot conform to the protocol itself; only concrete types such as structs, enums and classes can conform to protocols}} } diff --git a/test/Generics/existential_restrictions.swift b/test/Generics/existential_restrictions.swift index fbf2f29375fc5..425308b798901 100644 --- a/test/Generics/existential_restrictions.swift +++ b/test/Generics/existential_restrictions.swift @@ -23,7 +23,7 @@ func fAOE(_ t: AnyObject) { } func fT(_ t: T) { } func testPassExistential(_ p: P, op: OP, opp: OP & P, cp: CP, sp: SP, any: Any, ao: AnyObject) { - fP(p) // expected-error{{value of protocol type 'P' cannot conform to 'P'; only struct/enum/class types can conform to protocols}} + fP(p) // expected-error{{protocol 'P' as a type cannot conform to the protocol itself; only concrete types such as structs, enums and classes can conform to protocols}} fAO(p) // expected-error{{global function 'fAO' requires that 'P' be a class type}} fAOE(p) // expected-error{{argument type 'P' expected to be an instance of a class or class-constrained type}} fT(p) @@ -37,8 +37,8 @@ func testPassExistential(_ p: P, op: OP, opp: OP & P, cp: CP, sp: SP, any: Any, fAOE(cp) fT(cp) - fP(opp) // expected-error{{value of protocol type 'OP & P' cannot conform to 'P'; only struct/enum/class types can conform to protocols}} - fOP(opp) // expected-error{{value of protocol type 'OP & P' cannot conform to 'OP'; only struct/enum/class types can conform to protocols}} + fP(opp) // expected-error{{protocol 'OP & P' as a type cannot conform to 'P'; only concrete types such as structs, enums and classes can conform to protocols}} + fOP(opp) // expected-error{{protocol 'OP & P' as a type cannot conform to 'OP'; only concrete types such as structs, enums and classes can conform to protocols}} fAO(opp) // expected-error{{global function 'fAO' requires that 'OP & P' be a class type}} fAOE(opp) fT(opp) @@ -64,9 +64,9 @@ class GAO {} // expected-note 2{{requirement specified as 'T' : ' func blackHole(_ t: Any) {} func testBindExistential() { - blackHole(GP

()) // expected-error{{value of protocol type 'P' cannot conform to 'P'; only struct/enum/class types can conform to protocols}} + blackHole(GP

()) // expected-error{{protocol 'P' as a type cannot conform to the protocol itself; only concrete types such as structs, enums and classes can conform to protocols}} blackHole(GOP()) - blackHole(GCP()) // expected-error{{value of protocol type 'CP' cannot conform to 'CP'; only struct/enum/class types can conform to protocols}} + blackHole(GCP()) // expected-error{{protocol 'CP' as a type cannot conform to the protocol itself; only concrete types such as structs, enums and classes can conform to protocols}} blackHole(GAO

()) // expected-error{{'GAO' requires that 'P' be a class type}} blackHole(GAO()) blackHole(GAO()) // expected-error{{'GAO' requires that 'CP' be a class type}} @@ -92,5 +92,5 @@ func foo() { // generic no overloads error path. The error should actually talk // about the return type, and this can happen in other contexts as well; // tracks improving QoI here. - allMine.takeAll() // expected-error{{value of protocol type 'Mine' cannot conform to 'Mine'; only struct/enum/class types can conform to protocols}} + allMine.takeAll() // expected-error{{protocol 'Mine' as a type cannot conform to the protocol itself; only concrete types such as structs, enums and classes can conform to protocols}} } diff --git a/test/IRGen/osx-targets.swift b/test/IRGen/osx-targets.swift index 32d0f9e9cf2c9..deb62e65ff4c3 100644 --- a/test/IRGen/osx-targets.swift +++ b/test/IRGen/osx-targets.swift @@ -1,6 +1,8 @@ // RUN: %swift %s -emit-ir | %FileCheck %s // RUN: %swift -target x86_64-apple-macosx10.51 %s -emit-ir | %FileCheck -check-prefix=CHECK-SPECIFIC %s -// RUN: %swift -target x86_64-apple-darwin55 %s -emit-ir | %FileCheck -check-prefix=CHECK-SPECIFIC %s + +// disable this test until macOS 11 support lands in Swift. +// : %swift -target x86_64-apple-darwin55 %s -emit-ir | %FileCheck -check-prefix=CHECK-SPECIFIC %s // REQUIRES: OS=macosx diff --git a/test/Interop/Cxx/class/Inputs/module.modulemap b/test/Interop/Cxx/class/Inputs/module.modulemap index cb61582d4b941..d4460da89db64 100644 --- a/test/Interop/Cxx/class/Inputs/module.modulemap +++ b/test/Interop/Cxx/class/Inputs/module.modulemap @@ -21,3 +21,7 @@ module MemberVariables { module ProtocolConformance { header "protocol-conformance.h" } + +module SynthesizedInitializers { + header "synthesized-initializers.h" +} diff --git a/test/Interop/Cxx/class/Inputs/synthesized-initializers.h b/test/Interop/Cxx/class/Inputs/synthesized-initializers.h new file mode 100644 index 0000000000000..da20bf036bd10 --- /dev/null +++ b/test/Interop/Cxx/class/Inputs/synthesized-initializers.h @@ -0,0 +1,5 @@ +struct EmptyStruct {}; + +struct IntBox { + int x; +}; diff --git a/test/Interop/Cxx/class/synthesized-initializers.swift b/test/Interop/Cxx/class/synthesized-initializers.swift new file mode 100644 index 0000000000000..ea74f8ab4eecb --- /dev/null +++ b/test/Interop/Cxx/class/synthesized-initializers.swift @@ -0,0 +1,46 @@ +// RUN: %target-swift-frontend -I %S/Inputs -enable-cxx-interop -emit-silgen %s | %FileCheck %s + +import SynthesizedInitializers + +// CHECK-LABEL: sil shared [transparent] [serializable] [ossa] @$sSo11EmptyStructVABycfC : $@convention(method) (@thin EmptyStruct.Type) -> EmptyStruct +// CHECK: bb0(%{{[0-9]+}} : $@thin EmptyStruct.Type): +// CHECK-NEXT: [[BOX:%.*]] = alloc_box ${ var EmptyStruct } +// CHECK-NEXT: [[UNINIT:%.*]] = mark_uninitialized [rootself] [[BOX]] : ${ var EmptyStruct } +// CHECK-NEXT: [[PTR:%.*]] = project_box [[UNINIT]] : ${ var EmptyStruct }, 0 +// CHECK-NEXT: [[OBJ:%.*]] = builtin "zeroInitializer"() : $EmptyStruct +// CHECK-NEXT: [[PA:%.*]] = begin_access [modify] [unknown] [[PTR]] : $*EmptyStruct +// CHECK-NEXT: assign [[OBJ]] to [[PA]] +// CHECK-NEXT: end_access [[PA]] +// CHECK-NEXT: [[OUT:%.*]] = load [trivial] [[PTR]] +// CHECK-NEXT: destroy_value [[UNINIT]] +// CHECK-NEXT: return [[OUT]] +// CHECK-LABEL: end sil function '$sSo11EmptyStructVABycfC' +public func emptyTypeNoArgInit() { + let e = EmptyStruct() +} + +// CHECK-LABEL: sil shared [transparent] [serializable] [ossa] @$sSo6IntBoxVABycfC : $@convention(method) (@thin IntBox.Type) -> IntBox +// CHECK: bb0(%{{[0-9]+}} : $@thin IntBox.Type): +// CHECK-NEXT: [[BOX:%.*]] = alloc_box ${ var IntBox } +// CHECK-NEXT: [[UNINIT:%.*]] = mark_uninitialized [rootself] [[BOX]] : ${ var IntBox } +// CHECK-NEXT: [[PTR:%.*]] = project_box [[UNINIT]] : ${ var IntBox }, 0 +// CHECK-NEXT: [[OBJ:%.*]] = builtin "zeroInitializer"() : $IntBox +// CHECK-NEXT: [[PA:%.*]] = begin_access [modify] [unknown] [[PTR]] : $*IntBox +// CHECK-NEXT: assign [[OBJ]] to [[PA]] +// CHECK-NEXT: end_access [[PA]] +// CHECK-NEXT: [[OUT:%.*]] = load [trivial] [[PTR]] +// CHECK-NEXT: destroy_value [[UNINIT]] +// CHECK-NEXT: return [[OUT]] +// CHECK-LABEL: end sil function '$sSo6IntBoxVABycfC' +public func singleMemberTypeNoArgInit() { + let i = IntBox() +} + +// CHECK-LABEL: sil shared [transparent] [serializable] [ossa] @$sSo6IntBoxV1xABs5Int32V_tcfC : $@convention(method) (Int32, @thin IntBox.Type) -> IntBox +// CHECK: bb0([[I:%[0-9]+]] : $Int32, %{{[0-9]+}} : $@thin IntBox.Type): +// CHECK-NEXT: [[S:%.*]] = struct $IntBox ([[I]] : $Int32) +// CHECK-NEXT: return [[S]] +// CHECK-LABEL: end sil function '$sSo6IntBoxV1xABs5Int32V_tcfC' +public func singleMemberTypeValueInit() { + let i = IntBox(x: 42) +} diff --git a/test/Interop/Cxx/operators/Inputs/member-inline.h b/test/Interop/Cxx/operators/Inputs/member-inline.h new file mode 100644 index 0000000000000..8204aa0644848 --- /dev/null +++ b/test/Interop/Cxx/operators/Inputs/member-inline.h @@ -0,0 +1,9 @@ +#ifndef TEST_INTEROP_CXX_OPERATORS_INPUTS_MEMBER_INLINE_H +#define TEST_INTEROP_CXX_OPERATORS_INPUTS_MEMBER_INLINE_H + +struct IntBox { + int value; + IntBox operator+(IntBox rhs) { return IntBox{.value = value + rhs.value}; } +}; + +#endif diff --git a/test/Interop/Cxx/operators/Inputs/module.modulemap b/test/Interop/Cxx/operators/Inputs/module.modulemap index 2cc3fa14cd834..a811dbe61fa0e 100644 --- a/test/Interop/Cxx/operators/Inputs/module.modulemap +++ b/test/Interop/Cxx/operators/Inputs/module.modulemap @@ -1,3 +1,7 @@ +module MemberInline { + header "member-inline.h" +} + module NonMemberInline { header "non-member-inline.h" } diff --git a/test/Interop/Cxx/operators/member-inline-irgen.swift b/test/Interop/Cxx/operators/member-inline-irgen.swift new file mode 100644 index 0000000000000..797682073a393 --- /dev/null +++ b/test/Interop/Cxx/operators/member-inline-irgen.swift @@ -0,0 +1,11 @@ +// RUN: %target-swift-emit-ir %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s +// +// We can't yet call member functions correctly on Windows (SR-13129). +// XFAIL: OS=windows-msvc + +import MemberInline + +public func add(_ lhs: inout IntBox, _ rhs: IntBox) -> IntBox { lhs + rhs } + +// CHECK: call [[RES:i32|i64]] [[NAME:@(_ZN6IntBoxplES_|"\?\?HIntBox@@QEAA\?AU0@U0@@Z")]](%struct.IntBox* {{%[0-9]+}}, {{i32|\[1 x i32\]|i64|%struct.IntBox\* byval align 4}} {{%[0-9]+}}) +// CHECK: define linkonce_odr [[RES]] [[NAME]](%struct.IntBox* %this, {{i32 %rhs.coerce|\[1 x i32\] %rhs.coerce|i64 %rhs.coerce|%struct.IntBox\* byval\(%struct.IntBox\) align 4 %rhs}}) diff --git a/test/Interop/Cxx/operators/member-inline-module-interface.swift b/test/Interop/Cxx/operators/member-inline-module-interface.swift new file mode 100644 index 0000000000000..aef362f01c207 --- /dev/null +++ b/test/Interop/Cxx/operators/member-inline-module-interface.swift @@ -0,0 +1,5 @@ +// RUN: %target-swift-ide-test -print-module -module-to-print=MemberInline -I %S/Inputs -source-filename=x -enable-cxx-interop | %FileCheck %s + +// CHECK: struct IntBox { +// CHECK: static func + (lhs: inout IntBox, rhs: IntBox) -> IntBox +// CHECK: } diff --git a/test/Interop/Cxx/operators/member-inline-silgen.swift b/test/Interop/Cxx/operators/member-inline-silgen.swift new file mode 100644 index 0000000000000..96d89a4a4fa86 --- /dev/null +++ b/test/Interop/Cxx/operators/member-inline-silgen.swift @@ -0,0 +1,14 @@ +// RUN: %target-swift-emit-sil %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s + +import MemberInline + +public func add(_ lhs: inout IntBox, _ rhs: IntBox) -> IntBox { lhs + rhs } + +// CHECK: bb0([[SELF:%.*]] : $*IntBox, [[RHS:%.*]] : $IntBox): + +// CHECK: [[SELFACCESS:%.*]] = begin_access [modify] [static] [[SELF]] : $*IntBox +// CHECK: [[OP:%.*]] = function_ref [[NAME:@(_ZN6IntBoxplES_|\?\?HIntBox@@QEAA\?AU0@U0@@Z)]] : $@convention(c) (@inout IntBox, IntBox) -> IntBox +// CHECK: apply [[OP]]([[SELFACCESS]], [[RHS]]) : $@convention(c) (@inout IntBox, IntBox) -> IntBox +// CHECK: end_access [[SELFACCESS]] : $*IntBox + +// CHECK: sil [clang IntBox."+"] [[NAME]] : $@convention(c) (@inout IntBox, IntBox) -> IntBox diff --git a/test/Interop/Cxx/operators/member-inline-typechecker.swift b/test/Interop/Cxx/operators/member-inline-typechecker.swift new file mode 100644 index 0000000000000..635875a05c71b --- /dev/null +++ b/test/Interop/Cxx/operators/member-inline-typechecker.swift @@ -0,0 +1,8 @@ +// RUN: %target-typecheck-verify-swift -I %S/Inputs -enable-cxx-interop + +import MemberInline + +var lhs = IntBox(value: 42) +let rhs = IntBox(value: 23) + +let resultPlus = lhs + rhs diff --git a/test/Interop/Cxx/operators/member-inline.swift b/test/Interop/Cxx/operators/member-inline.swift new file mode 100644 index 0000000000000..0313d849da70b --- /dev/null +++ b/test/Interop/Cxx/operators/member-inline.swift @@ -0,0 +1,22 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop) +// +// REQUIRES: executable_test +// +// We can't yet call member functions correctly on Windows (SR-13129). +// XFAIL: OS=windows-msvc + +import MemberInline +import StdlibUnittest + +var OperatorsTestSuite = TestSuite("Operators") + +OperatorsTestSuite.test("plus") { + var lhs = IntBox(value: 42) + let rhs = IntBox(value: 23) + + let result = lhs + rhs + + expectEqual(65, result.value) +} + +runAllTests() diff --git a/test/Interpreter/generic_casts.swift b/test/Interpreter/generic_casts.swift index ecace2ee16136..73f1837d20ab9 100644 --- a/test/Interpreter/generic_casts.swift +++ b/test/Interpreter/generic_casts.swift @@ -1,9 +1,10 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -Onone %s -o %t/a.out -// RUN: %target-run %t/a.out | %FileCheck --check-prefix CHECK --check-prefix CHECK-ONONE %s // RUN: %target-build-swift -O %s -o %t/a.out.optimized // RUN: %target-codesign %t/a.out.optimized -// RUN: %target-run %t/a.out.optimized | %FileCheck %s +// +// RUN: %target-run %t/a.out | %FileCheck --check-prefix CHECK %s +// RUN: %target-run %t/a.out.optimized | %FileCheck --check-prefix CHECK %s // REQUIRES: executable_test // FIXME: rdar://problem/19648117 Needs splitting objc parts out @@ -140,42 +141,50 @@ class PC: P {} class PCSub: PC {} // `is` checks -func nongenericAnyIsPConforming(type: Any.Type) -> Bool { +func nongenericAnyIsPType(type: Any.Type) -> Bool { // `is P.Type` tests whether the argument conforms to `P` // Note: this can only be true for a concrete type, never a protocol return type is P.Type } -func nongenericAnyIsPSubtype(type: Any.Type) -> Bool { +func nongenericAnyIsPProtocol(type: Any.Type) -> Bool { + // `P.Protocol` is the metatype for `P` (the type of `P.self`) // `is P.Protocol` tests whether the argument is a subtype of `P` // In particular, it is true for `P.self` return type is P.Protocol } -func nongenericAnyIsPAndAnyObjectConforming(type: Any.Type) -> Bool { +func nongenericAnyIsPAndAnyObjectType(type: Any.Type) -> Bool { return type is (P & AnyObject).Type } -func nongenericAnyIsPAndPCSubConforming(type: Any.Type) -> Bool { +func nongenericAnyIsPAndAnyObjectProtocol(type: Any.Type) -> Bool { + return type is (P & AnyObject).Protocol +} +func nongenericAnyIsPAndPCSubType(type: Any.Type) -> Bool { return type is (P & PCSub).Type } func genericAnyIs(type: Any.Type, to: T.Type, expected: Bool) -> Bool { // If we're testing against a runtime that doesn't have the fix this tests, // just pretend we got it right. if #available(macOS 10.15.4, iOS 13.4, watchOS 6.2, tvOS 13.4, *) { + // Remember: If `T` is bound to `P`, then `T.Type` is `P.Protocol` return type is T.Type } else { return expected } } // `as?` checks -func nongenericAnyAsConditionalPConforming(type: Any.Type) -> Bool { +func nongenericAnyAsConditionalPType(type: Any.Type) -> Bool { return (type as? P.Type) != nil } -func nongenericAnyAsConditionalPSubtype(type: Any.Type) -> Bool { +func nongenericAnyAsConditionalPProtocol(type: Any.Type) -> Bool { return (type as? P.Protocol) != nil } -func nongenericAnyAsConditionalPAndAnyObjectConforming(type: Any.Type) -> Bool { +func nongenericAnyAsConditionalPAndAnyObjectType(type: Any.Type) -> Bool { return (type as? (P & AnyObject).Type) != nil } -func nongenericAnyAsConditionalPAndPCSubConforming(type: Any.Type) -> Bool { +func nongenericAnyAsConditionalPAndAnyObjectProtocol(type: Any.Type) -> Bool { + return (type as? (P & AnyObject).Protocol) != nil +} +func nongenericAnyAsConditionalPAndPCSubType(type: Any.Type) -> Bool { return (type as? (P & PCSub).Type) != nil } func genericAnyAsConditional(type: Any.Type, to: T.Type, expected: Bool) -> Bool { @@ -190,19 +199,19 @@ func genericAnyAsConditional(type: Any.Type, to: T.Type, expected: Bool) -> B // `as!` checks func blackhole(_ : T) { } -func nongenericAnyAsUnconditionalPConforming(type: Any.Type) -> Bool { +func nongenericAnyAsUnconditionalPType(type: Any.Type) -> Bool { blackhole(type as! P.Type) return true } -func nongenericAnyAsUnconditionalPSubtype(type: Any.Type) -> Bool { +func nongenericAnyAsUnconditionalPProtocol(type: Any.Type) -> Bool { blackhole(type as! P.Protocol) return true } -func nongenericAnyAsUnconditionalPAndAnyObjectConforming(type: Any.Type) -> Bool { +func nongenericAnyAsUnconditionalPAndAnyObjectType(type: Any.Type) -> Bool { blackhole(type as! (P & AnyObject).Type) return true } -func nongenericAnyAsUnconditionalPAndPCSubConforming(type: Any.Type) -> Bool { +func nongenericAnyAsUnconditionalPAndPCSubType(type: Any.Type) -> Bool { blackhole(type as! (P & PCSub).Type) return true } @@ -215,135 +224,153 @@ func genericAnyAsUnconditional(type: Any.Type, to: T.Type, expected: Bool) -> // CHECK-LABEL: casting types to protocols with generics: print("casting types to protocols with generics:") -print(nongenericAnyIsPConforming(type: P.self)) // CHECK: false -print(nongenericAnyIsPSubtype(type: P.self)) // CHECK: true -print(genericAnyIs(type: P.self, to: P.self, expected: true)) // CHECK: true -print(nongenericAnyIsPConforming(type: PS.self)) // CHECK: true -print(genericAnyIs(type: PS.self, to: P.self, expected: true)) // CHECK-ONONE: true -print(nongenericAnyIsPConforming(type: PE.self)) // CHECK: true -print(genericAnyIs(type: PE.self, to: P.self, expected: true)) // CHECK-ONONE: true -print(nongenericAnyIsPConforming(type: PC.self)) // CHECK: true -print(genericAnyIs(type: PC.self, to: P.self, expected: true)) // CHECK-ONONE: true -print(nongenericAnyIsPConforming(type: PCSub.self)) // CHECK: true -print(genericAnyIs(type: PCSub.self, to: P.self, expected: true)) // CHECK-ONONE: true +print(#line, nongenericAnyIsPType(type: P.self)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyIsPProtocol(type: P.self)) // CHECK: [[@LINE]] true +print(#line, genericAnyIs(type: P.self, to: P.self, expected: true)) // CHECK: [[@LINE]] true +print(#line, nongenericAnyIsPType(type: PS.self)) // CHECK: [[@LINE]] true +print(#line, PS() is P) // CHECK: [[@LINE]] true +// One candidate for a Swift type theory holds that +// `A is a subtype of B iff A.self is metatype` +// In that theory, `PS() is P` above would imply that +// `PS.self is P.Protocol` below must also be true. +// But that theory is not the one that Swift currently +// implements. +print(#line, nongenericAnyIsPProtocol(type: PS.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyIs(type: PS.self, to: P.self, expected: false)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyIsPType(type: PE.self)) // CHECK: [[@LINE]] true +print(#line, nongenericAnyIsPProtocol(type: PE.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyIs(type: PE.self, to: P.self, expected: false)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyIsPType(type: PC.self)) // CHECK: [[@LINE]] true +print(#line, nongenericAnyIsPProtocol(type: PC.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyIs(type: PC.self, to: P.self, expected: false)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyIsPType(type: PCSub.self)) // CHECK: [[@LINE]] true +print(#line, nongenericAnyIsPProtocol(type: PCSub.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyIs(type: PCSub.self, to: P.self, expected: false)) // CHECK: [[@LINE]] false // CHECK-LABEL: conditionally casting types to protocols with generics: -print("conditionally casting types to protocols with generics:") -print(nongenericAnyAsConditionalPConforming(type: P.self)) // CHECK: false -print(nongenericAnyAsConditionalPSubtype(type: P.self)) // CHECK: true -print(genericAnyAsConditional(type: P.self, to: P.self, expected: true)) // CHECK: true -print(nongenericAnyAsConditionalPConforming(type: PS.self)) // CHECK: true -print(genericAnyAsConditional(type: PS.self, to: P.self, expected: true)) // CHECK-ONONE: true -print(nongenericAnyAsConditionalPConforming(type: PE.self)) // CHECK: true -print(genericAnyAsConditional(type: PE.self, to: P.self, expected: true)) // CHECK-ONONE: true -print(nongenericAnyAsConditionalPConforming(type: PC.self)) // CHECK: true -print(genericAnyAsConditional(type: PC.self, to: P.self, expected: true)) // CHECK-ONONE: true -print(nongenericAnyAsConditionalPConforming(type: PCSub.self)) // CHECK: true -print(genericAnyAsConditional(type: PCSub.self, to: P.self, expected: true)) // CHECK-ONONE: true +print(#line, "conditionally casting types to protocols with generics:") +print(#line, nongenericAnyAsConditionalPType(type: P.self)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyAsConditionalPProtocol(type: P.self)) // CHECK: [[@LINE]] true +print(#line, genericAnyAsConditional(type: P.self, to: P.self, expected: true)) // CHECK: [[@LINE]] true +print(#line, nongenericAnyAsConditionalPType(type: PS.self)) // CHECK: [[@LINE]] true +print(#line, nongenericAnyAsConditionalPProtocol(type: PS.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyAsConditional(type: PS.self, to: P.self, expected: false)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyAsConditionalPType(type: PE.self)) // CHECK: [[@LINE]] true +print(#line, nongenericAnyAsConditionalPProtocol(type: PE.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyAsConditional(type: PE.self, to: P.self, expected: false)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyAsConditionalPType(type: PC.self)) // CHECK: [[@LINE]] true +print(#line, nongenericAnyAsConditionalPProtocol(type: PC.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyAsConditional(type: PC.self, to: P.self, expected: false)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyAsConditionalPType(type: PCSub.self)) // CHECK: [[@LINE]] true +print(#line, nongenericAnyAsConditionalPProtocol(type: PCSub.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyAsConditional(type: PCSub.self, to: P.self, expected: false)) // CHECK: [[@LINE]] false // CHECK-LABEL: unconditionally casting types to protocols with generics: -print("unconditionally casting types to protocols with generics:") -//print(nongenericAnyAsUnconditionalPConforming(type: P.self)) // expected to trap -print(nongenericAnyAsUnconditionalPSubtype(type: P.self)) // CHECK: true -print(genericAnyAsUnconditional(type: P.self, to: P.self, expected: true)) // CHECK: true -print(nongenericAnyAsUnconditionalPConforming(type: PS.self)) // CHECK: true -print(genericAnyAsUnconditional(type: PS.self, to: P.self, expected: true)) // CHECK: true -print(nongenericAnyAsUnconditionalPConforming(type: PE.self)) // CHECK: true -print(genericAnyAsUnconditional(type: PE.self, to: P.self, expected: true)) // CHECK: true -print(nongenericAnyAsUnconditionalPConforming(type: PC.self)) // CHECK: true -print(genericAnyAsUnconditional(type: PC.self, to: P.self, expected: true)) // CHECK: true -print(nongenericAnyAsUnconditionalPConforming(type: PCSub.self)) // CHECK: true -print(genericAnyAsUnconditional(type: PCSub.self, to: P.self, expected: true)) // CHECK: true +print(#line, "unconditionally casting types to protocols with generics:") +//print(#line, nongenericAnyAsUnconditionalPType(type: P.self)) // expected to trap +print(#line, nongenericAnyAsUnconditionalPProtocol(type: P.self)) // CHECK: [[@LINE]] true +print(#line, genericAnyAsUnconditional(type: P.self, to: P.self, expected: true)) // CHECK: [[@LINE]] true +print(#line, nongenericAnyAsUnconditionalPType(type: PS.self)) // CHECK: [[@LINE]] true +print(#line, genericAnyAsUnconditional(type: PS.self, to: P.self, expected: true)) // CHECK: [[@LINE]] true +print(#line, nongenericAnyAsUnconditionalPType(type: PE.self)) // CHECK: [[@LINE]] true +print(#line, genericAnyAsUnconditional(type: PE.self, to: P.self, expected: true)) // CHECK: [[@LINE]] true +print(#line, nongenericAnyAsUnconditionalPType(type: PC.self)) // CHECK: [[@LINE]] true +print(#line, genericAnyAsUnconditional(type: PC.self, to: P.self, expected: true)) // CHECK: [[@LINE]] true +print(#line, nongenericAnyAsUnconditionalPType(type: PCSub.self)) // CHECK: [[@LINE]] true +print(#line, genericAnyAsUnconditional(type: PCSub.self, to: P.self, expected: true)) // CHECK: [[@LINE]] true // CHECK-LABEL: casting types to protocol & AnyObject existentials: -print("casting types to protocol & AnyObject existentials:") -print(nongenericAnyIsPAndAnyObjectConforming(type: PS.self)) // CHECK: false -print(genericAnyIs(type: PS.self, to: (P & AnyObject).self, expected: false)) // CHECK: false -print(nongenericAnyIsPAndAnyObjectConforming(type: PE.self)) // CHECK: false -print(genericAnyIs(type: PE.self, to: (P & AnyObject).self, expected: false)) // CHECK: false -print(nongenericAnyIsPAndAnyObjectConforming(type: PC.self)) // CHECK: true -print(genericAnyIs(type: PC.self, to: (P & AnyObject).self, expected: true)) // CHECK-ONONE: true -print(nongenericAnyIsPAndAnyObjectConforming(type: PCSub.self)) // CHECK: true -print(genericAnyIs(type: PCSub.self, to: (P & AnyObject).self, expected: true)) // CHECK-ONONE: true -print(nongenericAnyAsConditionalPAndAnyObjectConforming(type: PS.self)) // CHECK: false -print(genericAnyAsConditional(type: PS.self, to: (P & AnyObject).self, expected: false)) // CHECK: false -print(nongenericAnyAsConditionalPAndAnyObjectConforming(type: PE.self)) // CHECK: false -print(genericAnyAsConditional(type: PE.self, to: (P & AnyObject).self, expected: false)) // CHECK: false -print(nongenericAnyAsConditionalPAndAnyObjectConforming(type: PC.self)) // CHECK: true -print(genericAnyAsConditional(type: PC.self, to: (P & AnyObject).self, expected: true)) // CHECK-ONONE: true -print(nongenericAnyAsConditionalPAndAnyObjectConforming(type: PCSub.self)) // CHECK: true -print(genericAnyAsConditional(type: PCSub.self, to: (P & AnyObject).self, expected: true)) // CHECK-ONONE: true +print(#line, "casting types to protocol & AnyObject existentials:") +print(#line, nongenericAnyIsPAndAnyObjectType(type: PS.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyIs(type: PS.self, to: (P & AnyObject).self, expected: false)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyIsPAndAnyObjectType(type: PE.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyIs(type: PE.self, to: (P & AnyObject).self, expected: false)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyIsPAndAnyObjectType(type: PC.self)) // CHECK: [[@LINE]] true +print(#line, nongenericAnyIsPAndAnyObjectProtocol(type: PC.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyIs(type: PC.self, to: (P & AnyObject).self, expected: false)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyIsPAndAnyObjectType(type: PCSub.self)) // CHECK: [[@LINE]] true +print(#line, nongenericAnyIsPAndAnyObjectProtocol(type: PCSub.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyIs(type: PCSub.self, to: (P & AnyObject).self, expected: false)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyAsConditionalPAndAnyObjectType(type: PS.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyAsConditional(type: PS.self, to: (P & AnyObject).self, expected: false)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyAsConditionalPAndAnyObjectType(type: PE.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyAsConditional(type: PE.self, to: (P & AnyObject).self, expected: false)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyAsConditionalPAndAnyObjectType(type: PC.self)) // CHECK: [[@LINE]] true +print(#line, nongenericAnyAsConditionalPAndAnyObjectProtocol(type: PC.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyAsConditional(type: PC.self, to: (P & AnyObject).self, expected: false)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyAsConditionalPAndAnyObjectType(type: PCSub.self)) // CHECK: [[@LINE]] true +print(#line, genericAnyAsConditional(type: PCSub.self, to: (P & AnyObject).self, expected: false)) // CHECK: [[@LINE]] false // CHECK-LABEL: casting types to protocol & class existentials: -print("casting types to protocol & class existentials:") -print(nongenericAnyIsPAndPCSubConforming(type: PS.self)) // CHECK: false -print(genericAnyIs(type: PS.self, to: (P & PCSub).self, expected: false)) // CHECK: false -print(nongenericAnyIsPAndPCSubConforming(type: PE.self)) // CHECK: false -print(genericAnyIs(type: PE.self, to: (P & PCSub).self, expected: false)) // CHECK: false -//print(nongenericAnyIsPAndPCSubConforming(type: PC.self)) // CHECK-SR-11565: false -- FIXME: reenable this when SR-11565 is fixed -print(genericAnyIs(type: PC.self, to: (P & PCSub).self, expected: false)) // CHECK: false -print(nongenericAnyIsPAndPCSubConforming(type: PCSub.self)) // CHECK: true -print(genericAnyIs(type: PCSub.self, to: (P & PCSub).self, expected: true)) // CHECK-ONONE: true -print(nongenericAnyAsConditionalPAndPCSubConforming(type: PS.self)) // CHECK: false -print(genericAnyAsConditional(type: PS.self, to: (P & PCSub).self, expected: false)) // CHECK: false -print(nongenericAnyAsConditionalPAndPCSubConforming(type: PE.self)) // CHECK: false -print(genericAnyAsConditional(type: PE.self, to: (P & PCSub).self, expected: false)) // CHECK: false -//print(nongenericAnyAsConditionalPAndPCSubConforming(type: PC.self)) // CHECK-SR-11565: false -- FIXME: reenable this when SR-11565 is fixed -print(genericAnyAsConditional(type: PC.self, to: (P & PCSub).self, expected: false)) // CHECK: false -print(nongenericAnyAsConditionalPAndPCSubConforming(type: PCSub.self)) // CHECK: true -print(genericAnyAsConditional(type: PCSub.self, to: (P & PCSub).self, expected: true)) // CHECK-ONONE: true +print(#line, "casting types to protocol & class existentials:") +print(#line, nongenericAnyIsPAndPCSubType(type: PS.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyIs(type: PS.self, to: (P & PCSub).self, expected: false)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyIsPAndPCSubType(type: PE.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyIs(type: PE.self, to: (P & PCSub).self, expected: false)) // CHECK: [[@LINE]] false +//print(#line, nongenericAnyIsPAndPCSubType(type: PC.self)) // CHECK-SR-11565: [[@LINE]] false -- FIXME: reenable this when SR-11565 is fixed +print(#line, genericAnyIs(type: PC.self, to: (P & PCSub).self, expected: false)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyIsPAndPCSubType(type: PCSub.self)) // CHECK: [[@LINE]] true +print(#line, genericAnyIs(type: PCSub.self, to: (P & PCSub).self, expected: false)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyAsConditionalPAndPCSubType(type: PS.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyAsConditional(type: PS.self, to: (P & PCSub).self, expected: false)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyAsConditionalPAndPCSubType(type: PE.self)) // CHECK: [[@LINE]] false +print(#line, genericAnyAsConditional(type: PE.self, to: (P & PCSub).self, expected: false)) // CHECK: [[@LINE]] false +// print(#line, nongenericAnyAsConditionalPAndPCSubType(type: PC.self)) // CHECK-SR-11565: [[@LINE]] false -- FIXME: reenable this when SR-11565 is fixed +print(#line, genericAnyAsConditional(type: PC.self, to: (P & PCSub).self, expected: false)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyAsConditionalPAndPCSubType(type: PCSub.self)) // CHECK: [[@LINE]] true +print(#line, genericAnyAsConditional(type: PCSub.self, to: (P & PCSub).self, expected: false)) // CHECK: [[@LINE]] false // CHECK-LABEL: type comparisons: -print("type comparisons:\n") -print(allMetasToAllMetas(Int.self, Int.self)) // CHECK: true -print(allMetasToAllMetas(Int.self, Float.self)) // CHECK: false -print(allMetasToAllMetas(C.self, C.self)) // CHECK: true -print(allMetasToAllMetas(D.self, C.self)) // CHECK: true -print(allMetasToAllMetas(C.self, D.self)) // CHECK: false -print(C.self is D.Type) // CHECK: false -print((D.self as C.Type) is D.Type) // CHECK: true +print(#line, "type comparisons:\n") +print(#line, allMetasToAllMetas(Int.self, Int.self)) // CHECK: [[@LINE]] true +print(#line, allMetasToAllMetas(Int.self, Float.self)) // CHECK: [[@LINE]] false +print(#line, allMetasToAllMetas(C.self, C.self)) // CHECK: [[@LINE]] true +print(#line, allMetasToAllMetas(D.self, C.self)) // CHECK: [[@LINE]] true +print(#line, allMetasToAllMetas(C.self, D.self)) // CHECK: [[@LINE]] false +print(#line, C.self is D.Type) // CHECK: [[@LINE]] false +print(#line, (D.self as C.Type) is D.Type) // CHECK: [[@LINE]] true let t: Any.Type = type(of: 1 as Any) -print(t is Int.Type) // CHECK: true -print(t is Float.Type) // CHECK: false -print(t is C.Type) // CHECK: false +print(#line, t is Int.Type) // CHECK: [[@LINE]] true +print(#line, t is Float.Type) // CHECK: [[@LINE]] false +print(#line, t is C.Type) // CHECK: [[@LINE]] false let u: Any.Type = type(of: (D() as Any)) -print(u is C.Type) // CHECK: true -print(u is D.Type) // CHECK: true -print(u is E.Type) // CHECK: false -print(u is Int.Type) // CHECK: false +print(#line, u is C.Type) // CHECK: [[@LINE]] true +print(#line, u is D.Type) // CHECK: [[@LINE]] true +print(#line, u is E.Type) // CHECK: [[@LINE]] false +print(#line, u is Int.Type) // CHECK: [[@LINE]] false // FIXME: Can't spell AnyObject.Protocol // CHECK-LABEL: AnyObject casts: -print("AnyObject casts:") -print(allToAll(C(), AnyObject.self)) // CHECK: true +print(#line, "AnyObject casts:") +print(#line, allToAll(C(), AnyObject.self)) // CHECK: [[@LINE]] true // On Darwin, the object will be the ObjC-runtime-class object; // out of Darwin, this should not succeed. -print(allToAll(type(of: C()), AnyObject.self)) +print(#line, allToAll(type(of: C()), AnyObject.self)) // CHECK-objc: true // CHECK-native: false // Bridging // NSNumber on Darwin, __SwiftValue on Linux. -print(allToAll(0, AnyObject.self)) // CHECK: true +print(#line, allToAll(0, AnyObject.self)) // CHECK: [[@LINE]] true // This will get bridged using __SwiftValue. struct NotBridged { var x: Int } -print(allToAll(NotBridged(x: 0), AnyObject.self)) // CHECK: true +print(#line, allToAll(NotBridged(x: 0), AnyObject.self)) // CHECK: [[@LINE]] true #if canImport(Foundation) // This requires Foundation (for NSCopying): -print(allToAll(NotBridged(x: 0), NSCopying.self)) // CHECK-objc: true +print(#line, allToAll(NotBridged(x: 0), NSCopying.self)) // CHECK-objc: [[@LINE]] true #endif // On Darwin, these casts fail (intentionally) even though __SwiftValue does // technically conform to these protocols through NSObject. // Off Darwin, it should not conform at all. -print(allToAll(NotBridged(x: 0), CustomStringConvertible.self)) // CHECK: false -print(allToAll(NotBridged(x: 0), (AnyObject & CustomStringConvertible).self)) // CHECK: false +print(#line, allToAll(NotBridged(x: 0), CustomStringConvertible.self)) // CHECK: [[@LINE]] false +print(#line, allToAll(NotBridged(x: 0), (AnyObject & CustomStringConvertible).self)) // CHECK: [[@LINE]] false #if canImport(Foundation) // This requires Foundation (for NSArray): @@ -362,5 +389,5 @@ func swiftOptimizesThisFunctionIncorrectly() -> Bool { } let result = swiftOptimizesThisFunctionIncorrectly() -print("Bridge cast result: \(result)") // CHECK-NEXT-objc: Bridge cast result: true +print(#line, "Bridge cast result: \(result)") // CHECK-NEXT-objc: Bridge cast result: true #endif diff --git a/test/Interpreter/generic_casts_objc.swift b/test/Interpreter/generic_casts_objc.swift index f7e9ccd80c01e..e9561d2e2e047 100644 --- a/test/Interpreter/generic_casts_objc.swift +++ b/test/Interpreter/generic_casts_objc.swift @@ -16,9 +16,12 @@ enum PE: P {} class PC: P, PObjC {} class PCSub: PC {} -func nongenericAnyIsPObjC(type: Any.Type) -> Bool { +func nongenericAnyIsPObjCType(type: Any.Type) -> Bool { return type is PObjC.Type } +func nongenericAnyIsPObjCProtocol(type: Any.Type) -> Bool { + return type is PObjC.Protocol +} func genericAnyIs(type: Any.Type, to: T.Type, expected: Bool) -> Bool { // If we're testing against a runtime that doesn't have the fix this tests, // just pretend we got it right. @@ -29,13 +32,23 @@ func genericAnyIs(type: Any.Type, to: T.Type, expected: Bool) -> Bool { } } -// CHECK-LABEL: casting types to ObjC protocols with generics: -print("casting types to ObjC protocols with generics:") -print(nongenericAnyIsPObjC(type: PS.self)) // CHECK: false -print(genericAnyIs(type: PS.self, to: PObjC.self, expected: false)) // CHECK: false -print(nongenericAnyIsPObjC(type: PE.self)) // CHECK: false -print(genericAnyIs(type: PE.self, to: PObjC.self, expected: false)) // CHECK: false -print(nongenericAnyIsPObjC(type: PC.self)) // CHECK: true -print(genericAnyIs(type: PC.self, to: PObjC.self, expected: true)) // CHECK-ONONE: true -print(nongenericAnyIsPObjC(type: PCSub.self)) // CHECK: true -print(genericAnyIs(type: PCSub.self, to: PObjC.self, expected: true)) // CHECK-ONONE: true +// CHECK-LABEL: casting types to ObjC protocol existential metatype: +print("casting types to ObjC protocol existential metatype:") +print(#line, nongenericAnyIsPObjCType(type: PS.self)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyIsPObjCType(type: PE.self)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyIsPObjCType(type: PC.self)) // CHECK: [[@LINE]] true +print(#line, nongenericAnyIsPObjCType(type: PCSub.self)) // CHECK: [[@LINE]] true + +// CHECK-LABEL: casting types to ObjC protocol metatype: +print("casting types to ObjC protocol metatype:") +print(#line, nongenericAnyIsPObjCProtocol(type: PS.self)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyIsPObjCProtocol(type: PE.self)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyIsPObjCProtocol(type: PC.self)) // CHECK: [[@LINE]] false +print(#line, nongenericAnyIsPObjCProtocol(type: PCSub.self)) // CHECK: [[@LINE]] false + +// CHECK-LABEL: casting types to ObjC protocol metatype via generic: +print("casting types to ObjC protocol metatype via generic:") +print(#line, genericAnyIs(type: PS.self, to: PObjC.self, expected: false)) // CHECK: [[@LINE]] false +print(#line, genericAnyIs(type: PE.self, to: PObjC.self, expected: false)) // CHECK: [[@LINE]] false +print(#line, genericAnyIs(type: PC.self, to: PObjC.self, expected: false)) // CHECK: [[@LINE]] false +print(#line, genericAnyIs(type: PCSub.self, to: PObjC.self, expected: false)) // CHECK: [[@LINE]] false diff --git a/test/Misc/misc_diagnostics.swift b/test/Misc/misc_diagnostics.swift index 557b1beec9021..6bf146ba0ff36 100644 --- a/test/Misc/misc_diagnostics.swift +++ b/test/Misc/misc_diagnostics.swift @@ -143,7 +143,7 @@ func test17875634() { func test20770032() { if case let 1...10 = (1, 1) { // expected-warning{{'let' pattern has no effect; sub-pattern didn't bind any variables}} {{11-15=}} // expected-error@-1 {{expression pattern of type 'ClosedRange' cannot match values of type '(Int, Int)'}} - // expected-error@-2 {{'(Int, Int)' cannot conform to 'Equatable'; only struct/enum/class types can conform to protocols}} + // expected-error@-2 {{type '(Int, Int)' cannot conform to 'Equatable'; only concrete types such as structs, enums and classes can conform to protocols}} // expected-note@-3 {{required by operator function '~=' where 'T' = '(Int, Int)'}} } } diff --git a/test/Parse/confusables.swift b/test/Parse/confusables.swift index e32d07c56517e..57afcde30dd29 100644 --- a/test/Parse/confusables.swift +++ b/test/Parse/confusables.swift @@ -17,7 +17,7 @@ if (true ꝸꝸꝸ false) {} // expected-note {{identifier 'ꝸꝸꝸ' contains // expected-error @+3 {{invalid character in source file}} // expected-error @+2 {{expected ',' separator}} -// expected-error @+1 {{type '(Int, Int)' cannot conform to 'BinaryInteger'; only struct/enum/class types can conform to protocols}} +// expected-error @+1 {{type '(Int, Int)' cannot conform to 'BinaryInteger'; only concrete types such as structs, enums and classes can conform to protocols}} if (5 ‒ 5) == 0 {} // expected-note {{unicode character '‒' looks similar to '-'; did you mean to use '-'?}} {{7-10=-}} // expected-note @-1 {{operator function '=='}} diff --git a/test/Prototypes/BigInt.swift b/test/Prototypes/BigInt.swift index 7b8db3d181447..c84158a0d4b57 100644 --- a/test/Prototypes/BigInt.swift +++ b/test/Prototypes/BigInt.swift @@ -11,7 +11,7 @@ //===----------------------------------------------------------------------===// // RUN: %empty-directory(%t) -// RUN: %target-build-swift -swift-version 4 -o %t/a.out %s +// RUN: not --crash %target-build-swift -swift-version 4 -o %t/a.out %s // RUN: %target-run %t/a.out // REQUIRES: executable_test // REQUIRES: CPU=x86_64 diff --git a/test/SILGen/keypaths.swift b/test/SILGen/keypaths.swift index 7c1e88cff14a4..42a7605d881b6 100644 --- a/test/SILGen/keypaths.swift +++ b/test/SILGen/keypaths.swift @@ -486,9 +486,7 @@ func test_variadics() { // CHECK: [[FN_REF:%[0-9]+]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF // CHECK: [[MAKE_ARR:%[0-9]+]] = apply [[FN_REF]]([[ARR_COUNT]]) // CHECK: ([[ARR:%[0-9]+]], %{{[0-9]+}}) = destructure_tuple [[MAKE_ARR]] : $(Array, Builtin.RawPointer) - // CHECK: [[FIN_REF:%[0-9]+]] = function_ref @$ss27_finalizeUninitializedArrayySayxGABnlF - // CHECK: [[FIN_ARR:%[0-9]+]] = apply [[FIN_REF]]([[ARR]]) - // CHECK: keypath $KeyPath, (root $SubscriptVariadic1; gettable_property $Int, id @$s8keypaths18SubscriptVariadic1VyS2id_tcig : $@convention(method) (@guaranteed Array, SubscriptVariadic1) -> Int, getter @$s8keypaths18SubscriptVariadic1VyS2id_tcipACTK : $@convention(thin) (@in_guaranteed SubscriptVariadic1, UnsafeRawPointer) -> @out Int, indices [%$0 : $Array : $Array], indices_equals @$sSaySiGTH : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @$sSaySiGTh : $@convention(thin) (UnsafeRawPointer) -> Int) ([[FIN_ARR]]) + // CHECK: keypath $KeyPath, (root $SubscriptVariadic1; gettable_property $Int, id @$s8keypaths18SubscriptVariadic1VyS2id_tcig : $@convention(method) (@guaranteed Array, SubscriptVariadic1) -> Int, getter @$s8keypaths18SubscriptVariadic1VyS2id_tcipACTK : $@convention(thin) (@in_guaranteed SubscriptVariadic1, UnsafeRawPointer) -> @out Int, indices [%$0 : $Array : $Array], indices_equals @$sSaySiGTH : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @$sSaySiGTh : $@convention(thin) (UnsafeRawPointer) -> Int) ([[ARR]]) _ = \SubscriptVariadic1.[] _ = \SubscriptVariadic2.["", "1"] diff --git a/test/SILGen/scalar_to_tuple_args.swift b/test/SILGen/scalar_to_tuple_args.swift index 67888cc061196..004d6cade6d5d 100644 --- a/test/SILGen/scalar_to_tuple_args.swift +++ b/test/SILGen/scalar_to_tuple_args.swift @@ -68,8 +68,6 @@ variadicFirst(x) // CHECK: [[X:%.*]] = load [trivial] [[READ]] // CHECK: [[ALLOC_ARRAY:%.*]] = apply {{.*}} -> (@owned Array<τ_0_0>, Builtin.RawPointer) // CHECK: ([[ARRAY:%.*]], [[MEMORY:%.*]]) = destructure_tuple [[ALLOC_ARRAY]] -// CHECK: [[FIN_FN:%.*]] = function_ref @$ss27_finalizeUninitializedArrayySayxGABnlF -// CHECK: [[FIN_ARR:%.*]] = apply [[FIN_FN]]([[ARRAY]]) // CHECK: [[VARIADIC_SECOND:%.*]] = function_ref @$s20scalar_to_tuple_args14variadicSecondyySi_SidtF -// CHECK: apply [[VARIADIC_SECOND]]([[X]], [[FIN_ARR]]) +// CHECK: apply [[VARIADIC_SECOND]]([[X]], [[ARRAY]]) variadicSecond(x) diff --git a/test/SILOptimizer/Inputs/struct_with_fields.swift b/test/SILOptimizer/Inputs/struct_with_fields.swift new file mode 100644 index 0000000000000..7652d39100139 --- /dev/null +++ b/test/SILOptimizer/Inputs/struct_with_fields.swift @@ -0,0 +1,5 @@ + +public struct TestStruct { + public var x: Int + public var y: Int +} diff --git a/test/SILOptimizer/keypath_offset.swift b/test/SILOptimizer/keypath_offset.swift new file mode 100644 index 0000000000000..bb0ffca7249f1 --- /dev/null +++ b/test/SILOptimizer/keypath_offset.swift @@ -0,0 +1,197 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift %S/Inputs/struct_with_fields.swift -parse-as-library -wmo -enable-library-evolution -module-name=Test -emit-module -emit-module-path=%t/Test.swiftmodule -c -o %t/test.o + +// RUN: %target-build-swift -O %s -module-name=test -Xfrontend -sil-verify-all -I%t -emit-sil | %FileCheck %s + +// RUN: %target-build-swift -Onone %s -I%t %t/test.o -o %t/Onone.out +// RUN: %target-build-swift -O %s -I%t %t/test.o -o %t/O.out +// RUN: %target-run %t/Onone.out > %t/Onone.txt +// RUN: %target-run %t/O.out > %t/O.txt +// RUN: diff %t/Onone.txt %t/O.txt + +// REQUIRES: executable_test,swift_stdlib_no_asserts,optimized_stdlib + +import Test + +final class C { + var x: Int + var z: T + let immutable: String + private(set) var secretlyMutable: String + + init(x: Int, z: T) { + self.x = x + self.z = z + self.immutable = "somestring" + self.secretlyMutable = immutable + } +} + +struct Point { + var x: Double + var y: Double +} + +struct S { + var x: Int + var y: Int? + var z: T + var p: Point + var op: Point? + var c: C +} + +struct NonOffsetableProperties { + // observers + var x: Int { didSet {} } + // reabstracted + var y: () -> () + // computed + var z: Int { return 0 } +} + +struct TupleProperties { + // unlabeled + var a: (Int, String) + // labeled + let b: (x: String, y: Int) + // reference writable + let c: (m: C, n: C) +} + +typealias Tuple = (S, C) + +func getIdentityKeyPathOfType(_: T.Type) -> KeyPath { + return \.self +} + + +@inline(never) +func printOffset(_ o: Int?) { + print(o as Any) +} + +// CHECK-LABEL: sil {{.*}} @$s4test0A13StructOffsetsyyF +// CHECK-NOT: _storedInlineOffset +// CHECK-NOT: class_method +// CHECK: } // end sil function '$s4test0A13StructOffsetsyyF' +@inline(never) +func testStructOffsets() { + let SLayout = MemoryLayout>.self + printOffset(SLayout.offset(of: \S.x)) + printOffset(SLayout.offset(of: \S.y)) + printOffset(SLayout.offset(of: \S.z)) + printOffset(SLayout.offset(of: \S.p)) + printOffset(SLayout.offset(of: \S.p.x)) + printOffset(SLayout.offset(of: \S.p.y)) + printOffset(SLayout.offset(of: \S.c)) +} + +// CHECK-LABEL: sil {{.*}} @$s4test0A20GenericStructOffsetsyyxmlF +// CHECK-NOT: _storedInlineOffset +// CHECK-NOT: class_method +// CHECK: } // end sil function '$s4test0A20GenericStructOffsetsyyxmlF' +@inline(never) +@_semantics("optimize.sil.specialize.generic.never") +func testGenericStructOffsets(_ t: T.Type) { + let SLayout = MemoryLayout>.self + printOffset(SLayout.offset(of: \S.x)) + printOffset(SLayout.offset(of: \S.y)) + printOffset(SLayout.offset(of: \S.z)) + printOffset(SLayout.offset(of: \S.p)) + printOffset(SLayout.offset(of: \S.p.x)) + printOffset(SLayout.offset(of: \S.p.y)) + printOffset(SLayout.offset(of: \S.c)) +} + +// CHECK-LABEL: sil {{.*}} @$s4test0A10NonOffsetsyyF +// CHECK-NOT: _storedInlineOffset +// CHECK-NOT: class_method +// CHECK: } // end sil function '$s4test0A10NonOffsetsyyF' +@inline(never) +func testNonOffsets() { + let NOPLayout = MemoryLayout.self + printOffset(NOPLayout.offset(of: \NonOffsetableProperties.x)) + printOffset(NOPLayout.offset(of: \NonOffsetableProperties.y)) + printOffset(NOPLayout.offset(of: \NonOffsetableProperties.z)) + printOffset(MemoryLayout>.offset(of: \C.x)) + let SLayout = MemoryLayout>.self + printOffset(SLayout.offset(of: \S.c.x)) + printOffset(SLayout.offset(of: \S.op!.x)) + printOffset(SLayout.offset(of: \S.op?.x)) +} + +// CHECK-LABEL: sil {{.*}} @$s4test0A11SelfOffsetsyyF +// CHECK-NOT: _storedInlineOffset +// CHECK-NOT: class_method +// CHECK: } // end sil function '$s4test0A11SelfOffsetsyyF' +@inline(never) +func testSelfOffsets() { + let SLayout = MemoryLayout>.self + printOffset(SLayout.offset(of: \.self)) + printOffset(SLayout.offset(of: getIdentityKeyPathOfType(S.self))) +} + +// CHECK-LABEL: sil {{.*}} @$s4test0A12TupleOffsetsyyF +// CHECK-NOT: _storedInlineOffset +// CHECK-NOT: class_method +// CHECK: } // end sil function '$s4test0A12TupleOffsetsyyF' +@inline(never) +func testTupleOffsets() { + let TPLayout = MemoryLayout.self + printOffset(TPLayout.offset(of: \TupleProperties.self)) + printOffset(TPLayout.offset(of: \TupleProperties.a)) + printOffset(TPLayout.offset(of: \TupleProperties.a.0)) + printOffset(TPLayout.offset(of: \TupleProperties.a.1)) + printOffset(TPLayout.offset(of: \TupleProperties.b)) + printOffset(TPLayout.offset(of: \TupleProperties.b.x)) + printOffset(TPLayout.offset(of: \TupleProperties.b.y)) + printOffset(TPLayout.offset(of: \TupleProperties.c)) + printOffset(TPLayout.offset(of: \TupleProperties.c.m)) + printOffset(TPLayout.offset(of: \TupleProperties.c.n)) + + let TLayout = MemoryLayout>.self + printOffset(TLayout.offset(of: \Tuple.self)) + printOffset(TLayout.offset(of: \Tuple.0)) + printOffset(TLayout.offset(of: \Tuple.0.x)) + printOffset(TLayout.offset(of: \Tuple.1)) +} + +// CHECK-LABEL: sil {{.*}} @$s4test0A19GenericTupleOffsetsyyxmlF +// CHECK-NOT: _storedInlineOffset +// CHECK-NOT: class_method +// CHECK: } // end sil function '$s4test0A19GenericTupleOffsetsyyxmlF' +@inline(never) +@_semantics("optimize.sil.specialize.generic.never") +func testGenericTupleOffsets(_ t: T.Type) { + let TLayout = MemoryLayout>.self + printOffset(TLayout.offset(of: \Tuple.self)) + printOffset(TLayout.offset(of: \Tuple.0)) + printOffset(TLayout.offset(of: \Tuple.0.x)) + printOffset(TLayout.offset(of: \Tuple.1)) +} + +// CHECK-LABEL: sil {{.*}} @$s4test0A16ResilientOffsetsyyF +// CHECK: class_method {{.*}}_storedInlineOffset +// CHECK: } // end sil function '$s4test0A16ResilientOffsetsyyF' +@inline(never) +func testResilientOffsets() { + let TLayout = MemoryLayout.self + printOffset(TLayout.offset(of: \TestStruct.x)) +} + +print("### testStructOffsets") +testStructOffsets() +print("### testGenericStructOffsets") +testGenericStructOffsets(Int.self) +print("### testNonOffsets") +testNonOffsets() +print("### testSelfOffsets") +testSelfOffsets() +print("### testTupleOffsets") +testTupleOffsets() +print("### testGenericTupleOffsets") +testGenericTupleOffsets(Int.self) +print("### testResilientOffsets") +testResilientOffsets() + diff --git a/test/decl/protocol/conforms/error_self_conformance.swift b/test/decl/protocol/conforms/error_self_conformance.swift index a5ceb7947a8c3..b451839b0e5ec 100644 --- a/test/decl/protocol/conforms/error_self_conformance.swift +++ b/test/decl/protocol/conforms/error_self_conformance.swift @@ -11,15 +11,15 @@ func testSimple(error: Error) { protocol ErrorRefinement : Error {} func testErrorRefinment(error: ErrorRefinement) { - wantsError(error) // expected-error {{value of protocol type 'ErrorRefinement' cannot conform to 'Error'; only struct/enum/class types can conform to protocols}} + wantsError(error) // expected-error {{protocol 'ErrorRefinement' as a type cannot conform to 'Error'; only concrete types such as structs, enums and classes can conform to protocols}} } protocol OtherProtocol {} func testErrorComposition(error: Error & OtherProtocol) { - wantsError(error) // expected-error {{value of protocol type 'Error & OtherProtocol' cannot conform to 'Error'; only struct/enum/class types can conform to protocols}} + wantsError(error) // expected-error {{protocol 'Error & OtherProtocol' as a type cannot conform to 'Error'; only concrete types such as structs, enums and classes can conform to protocols}} } class C {} func testErrorCompositionWithClass(error: Error & C) { - wantsError(error) // expected-error {{value of protocol type 'C & Error' cannot conform to 'Error'; only struct/enum/class types can conform to protocols}} + wantsError(error) // expected-error {{protocol 'C & Error' as a type cannot conform to 'Error'; only concrete types such as structs, enums and classes can conform to protocols}} } diff --git a/test/lit.cfg b/test/lit.cfg index a2f4fb6b27b28..9e0ece5f4fb31 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -699,7 +699,7 @@ if (run_os == 'maccatalyst'): target_os_abi = 'macosx' target_os_is_maccatalyst = "TRUE" config.available_features.add("OS=ios") -if (run_os in ['linux-gnu', 'linux-gnueabihf', 'freebsd', 'windows-cygnus', 'windows-gnu', 'windows-msvc', 'linux-android', 'linux-androideabi']): +if (run_os in ['linux-gnu', 'linux-gnueabihf', 'freebsd', 'openbsd', 'windows-cygnus', 'windows-gnu', 'windows-msvc', 'linux-android', 'linux-androideabi']): target_mandates_stable_abi = "TRUE" config.available_features.add('swift_only_stable_abi') config.substitutions.append(('%target-os-abi', target_os_abi)) @@ -1590,7 +1590,7 @@ source_compiler_rt_libs(compiler_rt_dir) def check_runtime_libs(features_to_check): for lib in config.compiler_rt_libs: - for (libname, feature) in features_to_check.iteritems(): + for (libname, feature) in features_to_check.items(): if lib.startswith("libclang_rt." + libname + "_"): config.available_features.add(feature) diff --git a/test/stdlib/Casts.swift b/test/stdlib/Casts.swift index 95bfd67ceb3e1..e29d94c043f88 100644 --- a/test/stdlib/Casts.swift +++ b/test/stdlib/Casts.swift @@ -21,6 +21,8 @@ import StdlibUnittest import Foundation #endif +private func blackhole(_ t: T) {} + let CastsTests = TestSuite("Casts") // Test for SR-426: missing release for some types after failed conversion @@ -161,4 +163,63 @@ CastsTests.test("Dynamic casts of CF types to protocol existentials") } #endif +CastsTests.test("Any.Protocol") { + class C {} + struct S {} + func isAnyProtocol(_ type: T.Type) -> Bool { + let result = T.self is Any.Protocol + if result { + // `as!` should succeed if `is` does + blackhole(T.self as! Any.Protocol) + } + return result + } + func isAnyType(_ type: T.Type) -> Bool { + return T.self is Any.Type + } + func isType(_ type: T.Type, to: U.Type) -> Bool { + return T.self is U.Type + } + + expectTrue(Int.self is Any.Type) + expectNotNil(Int.self as? Any.Type) + expectTrue(isAnyType(Int.self)) + expectFalse(Int.self is Any.Protocol) + expectNil(Int.self as? Any.Protocol) + expectFalse(isAnyProtocol(Int.self)) + expectFalse(isType(Int.self, to: Any.self)) + + expectTrue(C.self is Any.Type) + expectNotNil(C.self as? Any.Type) + expectTrue(isAnyType(C.self)) + expectFalse(C.self is Any.Protocol) + expectNil(C.self as? Any.Protocol) + expectFalse(isAnyProtocol(C.self)) + expectFalse(isType(C.self, to: Any.self)) + + expectTrue(S.self is Any.Type) + expectNotNil(S.self as? Any.Type) + expectTrue(isAnyType(S.self)) + expectFalse(S.self is Any.Protocol) + expectNil(S.self as? Any.Protocol) + expectFalse(isAnyProtocol(S.self)) + expectFalse(isType(S.self, to: Any.self)) + + expectTrue(Any.self is Any.Type) + expectNotNil(Any.self as? Any.Type) + expectTrue(isAnyType(Any.self)) + expectTrue(Any.self is Any.Protocol) + expectNotNil(Any.self as? Any.Protocol) + expectTrue(isAnyProtocol(Any.self)) + expectTrue(isType(Any.self, to: Any.self)) + + expectTrue(Any?.self is Any.Type) + expectNotNil(Any?.self as? Any.Type) + expectTrue(isAnyType(Any?.self)) + expectFalse(Any?.self is Any.Protocol) + expectNil(Any?.self as? Any.Protocol) + expectFalse(isAnyProtocol(Any?.self)) + expectFalse(isType(Any?.self, to: Any.self)) +} + runAllTests() diff --git a/test/stdlib/symbol-visibility-linux.test-sh b/test/stdlib/symbol-visibility-linux.test-sh index b4e5a7df71e50..62be057f4d919 100644 --- a/test/stdlib/symbol-visibility-linux.test-sh +++ b/test/stdlib/symbol-visibility-linux.test-sh @@ -30,6 +30,7 @@ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA80_cEEEvv \ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA88_cEEEvv \ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA104_cEEEvv \ +// RUN: -e _ZN9__gnu_cxx12__to_xstringISscEET_PFiPT0_mPKS2_P13__va_list_tagEmS5_z \ // RUN: > %t/swiftCore-all.txt // RUN: %llvm-nm --defined-only --extern-only --no-weak %platform-dylib-dir/%target-library-name(swiftCore) > %t/swiftCore-no-weak.txt // RUN: diff -u %t/swiftCore-all.txt %t/swiftCore-no-weak.txt @@ -51,6 +52,7 @@ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA80_cEEEvv \ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA88_cEEEvv \ // RUN: -e _ZSt16__once_call_implISt12_Bind_simpleIFPFvPvEPA104_cEEEvv \ +// RUN: -e _ZN9__gnu_cxx12__to_xstringISscEET_PFiPT0_mPKS2_P13__va_list_tagEmS5_z \ // RUN: > %t/swiftRemoteMirror-all.txt // RUN: %llvm-nm --defined-only --extern-only --no-weak %platform-dylib-dir/%target-library-name(swiftRemoteMirror) > %t/swiftRemoteMirror-no-weak.txt // RUN: diff -u %t/swiftRemoteMirror-all.txt %t/swiftRemoteMirror-no-weak.txt diff --git a/test/stmt/foreach.swift b/test/stmt/foreach.swift index 07441ed39f079..0b4ca6de47112 100644 --- a/test/stmt/foreach.swift +++ b/test/stmt/foreach.swift @@ -177,7 +177,7 @@ func testOptionalSequence() { // Crash with (invalid) for each over an existential func testExistentialSequence(s: Sequence) { // expected-error {{protocol 'Sequence' can only be used as a generic constraint because it has Self or associated type requirements}} - for x in s { // expected-error {{value of protocol type 'Sequence' cannot conform to 'Sequence'; only struct/enum/class types can conform to protocols}} + for x in s { // expected-error {{protocol 'Sequence' as a type cannot conform to the protocol itself; only concrete types such as structs, enums and classes can conform to protocols}} _ = x } } diff --git a/test/type/opaque.swift b/test/type/opaque.swift index 276933e611580..5f3f34c7225e8 100644 --- a/test/type/opaque.swift +++ b/test/type/opaque.swift @@ -13,7 +13,7 @@ class C {} class D: C, P, Q { func paul() {}; func priscilla() {}; func quinn() {} } let property: some P = 1 -let deflessLet: some P // expected-error{{has no initializer}} +let deflessLet: some P // expected-error{{has no initializer}} {{educational-notes=opaque-type-inference}} var deflessVar: some P // expected-error{{has no initializer}} struct GenericProperty { @@ -173,13 +173,13 @@ func recursion(x: Int) -> some P { return recursion(x: x - 1) } -func noReturnStmts() -> some P {} // expected-error {{function declares an opaque return type, but has no return statements in its body from which to infer an underlying type}} +func noReturnStmts() -> some P {} // expected-error {{function declares an opaque return type, but has no return statements in its body from which to infer an underlying type}} {{educational-notes=opaque-type-inference}} func returnUninhabited() -> some P { // expected-note {{opaque return type declared here}} fatalError() // expected-error{{return type of global function 'returnUninhabited()' requires that 'Never' conform to 'P'}} } -func mismatchedReturnTypes(_ x: Bool, _ y: Int, _ z: String) -> some P { // expected-error{{do not have matching underlying types}} +func mismatchedReturnTypes(_ x: Bool, _ y: Int, _ z: String) -> some P { // expected-error{{do not have matching underlying types}} {{educational-notes=opaque-type-inference}} if x { return y // expected-note{{underlying type 'Int'}} } else { @@ -209,7 +209,7 @@ func jan() -> some P { return [marcia(), marcia(), marcia()] } func marcia() -> some P { - return [marcia(), marcia(), marcia()] // expected-error{{defines the opaque type in terms of itself}} + return [marcia(), marcia(), marcia()] // expected-error{{defines the opaque type in terms of itself}} {{educational-notes=opaque-type-inference}} } protocol R { @@ -383,7 +383,7 @@ protocol P_51641323 { func rdar_51641323() { struct Foo: P_51641323 { var foo: some P_51641323 { // expected-note {{required by opaque return type of property 'foo'}} - {} // expected-error {{type '() -> ()' cannot conform to 'P_51641323'; only struct/enum/class types can conform to protocols}} + {} // expected-error {{type '() -> ()' cannot conform to 'P_51641323'; only concrete types such as structs, enums and classes can conform to protocols}} } } } diff --git a/test/type/subclass_composition.swift b/test/type/subclass_composition.swift index 1139c4bf3d34f..a7c52f539bf58 100644 --- a/test/type/subclass_composition.swift +++ b/test/type/subclass_composition.swift @@ -413,7 +413,7 @@ func conformsTo & P2>( // expected-error@-1 {{global function 'conformsToAnyObject' requires that 'P1' be a class type}} conformsToP1(p1) - // expected-error@-1 {{value of protocol type 'P1' cannot conform to 'P1'; only struct/enum/class types can conform to protocols}} + // expected-error@-1 {{protocol 'P1' as a type cannot conform to the protocol itself; only concrete types such as structs, enums and classes can conform to protocols}} // FIXME: Following diagnostics are not great because when // `conformsTo*` methods are re-typechecked, they loose information diff --git a/userdocs/diagnostics/opaque-type-inference.md b/userdocs/diagnostics/opaque-type-inference.md new file mode 100644 index 0000000000000..ebf63955530f5 --- /dev/null +++ b/userdocs/diagnostics/opaque-type-inference.md @@ -0,0 +1,68 @@ +# Underlying Type Inference for Opaque Result Types + +Opaque result types are a useful tool for abstracting the return type of a function or subscript, or type of a property. Although the concrete underlying type of an opaque type is hidden from clients, it is still inferred by the compiler, which enforces certain usage requirements: + +- Property declarations with opaque types must have an initializer expression or getter, and functions or subscripts returning opaque types must have at least one `return` statement: + +```swift +let x: some Equatable // error: property declares an opaque return type, but has no initializer expression from which to infer an underlying type +let y: some Equatable = 42 // OK +let z: some Equatable { // Also OK + return "hello, " + "world!" +} + +func foo() -> some Equatable { // error: function declares an opaque return type, but has no return statements in its body from which to infer an underlying type + fatalError("Unimplemented") +} + +func bar() -> some Equatable { // OK + fatalError("Unimplemented") + return 42 +} +``` + +- The underlying type of an opaque type must be unique. In other words, if a function or subscript returns an opaque type, it must return values of the same underlying type from every `return` statement in its body. + +```swift +func foo(bar: Bool) -> some Equatable { // error: function declares an opaque return type, but the return statements in its body do not have matching underlying types + if bar { + return "hello, world!" // note: return statement has underlying type 'String' + } else { + return 1 // note: return statement has underlying type 'Int' + } +} + +func bar(baz: Bool) -> some Equatable { // OK, both branches of the if statement return a value of the same underlying type, Int. + if baz { + return 100 + } else { + return 200 + } +} +``` + +- Functions returning opaque types may be recursive. However, such functions must have at least one `return` statement that returns a concrete underlying type as opposed to the function's own opaque result type. Additionally, recursive calls may not be used to create an infinitely recursive opaque type. + +```swift +func foo(_ x: Int) -> some Equatable { // error: function declares an opaque return type, but has no return statements in its body from which to infer an underlying type + // Not allowed because there aren't any non-recursive returns to infer the underlying type from. + return foo(x+1) +} + +struct EquatableWrapper: Equatable { var value: T } +func foo() -> some Equatable { // error: function opaque return type was inferred as 'EquatableWrapper', which defines the opaque type in terms of itself + // Not allowed because the use of EquatableWrapper creates an infinitely recursive underlying type: EquatableWrapper>>...> + return EquatableWrapper(value: foo()) +} + +func bar(_ x: Int) -> some Equatable { // OK, the underlying type can be inferred from the second return statement. + if x > 0 { + return bar(x-1) + } else { + return x + } +} +``` + +To learn more about opaque result types, see the [Opaque Types](https://docs.swift.org/swift-book/LanguageGuide/OpaqueTypes.html) section of _The Swift Programming Language_. + diff --git a/userdocs/diagnostics/protocol-type-non-conformance.md b/userdocs/diagnostics/protocol-type-non-conformance.md new file mode 100644 index 0000000000000..47cc95193a130 --- /dev/null +++ b/userdocs/diagnostics/protocol-type-non-conformance.md @@ -0,0 +1,46 @@ +# Protocol type not conforming to itself +Protocols in Swift may be used as types. Protocols as types are sometimes called existential types. + + +```swift +protocol P {} + +struct S: P {} + +var s: P = S() // This creates existential type because the protocol P is used as a type +``` + +However, a protocol type does not conform to protocols - not even the protocol itself. +Allowing existential types to conform to protocols is unsound. For protocols with static method, initializer, or associated type requirements, the implementation of these requirements cannot be accessed from the protocol type - accessing these kinds of requirements must be done using a concrete type. + +Let's walk through the example below: + +```swift +protocol Word: Hashable { + var word: String { get } +} + +struct Singular: Word { + var word: String +} + +struct Plural: Word { + var word: String +} + +let singularWord = Singular(word: "mango") +let pluralWord = Plural(word: "mangoes") + +let wordPairDict: [Word: Word] = [singularWord: pluralWord] // Error +``` + +One workaround to fix this problem is to use type erasure for the protocol `Word`. Think of type erasure as a way to hide an object's type. Since `Word` is of type `Hashable`, we already have `AnyHashable` type erasure available in the standard library which we can easily use here. + +```swift +// The fix +let wordPairDict: [AnyHashable: AnyHashable] = [singularWord: pluralWord] +``` + +# Exceptions +`@objc` protocol type with no static requirements however do conform to its own protocol. Another exception is the `Error` Swift protocol. + diff --git a/utils/PathSanitizingFileCheck b/utils/PathSanitizingFileCheck index 55cc4a5d286ac..3496895ec0d07 100755 --- a/utils/PathSanitizingFileCheck +++ b/utils/PathSanitizingFileCheck @@ -67,20 +67,21 @@ constants.""") if args.enable_windows_compatibility: if args.enable_yaml_compatibility: - slashes_re = b'(/|\\\\\\\\|\\\\\\\\\\\\\\\\)' + slashes_re = r'(/|\\\\|\\\\\\\\)' else: - slashes_re = b'(/|\\\\\\\\)' + slashes_re = r'(/|\\\\)' else: - slashes_re = b'/' + slashes_re = r'/' - stdin = io.open(sys.stdin.fileno(), 'rb').read() + stdin = io.open(sys.stdin.fileno(), 'r', encoding='utf-8', errors='ignore').read() for s in args.sanitize_strings: - replacement, pattern = s.encode(encoding="utf-8").split(b'=', 1) + replacement, pattern = s.split('=', 1) # Since we want to use pattern as a regex in some platforms, we need # to escape it first, and then replace the escaped slash # literal (r'\\/') for our platform-dependent slash regex. - stdin = re.sub(re.sub(b'\\\\/', slashes_re, re.escape(pattern)), + stdin = re.sub(re.sub('\\\\/' if sys.version_info[0] < 3 else r'[/\\]', + slashes_re, re.escape(pattern)), replacement, stdin) @@ -90,7 +91,7 @@ constants.""") else: p = subprocess.Popen( [args.file_check_path] + unknown_args, stdin=subprocess.PIPE) - stdout, stderr = p.communicate(stdin) + stdout, stderr = p.communicate(stdin.encode('utf-8')) if stdout is not None: print(stdout) if stderr is not None: diff --git a/utils/round-trip-syntax-test b/utils/round-trip-syntax-test index fc09165211488..18b374544c5a8 100755 --- a/utils/round-trip-syntax-test +++ b/utils/round-trip-syntax-test @@ -9,6 +9,7 @@ import os import subprocess import sys import tempfile +from functools import reduce logging.basicConfig(format='%(message)s', level=logging.INFO) @@ -17,7 +18,8 @@ class RoundTripTask(object): def __init__(self, input_filename, action, swift_syntax_test, skip_bad_syntax): assert action == '-round-trip-parse' or action == '-round-trip-lex' - assert type(input_filename) == unicode + if sys.version_info[0] < 3: + assert type(input_filename) == unicode assert type(swift_syntax_test) == str assert os.path.isfile(input_filename), \ @@ -51,9 +53,9 @@ class RoundTripTask(object): self.output_file.close() self.stderr_file.close() - with open(self.output_file.name, 'r') as stdout_in: + with open(self.output_file.name, 'rb') as stdout_in: self.stdout = stdout_in.read() - with open(self.stderr_file.name, 'r') as stderr_in: + with open(self.stderr_file.name, 'rb') as stderr_in: self.stderr = stderr_in.read() os.remove(self.output_file.name) @@ -75,7 +77,7 @@ class RoundTripTask(object): raise RuntimeError() contents = ''.join(map(lambda l: l.decode('utf-8', errors='replace'), - open(self.input_filename).readlines())) + open(self.input_filename, 'rb').readlines())) stdout_contents = self.stdout.decode('utf-8', errors='replace') if contents == stdout_contents: @@ -92,7 +94,7 @@ def swift_files_in_dir(d): swift_files = [] for root, dirs, files in os.walk(d): for basename in files: - if not basename.decode('utf-8').endswith('.swift'): + if not basename.endswith('.swift'): continue abs_file = os.path.abspath(os.path.join(root, basename)) swift_files.append(abs_file) @@ -149,7 +151,8 @@ This driver invokes swift-syntax-test using -round-trip-lex and all_input_files = [filename for dir_listing in dir_listings for filename in dir_listing] all_input_files += args.individual_input_files - all_input_files = [f.decode('utf-8') for f in all_input_files] + if sys.version_info[0] < 3: + all_input_files = [f.decode('utf-8') for f in all_input_files] if len(all_input_files) == 0: logging.error('No input files!') diff --git a/validation-test/Sema/type_checker_crashers_fixed/rdar27830834.swift b/validation-test/Sema/type_checker_crashers_fixed/rdar27830834.swift index 364998bae311b..f7be7a54079b2 100644 --- a/validation-test/Sema/type_checker_crashers_fixed/rdar27830834.swift +++ b/validation-test/Sema/type_checker_crashers_fixed/rdar27830834.swift @@ -2,5 +2,5 @@ var d = [String:String]() _ = "\(d.map{ [$0 : $0] })" -// expected-error@-1 {{type 'Dictionary.Element' (aka '(key: String, value: String)') cannot conform to 'Hashable'; only struct/enum/class types can conform to protocols}} +// expected-error@-1 {{type 'Dictionary.Element' (aka '(key: String, value: String)') cannot conform to 'Hashable'; only concrete types such as structs, enums and classes can conform to protocols}} // expected-note@-2 {{required by generic struct 'Dictionary' where 'Key' = 'Dictionary.Element' (aka '(key: String, value: String)')}} diff --git a/validation-test/compiler_crashers_2_fixed/0196-rdar48937223.swift b/validation-test/compiler_crashers_2_fixed/0196-rdar48937223.swift index c8e9979569714..2414c14a4442d 100644 --- a/validation-test/compiler_crashers_2_fixed/0196-rdar48937223.swift +++ b/validation-test/compiler_crashers_2_fixed/0196-rdar48937223.swift @@ -6,7 +6,7 @@ func fn(_ arg1: T, arg2: (T) -> U) {} // expected-note@-1 {{required by global function 'fn(_:arg2:)' where 'U' = '()'}} func test(str: String) { - fn(str) { arg in // expected-error {{type '()' cannot conform to 'P'; only struct/enum/class types can conform to protocols}} + fn(str) { arg in // expected-error {{type '()' cannot conform to 'P'; only concrete types such as structs, enums and classes can conform to protocols}} <#FOO#> // expected-error {{editor placeholder in source file}} } } diff --git a/validation-test/compiler_crashers_fixed/00017-llvm-foldingset-llvm-attributesetnode-nodeequals.swift b/validation-test/compiler_crashers_fixed/00017-llvm-foldingset-llvm-attributesetnode-nodeequals.swift index d58f6e86f203e..6f574b0e9dcac 100644 --- a/validation-test/compiler_crashers_fixed/00017-llvm-foldingset-llvm-attributesetnode-nodeequals.swift +++ b/validation-test/compiler_crashers_fixed/00017-llvm-foldingset-llvm-attributesetnode-nodeequals.swift @@ -20,4 +20,4 @@ extension Bool : BooleanProtocol { func f(_ b: T) {} // expected-note@-1 {{required by global function 'f' where 'T' = 'BooleanProtocol'}} -f(true as BooleanProtocol) // expected-error {{value of protocol type 'BooleanProtocol' cannot conform to 'BooleanProtocol'; only struct/enum/class types can conform to protocols}} +f(true as BooleanProtocol) // expected-error {{protocol 'BooleanProtocol' as a type cannot conform to the protocol itself; only concrete types such as structs, enums and classes can conform to protocols}}