diff --git a/docs/ABI/Mangling.rst b/docs/ABI/Mangling.rst index cfa67d6d80ab4..d8fb59b09a666 100644 --- a/docs/ABI/Mangling.rst +++ b/docs/ABI/Mangling.rst @@ -517,6 +517,10 @@ Types FUNCTION-KIND ::= 'C' // C function pointer type FUNCTION-KIND ::= 'A' // @auto_closure function type (escaping) FUNCTION-KIND ::= 'E' // function type (noescape) + FUNCTION-KIND ::= 'F' // @differentiable function type + FUNCTION-KIND ::= 'G' // @differentiable function type (escaping) + FUNCTION-KIND ::= 'H' // @differentiable(linear) function type + FUNCTION-KIND ::= 'I' // @differentiable(linear) function type (escaping) function-signature ::= params-type params-type throws? // results and parameters @@ -585,7 +589,7 @@ mangled in to disambiguate. impl-function-type ::= type* 'I' FUNC-ATTRIBUTES '_' impl-function-type ::= type* generic-signature 'I' FUNC-ATTRIBUTES '_' - FUNC-ATTRIBUTES ::= PATTERN-SUBS? INVOCATION-SUBS? PSEUDO-GENERIC? CALLEE-ESCAPE? CALLEE-CONVENTION FUNC-REPRESENTATION? COROUTINE-KIND? PARAM-CONVENTION* RESULT-CONVENTION* ('Y' PARAM-CONVENTION)* ('z' RESULT-CONVENTION)? + FUNC-ATTRIBUTES ::= PATTERN-SUBS? INVOCATION-SUBS? PSEUDO-GENERIC? CALLEE-ESCAPE? DIFFERENTIABILITY-KIND? CALLEE-CONVENTION FUNC-REPRESENTATION? COROUTINE-KIND? PARAM-CONVENTION* RESULT-CONVENTION* ('Y' PARAM-CONVENTION)* ('z' RESULT-CONVENTION)? PATTERN-SUBS ::= 's' // has pattern substitutions INVOCATION-SUB ::= 'I' // has invocation substitutions @@ -593,6 +597,10 @@ mangled in to disambiguate. CALLEE-ESCAPE ::= 'e' // @escaping (inverse of SIL @noescape) + DIFFERENTIABILITY-KIND ::= DIFFERENTIABLE | LINEAR + DIFFERENTIABLE ::= 'd' // @differentiable + LINEAR ::= 'l' // @differentiable(linear) + CALLEE-CONVENTION ::= 'y' // @callee_unowned CALLEE-CONVENTION ::= 'g' // @callee_guaranteed CALLEE-CONVENTION ::= 'x' // @callee_owned diff --git a/docs/DebuggingTheCompiler.rst b/docs/DebuggingTheCompiler.rst index 61e60bf53d8d0..ee7ef579c5dd3 100644 --- a/docs/DebuggingTheCompiler.rst +++ b/docs/DebuggingTheCompiler.rst @@ -359,6 +359,17 @@ we know to ignore swift_getGenericMetadata 84 times, i.e.:: (lldb) br set -i 84 -n GlobalARCOpts::run +A final trick is that one can use the -R option to stop at a relative assembly +address in lldb. Specifically, lldb resolves the breakpoint normally and then +just adds the argument -R to the address. So for instance, if I want to stop at +the address at +38 in the function with the name 'foo', I would write:: + + (lldb) br set -R 38 -n foo + +Then lldb would add 38 to the offset of foo and break there. This is really +useful in contexts where one wants to set a breakpoint at an assembly address +that is stable across multiple different invocations of lldb. + LLDB Scripts ~~~~~~~~~~~~ diff --git a/docs/Diagnostics.md b/docs/Diagnostics.md index 47d6ef6908993..b9ce5ad3b8712 100644 --- a/docs/Diagnostics.md +++ b/docs/Diagnostics.md @@ -92,23 +92,34 @@ Most diagnostics have no reason to change behavior under editor mode. An example ### Educational Notes ### -**Note**: This feature is currently experimental. It can be enabled by passing the `-Xfrontend -enable-descriptive-diagnostics` flag. +Educational notes are short-form documentation attached to a diagnostic which explain relevant language concepts. They are intended to further Swift's goal of progressive disclosure by providing a learning resource at the point of use when encountering an error message for the first time. In very limited circumstances, they also allow the main diagnostic message to use precise terminology (e.g. nominal types) which would otherwise be too unfriendly for beginners. -Educational notes are small snippets of documentation attached to a diagnostic which explain relevant language concepts. They are intended to further Swift's goal of progressive disclosure by providing a learning resource at the point of use for users encountering a new error message for the first time. In very limited circumstances, they also allow the main diagnostic message to use more precise and correct terminology (e.g. nominal types) which would otherwise be too unfriendly for beginners. +When outputting diagnostics on the command line, educational notes will be printed after the main diagnostic body if enabled using the `-print-educational-notes` driver option. When presented in an IDE, it's expected they will be collapsed under a disclosure arrow, info button, or similar to avoid cluttering output. -When outputting diagnostics on the command line, educational notes will be printed after the main diagnostic body if descriptive diagnostics are enabled. When presented in an IDE, it's expected they will be collapsed under a disclosure arrow, info button, or similar to avoid cluttering output. - -Generally speaking, a diagnostic should try to provide educational notes for any concepts/terminology which is difficult to understand from context or is especially subtle. Educational notes should: -- Explain a single language concept. This makes them easy to reuse across diagnostics and helps keep them clear, concise, and easy to understand. -- Be written in unabbreviated English. These are longer form messages compared to the main diagnostic, so there is no need to omit needless words and punctuation. -- Not generally exceed 3-4 paragraphs. Educational notes should be clear and easily digestible. Messages which are too long also have the potential to create diagnostics UX issues in some contexts. +Educational notes should: +- Explain a single language concept. This makes them easy to reuse across related diagnostics and helps keep them clear, concise, and easy to understand. +- Be written in unabbreviated English. These are longer-form messages compared to the main diagnostic, so there's no need to omit needless words and punctuation. +- Not generally exceed 3-4 paragraphs. Educational notes should be clear and easily digestible. Messages which are too long also have the potential to create UX issues on the command line. - Be accessible. Educational notes should be beginner friendly and avoid assuming unnecesary prior knowledge. The goal is not only to help users understand what a diagnostic is telling them, but also to turn errors and warnings into "teachable moments". -- Include references to relevant chapters of _The Swift Programming Language_ if applicable. -- Be written in Markdown, but avoid excessive markup to avoid impacting the terminal UX. +- Include references to relevant chapters of _The Swift Programming Language_. +- Be written in Markdown, but avoid excessive markup which negatively impacts the terminal UX. + +### Quick-Start Guide for Contributing New Educational Notes ### + +Adding new educational notes is a great way to get familiar with the process of contributing to Swift, while also making a big impact! To add a new educational note: -1. Add a new Markdown file in the `userdocs/diagnostics/` directory containing the contents of the note. -2. Associate the note with one or more diagnostics in EducationalNotes.def. +1. Follow the [directions in the README](https://github.com/apple/swift#getting-sources-for-swift-and-related-projects) to checkout the Swift sources locally. Being able to build the Swift compiler is recommended, but not required, when contributing a new note. +2. Identify a diagnostic to write an educational note for. To associate an educational note with a diagnostic name, you'll need to know its internal identifier. The easiest way to do this is to write a small program which triggers the diagnostic, and run it using the `-debug-diagnostic-names` compiler flag. This flag will cause the internal diagnostic identifier to be printed after the diagnostic message in square brackets. +3. Find any closely related diagnostics. Sometimes, what appears to be one diagnostic from a user's perspective may have multiple variations internally. After determining a diagnostic's internal identifier, run a search for it in the compiler source. You should find: + - An entry in a `Diagnostics*.def` file describing the diagnostic. If there are any closely related diagnostics the note should also be attached to, they can usually be found nearby. + - Each point in the compiler source where the diagnostic is emitted. This can be helpful in determining the exact circumstances which cause it to be emitted. +4. Add a new Markdown file in the `userdocs/diagnostics/` directory in the swift repository containing the contents of the note. When writing a note, keep the writing guidelines from the section above in mind. The existing notes in the directory are another useful guide. +5. Associate the note with the appropriate diagnostics in `EducationalNotes.def`. An entry like `EDUCATIONAL_NOTES(property_wrapper_failable_init, "property-wrapper-requirements.md")` will associate the note with filename `property-wrapper-requirements.md` with the diagnostic having an internal identifier of `property_wrapper_failable_init`. +6. If possible, rebuild the compiler and try recompiling your test program with `-print-educational-notes`. Your new note should appear after the diagnostic in the terminal. +7. That's it! The new note is now ready to be submitted as a pull request on GitHub. + +If you run into any issues or have questions while following the steps above, feel free to post a question on the Swift forums or open a work-in-progress pull request on GitHub. ### Format Specifiers ### diff --git a/include/swift/ABI/MetadataValues.h b/include/swift/ABI/MetadataValues.h index 606c1a007d150..ccff6128299a0 100644 --- a/include/swift/ABI/MetadataValues.h +++ b/include/swift/ABI/MetadataValues.h @@ -764,6 +764,14 @@ enum class FunctionMetadataConvention: uint8_t { CFunctionPointer = 3, }; +/// Differentiability kind for function type metadata. +/// Duplicates `DifferentiabilityKind` in AutoDiff.h. +enum class FunctionMetadataDifferentiabilityKind: uint8_t { + NonDifferentiable = 0b00, + Normal = 0b01, + Linear = 0b11 +}; + /// Flags in a function type metadata record. template class TargetFunctionTypeFlags { @@ -777,6 +785,8 @@ class TargetFunctionTypeFlags { ThrowsMask = 0x01000000U, ParamFlagsMask = 0x02000000U, EscapingMask = 0x04000000U, + DifferentiableMask = 0x08000000U, + LinearMask = 0x10000000U }; int_type Data; @@ -801,6 +811,16 @@ class TargetFunctionTypeFlags { (throws ? ThrowsMask : 0)); } + constexpr TargetFunctionTypeFlags withDifferentiabilityKind( + FunctionMetadataDifferentiabilityKind differentiability) const { + return TargetFunctionTypeFlags( + (Data & ~DifferentiableMask & ~LinearMask) | + (differentiability == FunctionMetadataDifferentiabilityKind::Normal + ? DifferentiableMask : 0) | + (differentiability == FunctionMetadataDifferentiabilityKind::Linear + ? LinearMask : 0)); + } + constexpr TargetFunctionTypeFlags withParameterFlags(bool hasFlags) const { return TargetFunctionTypeFlags((Data & ~ParamFlagsMask) | @@ -829,6 +849,19 @@ class TargetFunctionTypeFlags { bool hasParameterFlags() const { return bool(Data & ParamFlagsMask); } + bool isDifferentiable() const { + return getDifferentiabilityKind() >= + FunctionMetadataDifferentiabilityKind::Normal; + } + + FunctionMetadataDifferentiabilityKind getDifferentiabilityKind() const { + if (bool(Data & DifferentiableMask)) + return FunctionMetadataDifferentiabilityKind::Normal; + if (bool(Data & LinearMask)) + return FunctionMetadataDifferentiabilityKind::Linear; + return FunctionMetadataDifferentiabilityKind::NonDifferentiable; + } + int_type getIntValue() const { return Data; } @@ -849,9 +882,10 @@ using FunctionTypeFlags = TargetFunctionTypeFlags; template class TargetParameterTypeFlags { enum : int_type { - ValueOwnershipMask = 0x7F, - VariadicMask = 0x80, - AutoClosureMask = 0x100, + ValueOwnershipMask = 0x7F, + VariadicMask = 0x80, + AutoClosureMask = 0x100, + NoDerivativeMask = 0x200 }; int_type Data; @@ -881,6 +915,7 @@ class TargetParameterTypeFlags { bool isNone() const { return Data == 0; } bool isVariadic() const { return Data & VariadicMask; } bool isAutoClosure() const { return Data & AutoClosureMask; } + bool isNoDerivative() const { return Data & NoDerivativeMask; } ValueOwnership getValueOwnership() const { return (ValueOwnership)(Data & ValueOwnershipMask); diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index 81294f101e24f..ec0575ba3ecb3 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -741,6 +741,19 @@ class ASTContext final { unsigned previousGeneration, llvm::TinyPtrVector &methods); + /// Load derivative function configurations for the given + /// AbstractFunctionDecl. + /// + /// \param originalAFD The declaration whose derivative function + /// configurations should be loaded. + /// + /// \param previousGeneration The previous generation number. The AST already + /// contains derivative function configurations loaded from any generation up + /// to and including this one. + void loadDerivativeFunctionConfigurations( + AbstractFunctionDecl *originalAFD, unsigned previousGeneration, + llvm::SetVector &results); + /// Retrieve the Clang module loader for this ASTContext. /// /// If there is no Clang module loader, returns a null pointer. diff --git a/include/swift/AST/ASTTypeIDZone.def b/include/swift/AST/ASTTypeIDZone.def index ffa6f9e061c62..8c88e68936ccf 100644 --- a/include/swift/AST/ASTTypeIDZone.def +++ b/include/swift/AST/ASTTypeIDZone.def @@ -49,7 +49,9 @@ SWIFT_TYPEID_NAMED(Optional, PropertyWrapperMutability) SWIFT_TYPEID_NAMED(ParamDecl *, ParamDecl) SWIFT_TYPEID_NAMED(PatternBindingEntry *, PatternBindingEntry) +SWIFT_TYPEID_NAMED(PostfixOperatorDecl *, PostfixOperatorDecl) SWIFT_TYPEID_NAMED(PrecedenceGroupDecl *, PrecedenceGroupDecl) +SWIFT_TYPEID_NAMED(PrefixOperatorDecl *, PrefixOperatorDecl) SWIFT_TYPEID_NAMED(ProtocolDecl *, ProtocolDecl) SWIFT_TYPEID_NAMED(SourceFile *, SourceFile) SWIFT_TYPEID_NAMED(TypeAliasDecl *, TypeAliasDecl) diff --git a/include/swift/AST/ASTTypeIDs.h b/include/swift/AST/ASTTypeIDs.h index 1adde4e6bffaf..ad0db6fa19cbc 100644 --- a/include/swift/AST/ASTTypeIDs.h +++ b/include/swift/AST/ASTTypeIDs.h @@ -43,7 +43,9 @@ class OpaqueTypeDecl; class PatternBindingEntry; class ParamDecl; enum class ParamSpecifier : uint8_t; +class PostfixOperatorDecl; class PrecedenceGroupDecl; +class PrefixOperatorDecl; struct PropertyWrapperBackingPropertyInfo; struct PropertyWrapperTypeInfo; enum class CtorInitializerKind; diff --git a/include/swift/AST/AccessRequests.h b/include/swift/AST/AccessRequests.h index de08e3b0d8c65..b89ac7727799b 100644 --- a/include/swift/AST/AccessRequests.h +++ b/include/swift/AST/AccessRequests.h @@ -41,8 +41,7 @@ class AccessLevelRequest : friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, - ValueDecl *decl) const; + AccessLevel evaluate(Evaluator &evaluator, ValueDecl *decl) const; public: // Separate caching. @@ -65,8 +64,7 @@ class SetterAccessLevelRequest : friend SimpleRequest; // Evaluation. - llvm::Expected - evaluate(Evaluator &evaluator, AbstractStorageDecl *decl) const; + AccessLevel evaluate(Evaluator &evaluator, AbstractStorageDecl *decl) const; public: // Separate caching. @@ -88,8 +86,7 @@ class DefaultAndMaxAccessLevelRequest : friend SimpleRequest; // Evaluation. - llvm::Expected - evaluate(Evaluator &evaluator, ExtensionDecl *decl) const; + DefaultAndMax evaluate(Evaluator &evaluator, ExtensionDecl *decl) const; public: // Separate caching. diff --git a/include/swift/AST/Attr.def b/include/swift/AST/Attr.def index 6d8b366ce3e1d..0ccc1d770d8a8 100644 --- a/include/swift/AST/Attr.def +++ b/include/swift/AST/Attr.def @@ -552,6 +552,11 @@ DECL_ATTR(transpose, Transpose, ABIStableToAdd | ABIBreakingToRemove | APIStableToAdd | APIBreakingToRemove, 99) +SIMPLE_DECL_ATTR(noDerivative, NoDerivative, + OnAbstractFunction | OnVar | OnSubscript | + ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove, + 100) + #undef TYPE_ATTR #undef DECL_ATTR_ALIAS #undef CONTEXTUAL_DECL_ATTR_ALIAS diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index e3f3df4db22d7..c27525c366f63 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -2186,6 +2186,9 @@ class PatternBindingDecl final : public Decl, /// Can the pattern at index i be default initialized? bool isDefaultInitializable(unsigned i) const; + /// Can the property wrapper be used to provide default initialization? + bool isDefaultInitializableViaPropertyWrapper(unsigned i) const; + /// Does this pattern have a user-provided initializer expression? bool isExplicitlyInitialized(unsigned i) const; @@ -2433,6 +2436,7 @@ class ValueDecl : public Decl { friend class IsDynamicRequest; friend class IsImplicitlyUnwrappedOptionalRequest; friend class InterfaceTypeRequest; + friend class CheckRedeclarationRequest; friend class Decl; SourceLoc getLocFromSource() const { return NameLoc; } protected: @@ -2454,24 +2458,24 @@ class ValueDecl : public Decl { Bits.ValueDecl.AlreadyInLookupTable = value; } -public: - /// Return true if this protocol member is a protocol requirement. - /// - /// Asserts if this is not a member of a protocol. - bool isProtocolRequirement() const; - /// Determine whether we have already checked whether this /// declaration is a redeclaration. - bool alreadyCheckedRedeclaration() const { + bool alreadyCheckedRedeclaration() const { return Bits.ValueDecl.CheckedRedeclaration; } /// Set whether we have already checked this declaration as a /// redeclaration. - void setCheckedRedeclaration(bool checked) { - Bits.ValueDecl.CheckedRedeclaration = checked; + void setCheckedRedeclaration() { + Bits.ValueDecl.CheckedRedeclaration = true; } +public: + /// Return true if this protocol member is a protocol requirement. + /// + /// Asserts if this is not a member of a protocol. + bool isProtocolRequirement() const; + void setUserAccessible(bool Accessible) { Bits.ValueDecl.IsUserAccessible = Accessible; } @@ -5138,15 +5142,17 @@ class VarDecl : public AbstractStorageDecl { void setTopLevelGlobal(bool b) { Bits.VarDecl.IsTopLevelGlobal = b; } /// Retrieve the custom attributes that attach property wrappers to this - /// property. The returned list contains all of the attached property wrapper attributes in source order, - /// which means the outermost wrapper attribute is provided first. + /// property. The returned list contains all of the attached property wrapper + /// attributes in source order, which means the outermost wrapper attribute + /// is provided first. llvm::TinyPtrVector getAttachedPropertyWrappers() const; /// Whether this property has any attached property wrappers. bool hasAttachedPropertyWrapper() const; - /// Whether all of the attached property wrappers have an init(initialValue:) initializer. - bool allAttachedPropertyWrappersHaveInitialValueInit() const; + /// Whether all of the attached property wrappers have an init(wrappedValue:) + /// initializer. + bool allAttachedPropertyWrappersHaveWrappedValueInit() const; /// Retrieve the type of the attached property wrapper as a contextual /// type. @@ -5210,7 +5216,7 @@ class VarDecl : public AbstractStorageDecl { /// \end /// /// Or when there is no initializer but each composed property wrapper has - /// a suitable `init(initialValue:)`. + /// a suitable `init(wrappedValue:)`. bool isPropertyMemberwiseInitializedWithWrappedType() const; /// Whether the innermost property wrapper's initializer's 'wrappedValue' parameter @@ -5796,6 +5802,7 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { private: ParameterList *Params; +private: /// The generation at which we last loaded derivative function configurations. unsigned DerivativeFunctionConfigGeneration = 0; /// Prepare to traverse the list of derivative function configurations. @@ -5810,6 +5817,13 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { struct DerivativeFunctionConfigurationList; DerivativeFunctionConfigurationList *DerivativeFunctionConfigs = nullptr; +public: + /// Get all derivative function configurations. + ArrayRef getDerivativeFunctionConfigurations(); + + /// Add the given derivative function configuration. + void addDerivativeFunctionConfiguration(AutoDiffConfig config); + protected: // If a function has a body at all, we have either a parsed body AST node or // we have saved the end location of the unparsed body. @@ -6129,12 +6143,6 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { /// constructor. bool hasDynamicSelfResult() const; - /// Get all derivative function configurations. - ArrayRef getDerivativeFunctionConfigurations(); - - /// Add the given derivative function configuration. - void addDerivativeFunctionConfiguration(AutoDiffConfig config); - using DeclContext::operator new; using Decl::getASTContext; }; diff --git a/include/swift/AST/DiagnosticEngine.h b/include/swift/AST/DiagnosticEngine.h index 7ec80268f87ec..3abd15ea0f224 100644 --- a/include/swift/AST/DiagnosticEngine.h +++ b/include/swift/AST/DiagnosticEngine.h @@ -676,9 +676,6 @@ namespace swift { /// Print diagnostic names after their messages bool printDiagnosticNames = false; - /// Use educational notes when available. - bool useEducationalNotes = false; - /// Path to diagnostic documentation directory. std::string diagnosticDocumentationPath = ""; @@ -730,9 +727,6 @@ namespace swift { return printDiagnosticNames; } - void setUseEducationalNotes(bool val) { useEducationalNotes = val; } - bool getUseEducationalNotes() const { return useEducationalNotes; } - void setDiagnosticDocumentationPath(std::string path) { diagnosticDocumentationPath = path; } diff --git a/include/swift/AST/DiagnosticsFrontend.def b/include/swift/AST/DiagnosticsFrontend.def index 954dcc00beb12..387106b5c1a53 100644 --- a/include/swift/AST/DiagnosticsFrontend.def +++ b/include/swift/AST/DiagnosticsFrontend.def @@ -383,12 +383,12 @@ REMARK(interface_file_lock_timed_out,none, // Dependency Verifier Diagnostics ERROR(dependency_cascading_mismatch,none, - "expected %select{cascading|non-cascading}0 dependency; found " - "%select{cascading|non-cascading}1 dependency instead", + "expected %select{non-cascading|cascading}0 dependency; found " + "%select{non-cascading|cascading}1 dependency instead", (bool, bool)) ERROR(potential_dependency_cascading_mismatch,none, - "expected %select{cascading|non-cascading}0 potential member dependency; " - "found %select{cascading|non-cascading}1 potential member dependency " + "expected %select{non-cascading|cascading}0 potential member dependency; " + "found %select{non-cascading|cascading}1 potential member dependency " "instead", (bool, bool)) ERROR(missing_member_dependency,none, "expected " diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index d1797db598ccd..883559b50eab9 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -2712,6 +2712,19 @@ ERROR(broken_encodable_requirement,none, "Encodable protocol is broken: unexpected requirement", ()) ERROR(broken_decodable_requirement,none, "Decodable protocol is broken: unexpected requirement", ()) +ERROR(broken_differentiable_requirement,none, + "Differentiable protocol is broken: unexpected requirement", ()) +WARNING(differentiable_nondiff_type_implicit_noderivative_fixit,none, + "stored property %0 has no derivative because %1 does not conform to " + "'Differentiable'; add an explicit '@noDerivative' attribute" + "%select{|, or conform %2 to 'AdditiveArithmetic'}3", + (Identifier, Type, Identifier, bool)) +WARNING(differentiable_let_property_implicit_noderivative_fixit,none, + "synthesis of the 'Differentiable.move(along:)' requirement for %1 " + "requires all stored properties to be mutable; use 'var' instead, or add " + "an explicit '@noDerivative' attribute" + "%select{|, or conform %1 to 'AdditiveArithmetic'}2", + (Identifier, Identifier, bool)) NOTE(codable_extraneous_codingkey_case_here,none, "CodingKey case %0 does not match any stored properties", (Identifier)) @@ -3011,6 +3024,23 @@ ERROR(derivative_attr_original_already_has_derivative,none, NOTE(derivative_attr_duplicate_note,none, "other attribute declared here", ()) +// @transpose +ERROR(transpose_attr_invalid_linearity_parameter_or_result,none, + "cannot transpose with respect to original %select{result|parameter}1 " + "'%0' that does not conform to 'Differentiable' and satisfy " + "'%0 == %0.TangentVector'", (StringRef, /*isParameter*/ bool)) +ERROR(transpose_attr_overload_not_found,none, + "could not find function %0 with expected type %1", (DeclName, Type)) +ERROR(transpose_attr_cannot_use_named_wrt_params,none, + "cannot use named 'wrt' parameters in '@transpose(of:)' attribute, found " + "%0", (Identifier)) +ERROR(transpose_attr_wrt_self_must_be_static,none, + "the transpose of an instance method must be a 'static' method in the " + "same type when 'self' is a linearity parameter", ()) +NOTE(transpose_attr_wrt_self_self_type_mismatch_note,none, + "the transpose is declared in %0 but the original function is declared in " + "%1", (Type, Type)) + // Automatic differentiation attributes ERROR(autodiff_attr_original_decl_invalid_kind,none, "%0 is not a 'func', 'init', 'subscript', or 'var' computed property " diff --git a/include/swift/AST/Evaluator.h b/include/swift/AST/Evaluator.h index d91c27299ae67..6d51b9d7ec760 100644 --- a/include/swift/AST/Evaluator.h +++ b/include/swift/AST/Evaluator.h @@ -54,7 +54,7 @@ using AbstractRequestFunction = void(void); /// Form the specific request function for the given request type. template using RequestFunction = - llvm::Expected(const Request &, Evaluator &); + typename Request::OutputType(const Request &, Evaluator &); /// Pretty stack trace handler for an arbitrary request. template diff --git a/include/swift/AST/FileUnit.h b/include/swift/AST/FileUnit.h index 9395d6b2df401..61894edc1fdfb 100644 --- a/include/swift/AST/FileUnit.h +++ b/include/swift/AST/FileUnit.h @@ -196,6 +196,13 @@ class FileUnit : public DeclContext { SmallVectorImpl &Results, llvm::function_ref matchAttributes) const; + /// Finds all operator decls in this file. + /// + /// This does a simple local lookup, not recursively looking through imports. + /// The order of the results is not guaranteed to be meaningful. + virtual void + getOperatorDecls(SmallVectorImpl &results) const {} + /// Finds all precedence group decls in this file. /// /// This does a simple local lookup, not recursively looking through imports. diff --git a/include/swift/AST/IRGenRequests.h b/include/swift/AST/IRGenRequests.h index d1dd37b5e119b..dfc6bff76c882 100644 --- a/include/swift/AST/IRGenRequests.h +++ b/include/swift/AST/IRGenRequests.h @@ -124,7 +124,7 @@ class IRGenSourceFileRequest friend SimpleRequest; // Evaluation. - llvm::Expected> + std::unique_ptr evaluate(Evaluator &evaluator, IRGenDescriptor desc) const; public: @@ -142,7 +142,7 @@ class IRGenWholeModuleRequest friend SimpleRequest; // Evaluation. - llvm::Expected> + std::unique_ptr evaluate(Evaluator &evaluator, IRGenDescriptor desc) const; public: diff --git a/include/swift/AST/KnownIdentifiers.def b/include/swift/AST/KnownIdentifiers.def index b67e99f9f9919..58570dbc5d832 100644 --- a/include/swift/AST/KnownIdentifiers.def +++ b/include/swift/AST/KnownIdentifiers.def @@ -204,7 +204,10 @@ IDENTIFIER_(nsError) IDENTIFIER(OSLogMessage) // Differentiable programming +IDENTIFIER(along) IDENTIFIER(differential) +IDENTIFIER(direction) +IDENTIFIER(move) IDENTIFIER(pullback) IDENTIFIER(TangentVector) IDENTIFIER(zero) diff --git a/include/swift/AST/Module.h b/include/swift/AST/Module.h index 5ee0ab719a15e..bda4c8ebee6c7 100644 --- a/include/swift/AST/Module.h +++ b/include/swift/AST/Module.h @@ -165,6 +165,9 @@ class OverlayFile; /// /// \sa FileUnit class ModuleDecl : public DeclContext, public TypeDecl { + friend class DirectOperatorLookupRequest; + friend class DirectPrecedenceGroupLookupRequest; + public: typedef ArrayRef> AccessPathTy; typedef std::pair ImportedModule; @@ -620,6 +623,12 @@ class ModuleDecl : public DeclContext, public TypeDecl { /// The order of the results is not guaranteed to be meaningful. void getLocalTypeDecls(SmallVectorImpl &Results) const; + /// Finds all operator decls of this module. + /// + /// This does a simple local lookup, not recursively looking through imports. + /// The order of the results is not guaranteed to be meaningful. + void getOperatorDecls(SmallVectorImpl &results) const; + /// Finds all precedence group decls of this module. /// /// This does a simple local lookup, not recursively looking through imports. diff --git a/include/swift/AST/ModuleLoader.h b/include/swift/AST/ModuleLoader.h index 55b6008cf68ce..8e13dae85fdaf 100644 --- a/include/swift/AST/ModuleLoader.h +++ b/include/swift/AST/ModuleLoader.h @@ -36,6 +36,7 @@ class DependencyCollector; namespace swift { class AbstractFunctionDecl; +struct AutoDiffConfig; class ClangImporterOptions; class ClassDecl; class FileUnit; @@ -153,6 +154,23 @@ class ModuleLoader { unsigned previousGeneration, llvm::TinyPtrVector &methods) = 0; + /// Load derivative function configurations for the given + /// AbstractFunctionDecl. + /// + /// \param originalAFD The declaration whose derivative function + /// configurations should be loaded. + /// + /// \param previousGeneration The previous generation number. The AST already + /// contains derivative function configurations loaded from any generation up + /// to and including this one. + /// + /// \param results The result list of derivative function configurations. + /// This list will be extended with any methods found in subsequent + /// generations. + virtual void loadDerivativeFunctionConfigurations( + AbstractFunctionDecl *originalAFD, unsigned previousGeneration, + llvm::SetVector &results) {}; + /// Verify all modules loaded by this loader. virtual void verifyAllModules() { } diff --git a/include/swift/AST/NameLookupRequests.h b/include/swift/AST/NameLookupRequests.h index ff2f358b6d891..627d1a6c6d950 100644 --- a/include/swift/AST/NameLookupRequests.h +++ b/include/swift/AST/NameLookupRequests.h @@ -153,7 +153,7 @@ class SuperclassDeclRequest : friend SimpleRequest; // Evaluation. - llvm::Expected + ClassDecl * evaluate(Evaluator &evaluator, NominalTypeDecl *subject) const; public: @@ -197,7 +197,7 @@ class HasMissingDesignatedInitializersRequest : friend SimpleRequest; // Evaluation. - llvm::Expected + bool evaluate(Evaluator &evaluator, ClassDecl *subject) const; public: @@ -219,7 +219,7 @@ class ExtendedNominalRequest : friend SimpleRequest; // Evaluation. - llvm::Expected + NominalTypeDecl * evaluate(Evaluator &evaluator, ExtensionDecl *ext) const; public: @@ -283,7 +283,7 @@ class CustomAttrNominalRequest : friend SimpleRequest; // Evaluation. - llvm::Expected + NominalTypeDecl * evaluate(Evaluator &evaluator, CustomAttr *attr, DeclContext *dc) const; public: @@ -303,7 +303,7 @@ class GetDestructorRequest : friend SimpleRequest; // Evaluation. - llvm::Expected + DestructorDecl * evaluate(Evaluator &evaluator, ClassDecl *classDecl) const; public: @@ -324,7 +324,7 @@ class GenericParamListRequest : friend SimpleRequest; // Evaluation. - llvm::Expected + GenericParamList * evaluate(Evaluator &evaluator, GenericContext *value) const; public: @@ -347,7 +347,7 @@ class ExpandASTScopeRequest friend SimpleRequest; // Evaluation. - llvm::Expected + ast_scope::ASTScopeImpl * evaluate(Evaluator &evaluator, ast_scope::ASTScopeImpl *, ast_scope::ScopeCreator *) const; @@ -407,8 +407,8 @@ class UnqualifiedLookupRequest friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, - UnqualifiedLookupDescriptor desc) const; + LookupResult evaluate(Evaluator &evaluator, + UnqualifiedLookupDescriptor desc) const; }; using QualifiedLookupResult = SmallVector; @@ -427,7 +427,7 @@ class LookupInModuleRequest friend SimpleRequest; // Evaluation. - llvm::Expected + QualifiedLookupResult evaluate(Evaluator &evaluator, const DeclContext *moduleOrFile, DeclName name, NLKind lookupKind, namelookup::ResolutionKind resolutionKind, const DeclContext *moduleScopeContext) const; @@ -445,10 +445,10 @@ class AnyObjectLookupRequest private: friend SimpleRequest; - llvm::Expected evaluate(Evaluator &evaluator, - const DeclContext *dc, - DeclNameRef name, - NLOptions options) const; + QualifiedLookupResult evaluate(Evaluator &evaluator, + const DeclContext *dc, + DeclNameRef name, + NLOptions options) const; }; class ModuleQualifiedLookupRequest @@ -464,10 +464,10 @@ class ModuleQualifiedLookupRequest friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, - const DeclContext *DC, - ModuleDecl *mod, DeclNameRef name, - NLOptions opts) const; + QualifiedLookupResult evaluate(Evaluator &evaluator, + const DeclContext *DC, + ModuleDecl *mod, DeclNameRef name, + NLOptions opts) const; }; class QualifiedLookupRequest @@ -483,7 +483,7 @@ class QualifiedLookupRequest friend SimpleRequest; // Evaluation. - llvm::Expected + QualifiedLookupResult evaluate(Evaluator &evaluator, const DeclContext *DC, SmallVector decls, DeclNameRef name, @@ -534,7 +534,7 @@ class DirectLookupRequest friend SimpleRequest; // Evaluation. - llvm::Expected> + TinyPtrVector evaluate(Evaluator &evaluator, DirectLookupDescriptor desc) const; }; @@ -598,19 +598,23 @@ template class LookupOperatorRequest : public SimpleRequest, OperatorType *(OperatorLookupDescriptor), - CacheKind::Uncached> { + CacheKind::Cached> { using SimpleRequest, OperatorType *(OperatorLookupDescriptor), - CacheKind::Uncached>::SimpleRequest; + CacheKind::Cached>::SimpleRequest; private: friend SimpleRequest, OperatorType *(OperatorLookupDescriptor), - CacheKind::Uncached>; + CacheKind::Cached>; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, - OperatorLookupDescriptor desc) const; + OperatorType * + evaluate(Evaluator &evaluator, OperatorLookupDescriptor desc) const; + +public: + // Cached. + bool isCached() const { return true; } }; using LookupPrefixOperatorRequest = LookupOperatorRequest; @@ -631,7 +635,7 @@ class DirectOperatorLookupRequest private: friend SimpleRequest; - llvm::Expected> + TinyPtrVector evaluate(Evaluator &evaluator, OperatorLookupDescriptor descriptor, OperatorFixity fixity) const; }; @@ -649,7 +653,7 @@ class DirectPrecedenceGroupLookupRequest private: friend SimpleRequest; - llvm::Expected> + TinyPtrVector evaluate(Evaluator &evaluator, OperatorLookupDescriptor descriptor) const; }; @@ -694,7 +698,7 @@ class LookupConformanceInModuleRequest friend SimpleRequest; // Evaluation. - llvm::Expected evaluate( + ProtocolConformanceRef evaluate( Evaluator &evaluator, LookupConformanceDescriptor desc) const; }; diff --git a/include/swift/AST/NameLookupTypeIDZone.def b/include/swift/AST/NameLookupTypeIDZone.def index f1f680288d8b0..de346c54f8806 100644 --- a/include/swift/AST/NameLookupTypeIDZone.def +++ b/include/swift/AST/NameLookupTypeIDZone.def @@ -87,13 +87,13 @@ SWIFT_REQUEST(NameLookup, UnqualifiedLookupRequest, SWIFT_REQUEST(NameLookup, LookupPrefixOperatorRequest, PrefixOperatorDecl *(OperatorLookupDescriptor), - Uncached, NoLocationInfo) + Cached, NoLocationInfo) SWIFT_REQUEST(NameLookup, LookupInfixOperatorRequest, InfixOperatorDecl *(OperatorLookupDescriptor), - Uncached, NoLocationInfo) + Cached, NoLocationInfo) SWIFT_REQUEST(NameLookup, LookupPostfixOperatorRequest, PostfixOperatorDecl *(OperatorLookupDescriptor), - Uncached, NoLocationInfo) + Cached, NoLocationInfo) SWIFT_REQUEST(NameLookup, LookupPrecedenceGroupRequest, PrecedenceGroupDecl *(OperatorLookupDescriptor), - Uncached, NoLocationInfo) + Cached, NoLocationInfo) diff --git a/include/swift/AST/SILGenRequests.h b/include/swift/AST/SILGenRequests.h index 339c448c6479b..63b177b85c135 100644 --- a/include/swift/AST/SILGenRequests.h +++ b/include/swift/AST/SILGenRequests.h @@ -89,7 +89,7 @@ class SILGenSourceFileRequest : friend SimpleRequest; // Evaluation. - llvm::Expected> + std::unique_ptr evaluate(Evaluator &evaluator, SILGenDescriptor desc) const; public: @@ -107,7 +107,7 @@ class SILGenWholeModuleRequest : friend SimpleRequest; // Evaluation. - llvm::Expected> + std::unique_ptr evaluate(Evaluator &evaluator, SILGenDescriptor desc) const; public: diff --git a/include/swift/AST/SILOptimizerRequests.h b/include/swift/AST/SILOptimizerRequests.h index 8e4b581466812..19d282851d1b0 100644 --- a/include/swift/AST/SILOptimizerRequests.h +++ b/include/swift/AST/SILOptimizerRequests.h @@ -50,7 +50,7 @@ llvm::hash_code hash_value(const SILPipelineExecutionDescriptor &desc); /// Executes a SIL pipeline plan on a SIL module. class ExecuteSILPipelineRequest : public SimpleRequest { public: using SimpleRequest::SimpleRequest; @@ -59,8 +59,8 @@ class ExecuteSILPipelineRequest friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, - SILPipelineExecutionDescriptor desc) const; + evaluator::SideEffect + evaluate(Evaluator &evaluator, SILPipelineExecutionDescriptor desc) const; }; void simple_display(llvm::raw_ostream &out, diff --git a/include/swift/AST/SILOptimizerTypeIDZone.def b/include/swift/AST/SILOptimizerTypeIDZone.def index ce66045eb0ce5..55e5d4d3cfc85 100644 --- a/include/swift/AST/SILOptimizerTypeIDZone.def +++ b/include/swift/AST/SILOptimizerTypeIDZone.def @@ -15,4 +15,5 @@ //===----------------------------------------------------------------------===// SWIFT_REQUEST(SILOptimizer, ExecuteSILPipelineRequest, - bool(SILPipelineExecutionDescriptor), Uncached, NoLocationInfo) + evaluator::SideEffect(SILPipelineExecutionDescriptor), + Uncached, NoLocationInfo) diff --git a/include/swift/AST/SimpleRequest.h b/include/swift/AST/SimpleRequest.h index 018163f541630..6083fab88ea01 100644 --- a/include/swift/AST/SimpleRequest.h +++ b/include/swift/AST/SimpleRequest.h @@ -148,9 +148,9 @@ SourceLoc extractNearestSourceLoc(const std::tuple &value) { /// /// The \c Derived class needs to implement several operations. The most /// important one takes an evaluator and the input values, then computes the -/// final result, optionally bubbling up errors from recursive evaulations: +/// final result: /// \code -/// llvm::Expected evaluate(Evaluator &evaluator, Inputs...) const; +/// Output evaluate(Evaluator &evaluator, Inputs...) const; /// \endcode /// /// Cycle diagnostics can be handled in one of two ways. Either the \c Derived @@ -194,7 +194,7 @@ class SimpleRequest { } template - llvm::Expected + Output callDerived(Evaluator &evaluator, std::index_sequence) const { static_assert(sizeof...(Indices) > 0, "Subclass must define evaluate()"); return asDerived().evaluate(evaluator, std::get(storage)...); @@ -214,7 +214,7 @@ class SimpleRequest { : storage(inputs...) { } /// Request evaluation function that will be registered with the evaluator. - static llvm::Expected + static OutputType evaluateRequest(const Derived &request, Evaluator &evaluator) { return request.callDerived(evaluator, std::index_sequence_for()); diff --git a/include/swift/AST/SourceFile.h b/include/swift/AST/SourceFile.h index a4e089e5c57be..8fe0793cb8fd6 100644 --- a/include/swift/AST/SourceFile.h +++ b/include/swift/AST/SourceFile.h @@ -311,14 +311,6 @@ class SourceFile final : public FileUnit { /// List of Objective-C member conflicts we have found during type checking. std::vector ObjCMethodConflicts; - template - using OperatorMap = llvm::DenseMap>; - - OperatorMap InfixOperators; - OperatorMap PostfixOperators; - OperatorMap PrefixOperators; - OperatorMap PrecedenceGroups; - /// Describes what kind of file this is, which can affect some type checking /// and other behavior. const SourceFileKind Kind; @@ -448,6 +440,9 @@ class SourceFile final : public FileUnit { public: virtual void getTopLevelDecls(SmallVectorImpl &results) const override; + virtual void + getOperatorDecls(SmallVectorImpl &results) const override; + virtual void getPrecedenceGroups(SmallVectorImpl &results) const override; diff --git a/include/swift/AST/TBDGenRequests.h b/include/swift/AST/TBDGenRequests.h index f8db98d47508d..9f4aba50bf304 100644 --- a/include/swift/AST/TBDGenRequests.h +++ b/include/swift/AST/TBDGenRequests.h @@ -92,8 +92,7 @@ class GenerateTBDRequest friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, - TBDGenDescriptor desc) const; + TBDFileAndSymbols evaluate(Evaluator &evaluator, TBDGenDescriptor desc) const; }; /// Report that a request of the given kind is being evaluated, so it diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index 9938dd1c85f69..fc15a8008e7e3 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -74,7 +74,7 @@ class InheritedTypeRequest : friend SimpleRequest; // Evaluation. - llvm::Expected + Type evaluate(Evaluator &evaluator, llvm::PointerUnion decl, unsigned index, @@ -102,7 +102,7 @@ class SuperclassTypeRequest : friend SimpleRequest; // Evaluation. - llvm::Expected + Type evaluate(Evaluator &evaluator, NominalTypeDecl *classDecl, TypeResolutionStage stage) const; @@ -128,7 +128,7 @@ class EnumRawTypeRequest : friend SimpleRequest; // Evaluation. - llvm::Expected + Type evaluate(Evaluator &evaluator, EnumDecl *enumDecl, TypeResolutionStage stage) const; @@ -155,7 +155,7 @@ class OverriddenDeclsRequest : friend SimpleRequest; // Evaluation. - llvm::Expected> + llvm::TinyPtrVector evaluate(Evaluator &evaluator, ValueDecl *decl) const; public: @@ -177,7 +177,7 @@ class IsObjCRequest : friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, ValueDecl *decl) const; + bool evaluate(Evaluator &evaluator, ValueDecl *decl) const; public: // Separate caching. @@ -200,8 +200,8 @@ class InitKindRequest : friend SimpleRequest; // Evaluation. - llvm::Expected - evaluate(Evaluator &evaluator, ConstructorDecl *decl) const; + CtorInitializerKind + evaluate(Evaluator &evaluator, ConstructorDecl *decl) const; public: // Caching. @@ -220,7 +220,7 @@ class ProtocolRequiresClassRequest : friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, ProtocolDecl *decl) const; + bool evaluate(Evaluator &evaluator, ProtocolDecl *decl) const; public: // Cycle handling. @@ -246,7 +246,7 @@ class ExistentialConformsToSelfRequest : friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, ProtocolDecl *decl) const; + bool evaluate(Evaluator &evaluator, ProtocolDecl *decl) const; public: // Cycle handling. @@ -272,7 +272,7 @@ class ExistentialTypeSupportedRequest : friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, ProtocolDecl *decl) const; + bool evaluate(Evaluator &evaluator, ProtocolDecl *decl) const; public: // Cycle handling. @@ -297,7 +297,7 @@ class IsFinalRequest : friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, ValueDecl *decl) const; + bool evaluate(Evaluator &evaluator, ValueDecl *decl) const; public: // Separate caching. @@ -318,7 +318,7 @@ class IsDynamicRequest : friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, ValueDecl *decl) const; + bool evaluate(Evaluator &evaluator, ValueDecl *decl) const; public: // Separate caching. @@ -339,8 +339,8 @@ class RequirementSignatureRequest : friend SimpleRequest; // Evaluation. - llvm::Expected> evaluate(Evaluator &evaluator, - ProtocolDecl *proto) const; + ArrayRef + evaluate(Evaluator &evaluator, ProtocolDecl *proto) const; public: // Separate caching. @@ -361,7 +361,7 @@ class DefaultDefinitionTypeRequest : friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, AssociatedTypeDecl *decl) const; + Type evaluate(Evaluator &evaluator, AssociatedTypeDecl *decl) const; public: // Caching. @@ -440,10 +440,10 @@ class RequirementRequest : RequirementRepr &getRequirement() const; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, - WhereClauseOwner, - unsigned index, - TypeResolutionStage stage) const; + Requirement evaluate(Evaluator &evaluator, + WhereClauseOwner, + unsigned index, + TypeResolutionStage stage) const; public: // Source location @@ -471,7 +471,7 @@ class USRGenerationRequest : friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &eval, const ValueDecl *d) const; + std::string evaluate(Evaluator &eval, const ValueDecl *d) const; public: // Caching @@ -491,7 +491,7 @@ class MangleLocalTypeDeclRequest : friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &eval, const TypeDecl *d) const; + std::string evaluate(Evaluator &eval, const TypeDecl *d) const; public: // Caching @@ -512,8 +512,7 @@ class DefaultTypeRequest friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &eval, KnownProtocolKind, - const DeclContext *) const; + Type evaluate(Evaluator &eval, KnownProtocolKind, const DeclContext *) const; public: // Caching @@ -534,8 +533,8 @@ class PropertyWrapperTypeInfoRequest friend SimpleRequest; // Evaluation. - llvm::Expected - evaluate(Evaluator &eval, NominalTypeDecl *nominal) const; + PropertyWrapperTypeInfo + evaluate(Evaluator &eval, NominalTypeDecl *nominal) const; public: // Caching @@ -555,7 +554,7 @@ class AttachedPropertyWrappersRequest : friend SimpleRequest; // Evaluation. - llvm::Expected> + llvm::TinyPtrVector evaluate(Evaluator &evaluator, VarDecl *) const; public: @@ -576,7 +575,7 @@ class AttachedPropertyWrapperTypeRequest : friend SimpleRequest; // Evaluation. - llvm::Expected + Type evaluate(Evaluator &evaluator, VarDecl *var, unsigned i) const; public: @@ -597,7 +596,7 @@ class PropertyWrapperBackingPropertyTypeRequest : friend SimpleRequest; // Evaluation. - llvm::Expected + Type evaluate(Evaluator &evaluator, VarDecl *var) const; public: @@ -617,7 +616,7 @@ class PropertyWrapperMutabilityRequest : friend SimpleRequest; // Evaluation. - llvm::Expected> + Optional evaluate(Evaluator &evaluator, VarDecl *var) const; public: @@ -638,7 +637,7 @@ class PropertyWrapperBackingPropertyInfoRequest : friend SimpleRequest; // Evaluation. - llvm::Expected + PropertyWrapperBackingPropertyInfo evaluate(Evaluator &evaluator, VarDecl *var) const; public: @@ -658,7 +657,7 @@ class StructuralTypeRequest : friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &eval, TypeAliasDecl *d) const; + Type evaluate(Evaluator &eval, TypeAliasDecl *d) const; public: // Caching. @@ -677,8 +676,7 @@ class ResilienceExpansionRequest : friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &eval, - DeclContext *context) const; + ResilienceExpansion evaluate(Evaluator &eval, DeclContext *context) const; public: // Caching. @@ -701,7 +699,7 @@ class AttachedFunctionBuilderRequest : friend SimpleRequest; // Evaluation. - llvm::Expected + CustomAttr * evaluate(Evaluator &evaluator, ValueDecl *decl) const; public: @@ -721,7 +719,7 @@ class FunctionBuilderTypeRequest : private: friend SimpleRequest; - llvm::Expected + Type evaluate(Evaluator &evaluator, ValueDecl *decl) const; public: @@ -741,7 +739,7 @@ class SelfAccessKindRequest : friend SimpleRequest; // Evaluation. - llvm::Expected + SelfAccessKind evaluate(Evaluator &evaluator, FuncDecl *func) const; public: @@ -763,7 +761,7 @@ class IsGetterMutatingRequest : friend SimpleRequest; // Evaluation. - llvm::Expected + bool evaluate(Evaluator &evaluator, AbstractStorageDecl *func) const; public: @@ -785,7 +783,7 @@ class IsSetterMutatingRequest : friend SimpleRequest; // Evaluation. - llvm::Expected + bool evaluate(Evaluator &evaluator, AbstractStorageDecl *func) const; public: @@ -807,7 +805,7 @@ class OpaqueReadOwnershipRequest : friend SimpleRequest; // Evaluation. - llvm::Expected + OpaqueReadOwnership evaluate(Evaluator &evaluator, AbstractStorageDecl *storage) const; public: @@ -829,7 +827,7 @@ class LazyStoragePropertyRequest : friend SimpleRequest; // Evaluation. - llvm::Expected + VarDecl * evaluate(Evaluator &evaluator, VarDecl *lazyVar) const; public: @@ -852,7 +850,7 @@ class TypeCheckFunctionBodyUntilRequest : friend SimpleRequest; // Evaluation. - llvm::Expected + bool evaluate(Evaluator &evaluator, AbstractFunctionDecl *func, SourceLoc endTypeCheckLoc) const; @@ -875,7 +873,7 @@ class StoredPropertiesRequest : friend SimpleRequest; // Evaluation. - llvm::Expected> + ArrayRef evaluate(Evaluator &evaluator, NominalTypeDecl *decl) const; public: @@ -899,7 +897,7 @@ class StoredPropertiesAndMissingMembersRequest : friend SimpleRequest; // Evaluation. - llvm::Expected> + ArrayRef evaluate(Evaluator &evaluator, NominalTypeDecl *decl) const; public: @@ -917,7 +915,7 @@ class StorageImplInfoRequest : friend SimpleRequest; // Evaluation. - llvm::Expected + StorageImplInfo evaluate(Evaluator &evaluator, AbstractStorageDecl *decl) const; public: @@ -938,7 +936,7 @@ class RequiresOpaqueAccessorsRequest : friend SimpleRequest; // Evaluation. - llvm::Expected + bool evaluate(Evaluator &evaluator, VarDecl *decl) const; public: @@ -959,7 +957,7 @@ class RequiresOpaqueModifyCoroutineRequest : friend SimpleRequest; // Evaluation. - llvm::Expected + bool evaluate(Evaluator &evaluator, AbstractStorageDecl *decl) const; public: @@ -980,7 +978,7 @@ class IsAccessorTransparentRequest : friend SimpleRequest; // Evaluation. - llvm::Expected + bool evaluate(Evaluator &evaluator, AccessorDecl *decl) const; public: @@ -1002,7 +1000,7 @@ class SynthesizeAccessorRequest : friend SimpleRequest; // Evaluation. - llvm::Expected + AccessorDecl * evaluate(Evaluator &evaluator, AbstractStorageDecl *decl, AccessorKind kind) const; @@ -1024,7 +1022,7 @@ class EmittedMembersRequest : friend SimpleRequest; // Evaluation. - llvm::Expected + DeclRange evaluate(Evaluator &evaluator, ClassDecl *classDecl) const; public: @@ -1045,7 +1043,7 @@ class IsImplicitlyUnwrappedOptionalRequest : friend SimpleRequest; // Evaluation. - llvm::Expected + bool evaluate(Evaluator &evaluator, ValueDecl *value) const; public: @@ -1066,8 +1064,9 @@ class ClassAncestryFlagsRequest : friend SimpleRequest; // Evaluation. - llvm::Expected + AncestryFlags evaluate(Evaluator &evaluator, ClassDecl *value) const; + public: // Caching. bool isCached() const { return true; } @@ -1088,7 +1087,7 @@ class AbstractGenericSignatureRequest : friend SimpleRequest; // Evaluation. - llvm::Expected + GenericSignature evaluate(Evaluator &evaluator, GenericSignatureImpl *baseSignature, SmallVector addedParameters, @@ -1120,7 +1119,7 @@ class InferredGenericSignatureRequest : friend SimpleRequest; // Evaluation. - llvm::Expected + GenericSignature evaluate(Evaluator &evaluator, ModuleDecl *module, GenericSignatureImpl *baseSignature, @@ -1155,7 +1154,7 @@ class ExtendedTypeRequest friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &eval, ExtensionDecl *) const; + Type evaluate(Evaluator &eval, ExtensionDecl *) const; public: // Caching. bool isCached() const { return true; } @@ -1172,7 +1171,7 @@ class FunctionOperatorRequest : friend SimpleRequest; // Evaluation. - llvm::Expected + OperatorDecl * evaluate(Evaluator &evaluator, FuncDecl *value) const; public: @@ -1191,7 +1190,7 @@ class GenericSignatureRequest : friend SimpleRequest; // Evaluation. - llvm::Expected + GenericSignature evaluate(Evaluator &evaluator, GenericContext *value) const; public: @@ -1213,8 +1212,7 @@ class UnderlyingTypeRequest : friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, - TypeAliasDecl *decl) const; + Type evaluate(Evaluator &evaluator, TypeAliasDecl *decl) const; public: // Caching. @@ -1236,7 +1234,7 @@ class OperatorPrecedenceGroupRequest friend SimpleRequest; // Evaluation. - llvm::Expected + PrecedenceGroupDecl * evaluate(Evaluator &evaluator, InfixOperatorDecl *PGD) const; public: @@ -1247,7 +1245,7 @@ class OperatorPrecedenceGroupRequest /// Computes the raw values for an enum type. class EnumRawValuesRequest : public SimpleRequest { public: using SimpleRequest::SimpleRequest; @@ -1256,7 +1254,7 @@ class EnumRawValuesRequest : friend SimpleRequest; // Evaluation. - llvm::Expected + evaluator::SideEffect evaluate(Evaluator &evaluator, EnumDecl *ED, TypeResolutionStage stage) const; public: @@ -1266,8 +1264,8 @@ class EnumRawValuesRequest : // Separate caching. bool isCached() const; - Optional getCachedResult() const; - void cacheResult(bool value) const; + Optional getCachedResult() const; + void cacheResult(evaluator::SideEffect value) const; }; /// Determines if an override is ABI compatible with its base method. @@ -1281,7 +1279,7 @@ class IsABICompatibleOverrideRequest friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, ValueDecl *decl) const; + bool evaluate(Evaluator &evaluator, ValueDecl *decl) const; public: // Caching. @@ -1299,7 +1297,7 @@ class OpaqueResultTypeRequest private: friend SimpleRequest; - llvm::Expected + OpaqueTypeDecl * evaluate(Evaluator &evaluator, ValueDecl *VD) const; public: @@ -1319,7 +1317,7 @@ class IsStaticRequest : friend SimpleRequest; // Evaluation. - llvm::Expected + bool evaluate(Evaluator &evaluator, FuncDecl *value) const; public: @@ -1343,8 +1341,7 @@ class NeedsNewVTableEntryRequest friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, - AbstractFunctionDecl *decl) const; + bool evaluate(Evaluator &evaluator, AbstractFunctionDecl *decl) const; public: // Separate caching. @@ -1365,7 +1362,7 @@ class ParamSpecifierRequest friend SimpleRequest; // Evaluation. - llvm::Expected + ParamSpecifier evaluate(Evaluator &evaluator, ParamDecl *decl) const; public: @@ -1389,7 +1386,7 @@ class ResultTypeRequest TypeLoc &getResultTypeLoc() const; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, ValueDecl *decl) const; + Type evaluate(Evaluator &evaluator, ValueDecl *decl) const; public: // Separate caching. @@ -1410,7 +1407,7 @@ class PatternBindingEntryRequest friend SimpleRequest; // Evaluation. - llvm::Expected + const PatternBindingEntry * evaluate(Evaluator &evaluator, PatternBindingDecl *PBD, unsigned i) const; public: @@ -1430,8 +1427,7 @@ class NamingPatternRequest friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, - VarDecl *VD) const; + NamedPattern * evaluate(Evaluator &evaluator, VarDecl *VD) const; public: // Separate caching. @@ -1451,7 +1447,7 @@ class InterfaceTypeRequest : friend SimpleRequest; // Evaluation. - llvm::Expected + Type evaluate(Evaluator &evaluator, ValueDecl *decl) const; public: @@ -1506,7 +1502,7 @@ class ValidatePrecedenceGroupRequest friend SimpleRequest; // Evaluation. - llvm::Expected + PrecedenceGroupDecl * evaluate(Evaluator &evaluator, PrecedenceGroupDescriptor descriptor) const; public: @@ -1533,8 +1529,7 @@ class AreAllStoredPropertiesDefaultInitableRequest friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, - NominalTypeDecl *decl) const; + bool evaluate(Evaluator &evaluator, NominalTypeDecl *decl) const; public: // Caching. @@ -1554,8 +1549,7 @@ class HasUserDefinedDesignatedInitRequest friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, - NominalTypeDecl *decl) const; + bool evaluate(Evaluator &evaluator, NominalTypeDecl *decl) const; public: // Caching. @@ -1573,7 +1567,7 @@ class HasMemberwiseInitRequest friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, StructDecl *decl) const; + bool evaluate(Evaluator &evaluator, StructDecl *decl) const; public: // Caching. @@ -1592,8 +1586,7 @@ class SynthesizeMemberwiseInitRequest friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, - NominalTypeDecl *decl) const; + ConstructorDecl *evaluate(Evaluator &evaluator, NominalTypeDecl *decl) const; public: // Caching. @@ -1617,8 +1610,7 @@ class ResolveEffectiveMemberwiseInitRequest friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, - NominalTypeDecl *decl) const; + ConstructorDecl *evaluate(Evaluator &evaluator, NominalTypeDecl *decl) const; public: // Caching. @@ -1637,7 +1629,7 @@ class HasDefaultInitRequest friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, + bool evaluate(Evaluator &evaluator, NominalTypeDecl *decl) const; public: @@ -1657,8 +1649,8 @@ class SynthesizeDefaultInitRequest friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, - NominalTypeDecl *decl) const; + ConstructorDecl * evaluate(Evaluator &evaluator, + NominalTypeDecl *decl) const; public: // Caching. @@ -1676,9 +1668,9 @@ class CompareDeclSpecializationRequest friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, DeclContext *DC, - ValueDecl *VD1, ValueDecl *VD2, - bool dynamic) const; + bool evaluate(Evaluator &evaluator, DeclContext *DC, + ValueDecl *VD1, ValueDecl *VD2, + bool dynamic) const; public: // Caching. @@ -1697,7 +1689,7 @@ class InheritsSuperclassInitializersRequest friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, ClassDecl *decl) const; + bool evaluate(Evaluator &evaluator, ClassDecl *decl) const; public: // Separate caching. @@ -1718,7 +1710,8 @@ enum class ImplicitMemberAction : uint8_t { class ResolveImplicitMemberRequest : public SimpleRequest { public: using SimpleRequest::SimpleRequest; @@ -1727,8 +1720,9 @@ class ResolveImplicitMemberRequest friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, NominalTypeDecl *NTD, - ImplicitMemberAction action) const; + evaluator::SideEffect + evaluate(Evaluator &evaluator, NominalTypeDecl *NTD, + ImplicitMemberAction action) const; public: // Separate caching. @@ -1747,7 +1741,7 @@ class TypeWitnessRequest friend SimpleRequest; // Evaluation. - llvm::Expected + TypeWitnessAndDecl evaluate(Evaluator &evaluator, NormalProtocolConformance *conformance, AssociatedTypeDecl *ATD) const; @@ -1769,9 +1763,9 @@ class ValueWitnessRequest friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, - NormalProtocolConformance *conformance, - ValueDecl *VD) const; + Witness evaluate(Evaluator &evaluator, + NormalProtocolConformance *conformance, + ValueDecl *VD) const; public: // Separate caching. @@ -1802,7 +1796,7 @@ class PreCheckFunctionBuilderRequest friend SimpleRequest; // Evaluation. - llvm::Expected + FunctionBuilderBodyPreCheck evaluate(Evaluator &evaluator, AnyFunctionRef fn) const; public: @@ -1822,7 +1816,7 @@ class HasCircularInheritanceRequest friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, ClassDecl *decl) const; + bool evaluate(Evaluator &evaluator, ClassDecl *decl) const; public: // Cycle handling. @@ -1845,7 +1839,7 @@ class HasCircularInheritedProtocolsRequest friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, ProtocolDecl *decl) const; + bool evaluate(Evaluator &evaluator, ProtocolDecl *decl) const; public: // Cycle handling. @@ -1867,7 +1861,7 @@ class HasCircularRawValueRequest friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, EnumDecl *decl) const; + bool evaluate(Evaluator &evaluator, EnumDecl *decl) const; public: // Cycle handling. @@ -1890,7 +1884,7 @@ class DefaultArgumentInitContextRequest friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, + Initializer * evaluate(Evaluator &evaluator, ParamDecl *param) const; public: @@ -1912,7 +1906,7 @@ class DefaultArgumentExprRequest friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, ParamDecl *param) const; + Expr *evaluate(Evaluator &evaluator, ParamDecl *param) const; public: // Separate caching. @@ -1934,8 +1928,7 @@ class CallerSideDefaultArgExprRequest friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, - DefaultArgumentExpr *defaultExpr) const; + Expr * evaluate(Evaluator &evaluator, DefaultArgumentExpr *defaultExpr) const; public: // Separate caching. @@ -1956,8 +1949,7 @@ class IsCallableNominalTypeRequest friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, CanType ty, - DeclContext *dc) const; + bool evaluate(Evaluator &evaluator, CanType ty, DeclContext *dc) const; public: // Cached. @@ -1974,8 +1966,7 @@ class DynamicallyReplacedDeclRequest friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, - ValueDecl *VD) const; + ValueDecl * evaluate(Evaluator &evaluator, ValueDecl *VD) const; public: // Caching. @@ -1984,7 +1975,8 @@ class DynamicallyReplacedDeclRequest class TypeCheckSourceFileRequest : public SimpleRequest { + evaluator::SideEffect (SourceFile *), + CacheKind::SeparatelyCached> { public: using SimpleRequest::SimpleRequest; @@ -1992,13 +1984,14 @@ class TypeCheckSourceFileRequest : friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, SourceFile *SF) const; + evaluator::SideEffect + evaluate(Evaluator &evaluator, SourceFile *SF) const; public: // Separate caching. bool isCached() const { return true; } - Optional getCachedResult() const; - void cacheResult(bool result) const; + Optional getCachedResult() const; + void cacheResult(evaluator::SideEffect) const; }; /// Computes whether the specified type or a super-class/super-protocol has the @@ -2013,7 +2006,7 @@ class HasDynamicMemberLookupAttributeRequest friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, CanType ty) const; + bool evaluate(Evaluator &evaluator, CanType ty) const; public: bool isCached() const { @@ -2036,7 +2029,7 @@ class HasDynamicCallableAttributeRequest friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, CanType ty) const; + bool evaluate(Evaluator &evaluator, CanType ty) const; public: bool isCached() const { @@ -2062,8 +2055,7 @@ class PatternTypeRequest friend SimpleRequest; // Evaluation. - llvm::Expected evaluate( - Evaluator &evaluator, ContextualPattern pattern) const; + Type evaluate(Evaluator &evaluator, ContextualPattern pattern) const; public: bool isCached() const { return true; } @@ -2085,7 +2077,7 @@ class SPIGroupsRequest : friend SimpleRequest; // Evaluation. - llvm::Expected> + llvm::ArrayRef evaluate(Evaluator &evaluator, const Decl *decl) const; public: @@ -2112,8 +2104,8 @@ class DifferentiableAttributeTypeCheckRequest friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, - DifferentiableAttr *attr) const; + IndexSubset * evaluate(Evaluator &evaluator, + DifferentiableAttr *attr) const; public: // Separate caching. @@ -2134,8 +2126,8 @@ class TypeEraserHasViableInitRequest friend SimpleRequest; // Evaluation - llvm::Expected evaluate(Evaluator &evaluator, TypeEraserAttr *attr, - ProtocolDecl *protocol) const; + bool evaluate(Evaluator &evaluator, TypeEraserAttr *attr, + ProtocolDecl *protocol) const; public: bool isCached() const { return true; } @@ -2159,8 +2151,8 @@ class ScopedImportLookupRequest private: friend SimpleRequest; - llvm::Expected> evaluate(Evaluator &evaluator, - ImportDecl *import) const; + ArrayRef + evaluate(Evaluator &evaluator, ImportDecl *import) const; public: // Cached. @@ -2178,8 +2170,7 @@ class ClosureHasExplicitResultRequest private: friend SimpleRequest; - llvm::Expected evaluate(Evaluator &evaluator, - ClosureExpr *closure) const; + bool evaluate(Evaluator &evaluator, ClosureExpr *closure) const; public: bool isCached() const { return true; } @@ -2214,10 +2205,31 @@ class LookupAllConformancesInContextRequest : friend SimpleRequest; // Evaluation. - llvm::Expected + ProtocolConformanceLookupResult evaluate(Evaluator &evaluator, const DeclContext *DC) const; }; +class CheckRedeclarationRequest : + public SimpleRequest { +public: + using SimpleRequest::SimpleRequest; + + private: + friend SimpleRequest; + + // Evaluation. + evaluator::SideEffect + evaluate(Evaluator &evaluator, ValueDecl *VD) const; + + public: + // Separate caching. + bool isCached() const { return true; } + Optional getCachedResult() const; + void cacheResult(evaluator::SideEffect) const; +}; + // Allow AnyValue to compare two Type values, even though Type doesn't // support ==. template<> diff --git a/include/swift/AST/TypeCheckerTypeIDZone.def b/include/swift/AST/TypeCheckerTypeIDZone.def index 7dccd03e8ecfd..93ab1df57d71d 100644 --- a/include/swift/AST/TypeCheckerTypeIDZone.def +++ b/include/swift/AST/TypeCheckerTypeIDZone.def @@ -29,6 +29,9 @@ SWIFT_REQUEST(TypeChecker, AttachedPropertyWrappersRequest, NoLocationInfo) SWIFT_REQUEST(TypeChecker, CallerSideDefaultArgExprRequest, Expr *(DefaultArgumentExpr *), SeparatelyCached, NoLocationInfo) +SWIFT_REQUEST(TypeChecker, CheckRedeclarationRequest, + evaluator::SideEffect(ValueDecl *), + Uncached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, ClassAncestryFlagsRequest, AncestryFlags(ClassDecl *), Cached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, CompareDeclSpecializationRequest, @@ -55,8 +58,8 @@ SWIFT_REQUEST(TypeChecker, DynamicallyReplacedDeclRequest, SWIFT_REQUEST(TypeChecker, EmittedMembersRequest, DeclRange(ClassDecl *), SeparatelyCached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, EnumRawValuesRequest, - bool (EnumDecl *, TypeResolutionStage), SeparatelyCached, - NoLocationInfo) + evaluator::SideEffect (EnumDecl *, TypeResolutionStage), + SeparatelyCached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, EnumRawTypeRequest, Type(EnumDecl *, TypeResolutionStage), SeparatelyCached, NoLocationInfo) @@ -182,7 +185,8 @@ SWIFT_REQUEST(TypeChecker, SynthesizeAccessorRequest, AccessorDecl *(AbstractStorageDecl *, AccessorKind), SeparatelyCached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, TypeCheckFunctionBodyUntilRequest, - bool(AbstractFunctionDecl *, SourceLoc), Cached, NoLocationInfo) + bool(AbstractFunctionDecl *, SourceLoc), + Cached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, UnderlyingTypeRequest, Type(TypeAliasDecl *), SeparatelyCached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, USRGenerationRequest, std::string(const ValueDecl *), @@ -207,8 +211,8 @@ SWIFT_REQUEST(TypeChecker, PreCheckFunctionBuilderRequest, FunctionBuilderClosurePreCheck(AnyFunctionRef), Cached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, ResolveImplicitMemberRequest, - bool(NominalTypeDecl *, ImplicitMemberAction), Uncached, - NoLocationInfo) + evaluator::SideEffect(NominalTypeDecl *, ImplicitMemberAction), + Uncached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, SPIGroupsRequest, llvm::ArrayRef(Decl *), Cached, NoLocationInfo) diff --git a/include/swift/Basic/CTypeIDZone.def b/include/swift/Basic/CTypeIDZone.def index 6be90fd879b2e..007fa187389d4 100644 --- a/include/swift/Basic/CTypeIDZone.def +++ b/include/swift/Basic/CTypeIDZone.def @@ -35,6 +35,7 @@ SWIFT_TYPEID_NAMED(void, Void) SWIFT_TYPEID_NAMED(std::string, String) // C++ standard library types. +SWIFT_TYPEID_NAMED(evaluator::SideEffect, SideEffect) SWIFT_TYPEID_TEMPLATE1_NAMED(std::vector, Vector, typename T, T) SWIFT_TYPEID_TEMPLATE1_NAMED(std::unique_ptr, UniquePtr, typename T, T) diff --git a/include/swift/Basic/DiagnosticOptions.h b/include/swift/Basic/DiagnosticOptions.h index d1552f06f8053..58531d5908641 100644 --- a/include/swift/Basic/DiagnosticOptions.h +++ b/include/swift/Basic/DiagnosticOptions.h @@ -55,9 +55,9 @@ class DiagnosticOptions { // When printing diagnostics, include the diagnostic name at the end bool PrintDiagnosticNames = false; - /// If set to true, display educational note content to the user if available. + /// If set to true, include educational notes in printed output if available. /// Educational notes are documentation which supplement diagnostics. - bool EnableEducationalNotes = false; + bool PrintEducationalNotes = false; // If set to true, use the more descriptive experimental formatting style for // diagnostics. diff --git a/include/swift/Basic/Statistics.def b/include/swift/Basic/Statistics.def index 72f3baec59da0..6cc99e356934c 100644 --- a/include/swift/Basic/Statistics.def +++ b/include/swift/Basic/Statistics.def @@ -130,10 +130,8 @@ FRONTEND_STATISTIC(AST, NumLocalTypeDecls) /// Number of Objective-C declarations in the AST context. FRONTEND_STATISTIC(AST, NumObjCMethods) -/// Number of infix, postfix, and prefix operators in the AST context. -FRONTEND_STATISTIC(AST, NumInfixOperators) -FRONTEND_STATISTIC(AST, NumPostfixOperators) -FRONTEND_STATISTIC(AST, NumPrefixOperators) +/// Number of operators in the AST context. +FRONTEND_STATISTIC(AST, NumOperators) /// Number of precedence groups in the AST context. FRONTEND_STATISTIC(AST, NumPrecedenceGroups) diff --git a/include/swift/Basic/TypeID.h b/include/swift/Basic/TypeID.h index 743d0e4ab9440..49e66bb5457cb 100644 --- a/include/swift/Basic/TypeID.h +++ b/include/swift/Basic/TypeID.h @@ -66,6 +66,29 @@ constexpr uint64_t formTypeID(uint8_t zone, uint8_t type) { return (uint64_t(zone) << 8) | uint64_t(type); } +namespace evaluator { +/// The return type of requests that execute side effects. +/// +/// In general, it is not appropriate to use the request evaluator framework to +/// execute a request for the sake of its side effects. However, there are +/// operations we would currently like to be requests because it makes modelling +/// some aspect of their implementation particularly nice. For example, an +/// operation that emits diagnostics to run some checking code in a primary +/// file may be desirable to requestify because it should be run only once per +/// declaration, but it has no coherent return value. Another category of +/// side-effecting requests are those that adapt existing parts of the compiler that +/// do not yet behave in a "functional" manner to have a functional interface. Consider +/// the request to run the SIL Optimizer. In theory, it should be a request that takes in +/// a SILModule and returns a SILModule. In practice, it is a request that executes +/// effects against a SILModule. +/// +/// To make these requests stand out - partially in the hope we can return and +/// refactor them to behave in a more well-structured manner, partially because +/// they cannot return \c void or we will get template substitution failures - we +/// annotate them as computing an \c evaluator::SideEffect. +using SideEffect = std::tuple<>; +} + // Define the C type zone (zone 0). #define SWIFT_TYPEID_ZONE C #define SWIFT_TYPEID_HEADER "swift/Basic/CTypeIDZone.def" diff --git a/include/swift/Demangling/DemangleNodes.def b/include/swift/Demangling/DemangleNodes.def index 4f11bec456290..121268fecfd61 100644 --- a/include/swift/Demangling/DemangleNodes.def +++ b/include/swift/Demangling/DemangleNodes.def @@ -68,6 +68,10 @@ NODE(DependentProtocolConformanceInherited) NODE(DependentProtocolConformanceAssociated) CONTEXT_NODE(Destructor) CONTEXT_NODE(DidSet) +NODE(DifferentiableFunctionType) +NODE(EscapingDifferentiableFunctionType) +NODE(LinearFunctionType) +NODE(EscapingLinearFunctionType) NODE(Directness) NODE(DynamicAttribute) NODE(DirectMethodReferenceAttribute) @@ -109,6 +113,8 @@ NODE(Identifier) NODE(Index) CONTEXT_NODE(IVarInitializer) CONTEXT_NODE(IVarDestroyer) +NODE(ImplDifferentiable) +NODE(ImplLinear) NODE(ImplEscaping) NODE(ImplConvention) NODE(ImplFunctionAttribute) diff --git a/include/swift/Demangling/TypeDecoder.h b/include/swift/Demangling/TypeDecoder.h index 79450a6c9c591..af4143e00f9d0 100644 --- a/include/swift/Demangling/TypeDecoder.h +++ b/include/swift/Demangling/TypeDecoder.h @@ -494,6 +494,10 @@ class TypeDecoder { case NodeKind::NoEscapeFunctionType: case NodeKind::AutoClosureType: case NodeKind::EscapingAutoClosureType: + case NodeKind::DifferentiableFunctionType: + case NodeKind::EscapingDifferentiableFunctionType: + case NodeKind::LinearFunctionType: + case NodeKind::EscapingLinearFunctionType: case NodeKind::FunctionType: { if (Node->getNumChildren() < 2) return BuiltType(); @@ -507,6 +511,15 @@ class TypeDecoder { flags.withConvention(FunctionMetadataConvention::CFunctionPointer); } else if (Node->getKind() == NodeKind::ThinFunctionType) { flags = flags.withConvention(FunctionMetadataConvention::Thin); + } else if (Node->getKind() == NodeKind::DifferentiableFunctionType || + Node->getKind() == + NodeKind::EscapingDifferentiableFunctionType) { + flags = flags.withDifferentiabilityKind( + FunctionMetadataDifferentiabilityKind::Normal); + } else if (Node->getKind() == NodeKind::LinearFunctionType || + Node->getKind() == NodeKind::EscapingLinearFunctionType) { + flags = flags.withDifferentiabilityKind( + FunctionMetadataDifferentiabilityKind::Linear); } bool isThrow = @@ -527,7 +540,11 @@ class TypeDecoder { .withEscaping( Node->getKind() == NodeKind::FunctionType || Node->getKind() == NodeKind::EscapingAutoClosureType || - Node->getKind() == NodeKind::EscapingObjCBlock); + Node->getKind() == NodeKind::EscapingObjCBlock || + Node->getKind() == + NodeKind::EscapingDifferentiableFunctionType || + Node->getKind() == + NodeKind::EscapingLinearFunctionType); auto result = decodeMangledType(Node->getChild(isThrow ? 2 : 1)); if (!result) return BuiltType(); diff --git a/include/swift/Frontend/PrintingDiagnosticConsumer.h b/include/swift/Frontend/PrintingDiagnosticConsumer.h index 6be92e53691d1..3dc5f1addcd4b 100644 --- a/include/swift/Frontend/PrintingDiagnosticConsumer.h +++ b/include/swift/Frontend/PrintingDiagnosticConsumer.h @@ -31,6 +31,7 @@ class AnnotatedSourceSnippet; class PrintingDiagnosticConsumer : public DiagnosticConsumer { llvm::raw_ostream &Stream; bool ForceColors = false; + bool PrintEducationalNotes = false; bool DidErrorOccur = false; bool ExperimentalFormattingEnabled = false; // The current snippet used to display an error/warning/remark and the notes @@ -59,6 +60,10 @@ class PrintingDiagnosticConsumer : public DiagnosticConsumer { llvm::sys::Process::UseANSIEscapeCodes(true); } + void setPrintEducationalNotes(bool ShouldPrint) { + PrintEducationalNotes = ShouldPrint; + } + void enableExperimentalFormatting() { ExperimentalFormattingEnabled = true; } bool didErrorOccur() { diff --git a/include/swift/IDE/IDERequests.h b/include/swift/IDE/IDERequests.h index 11351e59c853c..f5538984b8862 100644 --- a/include/swift/IDE/IDERequests.h +++ b/include/swift/IDE/IDERequests.h @@ -69,8 +69,8 @@ class CursorInfoRequest: friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, - CursorInfoOwner CI) const; + ide::ResolvedCursorInfo evaluate(Evaluator &evaluator, + CursorInfoOwner CI) const; public: // Caching @@ -130,8 +130,8 @@ class RangeInfoRequest: friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, - RangeInfoOwner CI) const; + ide::ResolvedRangeInfo evaluate(Evaluator &evaluator, + RangeInfoOwner CI) const; public: // Caching @@ -158,8 +158,8 @@ class ProvideDefaultImplForRequest: friend SimpleRequest; // Evaluation. - llvm::Expected> evaluate(Evaluator &evaluator, - ValueDecl* VD) const; + ArrayRef evaluate(Evaluator &evaluator, + ValueDecl* VD) const; public: // Caching @@ -219,8 +219,8 @@ class CollectOverriddenDeclsRequest: friend SimpleRequest; // Evaluation. - llvm::Expected> evaluate(Evaluator &evaluator, - OverridenDeclsOwner Owner) const; + ArrayRef evaluate(Evaluator &evaluator, + OverridenDeclsOwner Owner) const; public: // Caching @@ -271,8 +271,8 @@ class ResolveProtocolNameRequest: friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, - ProtocolNameOwner Input) const; + ProtocolDecl *evaluate(Evaluator &evaluator, + ProtocolNameOwner Input) const; public: // Caching diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 92b9b400cb66a..c0219fbbadeba 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -130,9 +130,6 @@ def enable_cross_import_overlays : Flag<["-"], "enable-cross-import-overlays">, HelpText<"Automatically import declared cross-import overlays.">; def disable_cross_import_overlays : Flag<["-"], "disable-cross-import-overlays">, HelpText<"Do not automatically import declared cross-import overlays.">; - -def enable_educational_notes : Flag<["-"], "enable-educational-notes">, - HelpText<"Show educational notes, if available.">; def enable_experimental_diagnostic_formatting : Flag<["-"], "enable-experimental-diagnostic-formatting">, diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index 4043a786023ce..17383e5cb5872 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -372,6 +372,9 @@ def no_color_diagnostics : Flag<["-"], "no-color-diagnostics">, def debug_diagnostic_names : Flag<["-"], "debug-diagnostic-names">, Flags<[FrontendOption, DoesNotAffectIncrementalBuild, HelpHidden]>, HelpText<"Include diagnostic names when printing">; +def print_educational_notes : Flag<["-"], "print-educational-notes">, + Flags<[FrontendOption, DoesNotAffectIncrementalBuild]>, + HelpText<"Include educational notes in printed diagnostic output, if available">; def module_cache_path : Separate<["-"], "module-cache-path">, Flags<[FrontendOption, DoesNotAffectIncrementalBuild, ArgumentIsPath]>, diff --git a/include/swift/Sema/IDETypeCheckingRequests.h b/include/swift/Sema/IDETypeCheckingRequests.h index d32238cf7a4a8..7d274a94dc906 100644 --- a/include/swift/Sema/IDETypeCheckingRequests.h +++ b/include/swift/Sema/IDETypeCheckingRequests.h @@ -72,8 +72,7 @@ class IsDeclApplicableRequest: friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, - DeclApplicabilityOwner Owner) const; + bool evaluate(Evaluator &evaluator, DeclApplicabilityOwner Owner) const; public: // Caching @@ -170,8 +169,7 @@ class TypeRelationCheckRequest: friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, - TypeRelationCheckInput Owner) const; + bool evaluate(Evaluator &evaluator, TypeRelationCheckInput Owner) const; public: // Caching @@ -194,7 +192,7 @@ class RootAndResultTypeOfKeypathDynamicMemberRequest: friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, SubscriptDecl* SD) const; + TypePair evaluate(Evaluator &evaluator, SubscriptDecl* SD) const; public: // Caching @@ -214,7 +212,7 @@ class RootTypeOfKeypathDynamicMemberRequest: friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, SubscriptDecl* SD) const { + Type evaluate(Evaluator &evaluator, SubscriptDecl* SD) const { return evaluateOrDefault(SD->getASTContext().evaluator, RootAndResultTypeOfKeypathDynamicMemberRequest{SD}, TypePair()). FirstTy; diff --git a/include/swift/Serialization/SerializedModuleLoader.h b/include/swift/Serialization/SerializedModuleLoader.h index b508bb08dfd56..c02d80846b7eb 100644 --- a/include/swift/Serialization/SerializedModuleLoader.h +++ b/include/swift/Serialization/SerializedModuleLoader.h @@ -184,6 +184,10 @@ class SerializedModuleLoaderBase : public ModuleLoader { unsigned previousGeneration, llvm::TinyPtrVector &methods) override; + virtual void loadDerivativeFunctionConfigurations( + AbstractFunctionDecl *originalAFD, unsigned previousGeneration, + llvm::SetVector &results) override; + virtual void verifyAllModules() override; }; @@ -380,6 +384,9 @@ class SerializedASTFile final : public LoadedFile { SmallVectorImpl &Results, llvm::function_ref matchAttributes) const override; + virtual void + getOperatorDecls(SmallVectorImpl &results) const override; + virtual void getPrecedenceGroups(SmallVectorImpl &Results) const override; diff --git a/include/swift/SwiftRemoteMirror/SwiftRemoteMirror.h b/include/swift/SwiftRemoteMirror/SwiftRemoteMirror.h index 86ee1cc2a740b..53336f888378a 100644 --- a/include/swift/SwiftRemoteMirror/SwiftRemoteMirror.h +++ b/include/swift/SwiftRemoteMirror/SwiftRemoteMirror.h @@ -149,6 +149,16 @@ swift_reflection_typeRefForMangledTypeName(SwiftReflectionContextRef ContextRef, const char *MangledName, uint64_t Length); +/// Returns the demangled name for a typeref, or NULL if the name couldn't be +/// created. +/// +/// The returned string is heap allocated and the caller must free() it when +/// done. +SWIFT_REMOTE_MIRROR_LINKAGE +char * +swift_reflection_copyDemangledNameForTypeRef( + SwiftReflectionContextRef ContextRef, swift_typeref_t OpaqueTypeRef); + /// Returns a structure describing the layout of a value of a typeref. /// For classes, this returns the reference value itself. SWIFT_REMOTE_MIRROR_LINKAGE diff --git a/include/swift/SwiftRemoteMirror/SwiftRemoteMirrorLegacyInterop.h b/include/swift/SwiftRemoteMirror/SwiftRemoteMirrorLegacyInterop.h index 95524d170ceec..3834872d793f3 100644 --- a/include/swift/SwiftRemoteMirror/SwiftRemoteMirrorLegacyInterop.h +++ b/include/swift/SwiftRemoteMirror/SwiftRemoteMirrorLegacyInterop.h @@ -101,6 +101,11 @@ swift_reflection_interop_typeRefForMangledTypeName( const char *MangledName, uint64_t Length); +static inline char * +swift_reflection_interop_copyDemangledNameForTypeRef( + SwiftReflectionInteropContextRef ContextRef, + swift_typeref_interop_t OpaqueTypeRef); + static inline swift_typeinfo_t swift_reflection_interop_infoForTypeRef(SwiftReflectionInteropContextRef ContextRef, swift_typeref_interop_t OpaqueTypeRef); @@ -250,6 +255,9 @@ struct SwiftReflectionFunctions { const char *MangledName, uint64_t Length); + char * (*copyDemangledNameForTypeRef)( + SwiftReflectionContextRef ContextRef, swift_typeref_t OpaqueTypeRef); + swift_typeinfo_t (*infoForTypeRef)(SwiftReflectionContextRef ContextRef, swift_typeref_t OpaqueTypeRef); @@ -354,7 +362,7 @@ swift_reflection_interop_libraryOwnsAddress( // Search the images list to see if the address is in one of them. struct SwiftReflectionInteropContextLegacyImageRangeList *Node = ContextRef->LegacyImageRangeList; - while (Node != nullptr) { + while (Node != NULL) { if (Node->Start <= Address && Address < Node->End) return 1; Node = Node->Next; @@ -381,7 +389,7 @@ swift_reflection_interop_libraryForAddress( return Library; } } - return nullptr; + return NULL; } static inline uintptr_t @@ -409,7 +417,7 @@ swift_reflection_interop_libraryForObject( if (Library->IsLegacy) return Library; } - return nullptr; + return NULL; } return swift_reflection_interop_libraryForAddress(ContextRef, Metadata); @@ -418,7 +426,7 @@ swift_reflection_interop_libraryForObject( static inline int swift_reflection_interop_loadFunctions(struct SwiftReflectionInteropContext *Context, void *Handle) { - if (Handle == nullptr) + if (Handle == NULL) return 0; struct SwiftReflectionInteropContextLibrary *Library = &Context @@ -430,7 +438,7 @@ swift_reflection_interop_loadFunctions(struct SwiftReflectionInteropContext *Con #endif #define LOAD_NAMED(field, symbol, required) do { \ Functions->field = (decltype(Functions->field))dlsym(Handle, symbol); \ - if (required && Functions->field == nullptr) return 0; \ + if (required && Functions->field == NULL) return 0; \ } while (0) #define LOAD(name) LOAD_NAMED(name, "swift_reflection_" #name, 1) #define LOAD_OPT(name) LOAD_NAMED(name, "swift_reflection_" #name, 0) @@ -442,7 +450,7 @@ swift_reflection_interop_loadFunctions(struct SwiftReflectionInteropContext *Con if (version < SWIFT_LEGACY_METADATA_MIN_VERSION) return 0; - int IsLegacy = dlsym(Handle, "swift_reflection_addImage") == nullptr; + int IsLegacy = dlsym(Handle, "swift_reflection_addImage") == NULL; if (IsLegacy) { LOAD_NAMED(createReflectionContextLegacy, "swift_reflection_createReflectionContext", 1); @@ -464,6 +472,7 @@ swift_reflection_interop_loadFunctions(struct SwiftReflectionInteropContext *Con LOAD(typeRefForMetadata); LOAD(typeRefForInstance); LOAD(typeRefForMangledTypeName); + LOAD_OPT(copyDemangledNameForTypeRef); LOAD(infoForTypeRef); LOAD(childOfTypeRef); LOAD(infoForMetadata); @@ -499,11 +508,11 @@ swift_reflection_interop_readBytesAdapter(void *reader_context, void *FreeContext; const void *ptr = Context->ReadBytes(Context->ReaderContext, address, size, &FreeContext); - if (ptr == nullptr) + if (ptr == NULL) return 0; memcpy(dest, ptr, size); - if (Context->FreeBytes != nullptr) + if (Context->FreeBytes != NULL) Context->FreeBytes(Context->ReaderContext, ptr, FreeContext); return 1; } @@ -536,6 +545,8 @@ swift_reflection_interop_minimalDataLayoutQueryFunction4( void *ReaderContext, DataLayoutQueryType type, void *inBuffer, void *outBuffer) { + (void)ReaderContext; + (void)inBuffer; switch (type) { case DLQ_GetPointerSize: case DLQ_GetSizeSize: { @@ -565,17 +576,19 @@ swift_reflection_interop_minimalDataLayoutQueryFunction8( void *ReaderContext, DataLayoutQueryType type, void *inBuffer, void *outBuffer) { + (void)ReaderContext; + (void)inBuffer; // Caveat: This assumes the process being examined is // running in the same kind of environment as this host code. #if defined(__APPLE__) && __APPLE__ - auto applePlatform = true; + int applePlatform = 1; #else - auto applePlatform = false; + int applePlatform = 0; #endif #if defined(__APPLE__) && __APPLE__ && ((defined(TARGET_OS_IOS) && TARGET_OS_IOS) || (defined(TARGET_OS_IOS) && TARGET_OS_WATCH) || (defined(TARGET_OS_TV) && TARGET_OS_TV)) - auto iosDerivedPlatform = true; + int iosDerivedPlatform = 1; #else - auto iosDerivedPlatform = false; + int iosDerivedPlatform = 0; #endif switch (type) { @@ -628,7 +641,7 @@ swift_reflection_interop_createReflectionContext( return swift_reflection_interop_createReflectionContextWithDataLayout( ReaderContext, - nullptr, + DataLayout, FreeBytes, ReadBytes, GetStringLength, @@ -654,7 +667,7 @@ swift_reflection_interop_createReflectionContextWithDataLayout( ContextRef->GetStringLength = GetStringLength; ContextRef->GetSymbolAddress = GetSymbolAddress; - ContextRef->AddressToLibraryCache = CFDictionaryCreateMutable(nullptr, 0, nullptr, nullptr); + ContextRef->AddressToLibraryCache = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); return ContextRef; } @@ -687,7 +700,7 @@ swift_reflection_interop_addLibrary( } else { uint8_t PointerSize; int result = ContextRef->DataLayout( - ContextRef->ReaderContext, DLQ_GetPointerSize, nullptr, &PointerSize); + ContextRef->ReaderContext, DLQ_GetPointerSize, NULL, &PointerSize); if (!result) abort(); // We need the pointer size, can't proceed without it. @@ -712,14 +725,14 @@ swift_reflection_interop_destroyReflectionContext( free(ContextRef->Libraries); struct SwiftReflectionInteropContextLegacyImageRangeList *LegacyImageRangeList = ContextRef->LegacyImageRangeList; - while (LegacyImageRangeList != nullptr) { + while (LegacyImageRangeList != NULL) { struct SwiftReflectionInteropContextLegacyImageRangeList *Next = LegacyImageRangeList->Next; free(LegacyImageRangeList); LegacyImageRangeList = Next; } struct SwiftReflectionInteropContextFreeList *FreeList = ContextRef->FreeList; - while (FreeList != nullptr) { + while (FreeList != NULL) { ContextRef->FreeBytes(ContextRef->ReaderContext, FreeList->Pointer, FreeList->Context); struct SwiftReflectionInteropContextFreeList *Next = FreeList->Next; @@ -771,37 +784,37 @@ swift_reflection_interop_addImageLegacy( ImageStart, sizeof(MachHeader), &FreeContext); - if (Buf == nullptr) + if (Buf == NULL) return 0; MachHeader *Header = (MachHeader *)Buf; if (Header->magic != MH_MAGIC && Header->magic != MH_MAGIC_64) { - if (ContextRef->FreeBytes != nullptr) + if (ContextRef->FreeBytes != NULL) ContextRef->FreeBytes(ContextRef->ReaderContext, Buf, FreeContext); return 0; } // Read the commands. uint32_t Length = Header->sizeofcmds; - if (ContextRef->FreeBytes != nullptr) + if (ContextRef->FreeBytes != NULL) ContextRef->FreeBytes(ContextRef->ReaderContext, Buf, FreeContext); Buf = ContextRef->ReadBytes(ContextRef->ReaderContext, ImageStart, Length, &FreeContext); - if (Buf == nullptr) + if (Buf == NULL) return 0; Header = (MachHeader *)Buf; // Find the TEXT segment and figure out where the end is. unsigned long TextSize; uint8_t *TextSegment = getsegmentdata(Header, "__TEXT", &TextSize); - if (ContextRef->FreeBytes != nullptr) + if (ContextRef->FreeBytes != NULL) ContextRef->FreeBytes(ContextRef->ReaderContext, Buf, FreeContext); - if (TextSegment == nullptr) { + if (TextSegment == NULL) { return 0; } unsigned long TextEnd = TextSegment - (uint8_t *)Buf + TextSize; @@ -811,7 +824,7 @@ swift_reflection_interop_addImageLegacy( ImageStart, TextEnd, &FreeContext); - if (Buf == nullptr) + if (Buf == NULL) return 0; Header = (MachHeader *)Buf; @@ -839,7 +852,7 @@ swift_reflection_interop_addImageLegacy( &info.reflstr) || success; if (!success) { - if (ContextRef->FreeBytes != nullptr) + if (ContextRef->FreeBytes != NULL) ContextRef->FreeBytes(ContextRef->ReaderContext, Buf, FreeContext); return 0; } @@ -863,7 +876,7 @@ swift_reflection_interop_addImageLegacy( // If the buffer needs to be freed, save buffer and free context to free it when the // reflection context is destroyed. - if (ContextRef->FreeBytes != nullptr) { + if (ContextRef->FreeBytes != NULL) { struct SwiftReflectionInteropContextFreeList *FreeListNode = (struct SwiftReflectionInteropContextFreeList *)malloc(sizeof(*FreeListNode)); FreeListNode->Next = ContextRef->FreeList; @@ -911,7 +924,7 @@ swift_reflection_interop_lookupMetadata(SwiftReflectionInteropContextRef Context swift_metadata_interop_t Result = {}; struct SwiftReflectionInteropContextLibrary *Library = swift_reflection_interop_libraryForAddress(ContextRef, Metadata); - if (Library != nullptr) { + if (Library != NULL) { Result.Metadata = Metadata; Result.Library = (int)LIBRARY_INDEX; } @@ -935,7 +948,7 @@ swift_reflection_interop_typeRefForInstance(SwiftReflectionInteropContextRef Con swift_typeref_interop_t Result = {}; struct SwiftReflectionInteropContextLibrary *Library = swift_reflection_interop_libraryForObject(ContextRef, Object); - if (Library != nullptr) { + if (Library != NULL) { swift_typeref_t Typeref = Library->Functions.typeRefForInstance(Library->Context, Object); Result.Typeref = Typeref; @@ -966,6 +979,17 @@ swift_reflection_interop_typeRefForMangledTypeName( return Result; } +static inline char * +swift_reflection_interop_copyDemangledNameForTypeRef( + SwiftReflectionInteropContextRef ContextRef, + swift_typeref_interop_t OpaqueTypeRef) { + DECLARE_LIBRARY(OpaqueTypeRef.Library); + if (Library->Functions.copyDemangledNameForTypeRef) + return Library->Functions.copyDemangledNameForTypeRef(Library->Context, + OpaqueTypeRef.Typeref); + return NULL; +} + static inline swift_typeinfo_t swift_reflection_interop_infoForTypeRef(SwiftReflectionInteropContextRef ContextRef, swift_typeref_interop_t OpaqueTypeRef) { @@ -1021,7 +1045,7 @@ swift_reflection_interop_infoForInstance(SwiftReflectionInteropContextRef Contex struct SwiftReflectionInteropContextLibrary *Library = swift_reflection_interop_libraryForObject(ContextRef, Object); - if (Library != nullptr) { + if (Library != NULL) { Result = Library->Functions.infoForInstance(Library->Context, Object); } else { Result.Kind = SWIFT_UNKNOWN; @@ -1037,7 +1061,7 @@ swift_reflection_interop_childOfInstance(SwiftReflectionInteropContextRef Contex swift_childinfo_interop_t Result = {}; struct SwiftReflectionInteropContextLibrary *Library = swift_reflection_interop_libraryForObject(ContextRef, Object); - if (Library != nullptr) { + if (Library != NULL) { swift_childinfo_t LibResult = Library->Functions.childOfInstance(Library->Context, Object, Index); Result.Name = LibResult.Name; @@ -1115,7 +1139,7 @@ swift_reflection_interop_dumpInfoForInstance(SwiftReflectionInteropContextRef Co uintptr_t Object) { struct SwiftReflectionInteropContextLibrary *Library = swift_reflection_interop_libraryForObject(ContextRef, Object); - if (Library != nullptr) { + if (Library != NULL) { Library->Functions.dumpInfoForInstance(Library->Context, Object); } } diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 231eec4c32a5a..037e08199fedb 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1471,6 +1471,17 @@ void ASTContext::loadObjCMethods( } } +void ASTContext::loadDerivativeFunctionConfigurations( + AbstractFunctionDecl *originalAFD, unsigned previousGeneration, + llvm::SetVector &results) { + PrettyStackTraceDecl stackTrace( + "loading derivative function configurations for", originalAFD); + for (auto &loader : getImpl().ModuleLoaders) { + loader->loadDerivativeFunctionConfigurations(originalAFD, + previousGeneration, results); + } +} + void ASTContext::verifyAllLoadedModules() const { #ifndef NDEBUG FrontendStatsTracer tracer(Stats, "verify-all-loaded-modules"); diff --git a/lib/AST/ASTDemangler.cpp b/lib/AST/ASTDemangler.cpp index 1b91a213bbb60..a2c43cf1c12c7 100644 --- a/lib/AST/ASTDemangler.cpp +++ b/lib/AST/ASTDemangler.cpp @@ -365,7 +365,8 @@ Type ASTBuilder::createFunctionType( auto parameterFlags = ParameterTypeFlags() .withValueOwnership(ownership) .withVariadic(flags.isVariadic()) - .withAutoClosure(flags.isAutoClosure()); + .withAutoClosure(flags.isAutoClosure()) + .withNoDerivative(flags.isNoDerivative()); funcParams.push_back(AnyFunctionType::Param(type, label, parameterFlags)); } @@ -386,6 +387,19 @@ Type ASTBuilder::createFunctionType( break; } + DifferentiabilityKind diffKind; + switch (flags.getDifferentiabilityKind()) { + case FunctionMetadataDifferentiabilityKind::NonDifferentiable: + diffKind = DifferentiabilityKind::NonDifferentiable; + break; + case FunctionMetadataDifferentiabilityKind::Normal: + diffKind = DifferentiabilityKind::Normal; + break; + case FunctionMetadataDifferentiabilityKind::Linear: + diffKind = DifferentiabilityKind::Linear; + break; + } + auto noescape = (representation == FunctionTypeRepresentation::Swift || representation == FunctionTypeRepresentation::Block) @@ -393,9 +407,7 @@ Type ASTBuilder::createFunctionType( FunctionType::ExtInfo incompleteExtInfo( FunctionTypeRepresentation::Swift, - noescape, flags.throws(), - DifferentiabilityKind::NonDifferentiable, - /*clangFunctionType*/nullptr); + noescape, flags.throws(), diffKind, /*clangFunctionType*/nullptr); const clang::Type *clangFunctionType = nullptr; if (representation == FunctionTypeRepresentation::CFunctionPointer) diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index 7ed6f750fa345..28caa1120ff95 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -1517,6 +1517,18 @@ void ASTMangler::appendImplFunctionType(SILFunctionType *fn) { if (!fn->isNoEscape()) OpArgs.push_back('e'); + // Differentiability kind. + switch (fn->getExtInfo().getDifferentiabilityKind()) { + case DifferentiabilityKind::NonDifferentiable: + break; + case DifferentiabilityKind::Normal: + OpArgs.push_back('d'); + break; + case DifferentiabilityKind::Linear: + OpArgs.push_back('l'); + break; + } + // if (fn->getExtInfo().hasContext()) { OpArgs.push_back(getParamConvention(fn->getCalleeConvention())); @@ -2117,6 +2129,18 @@ void ASTMangler::appendFunctionType(AnyFunctionType *fn, bool isAutoClosure, case AnyFunctionType::Representation::Thin: return appendOperator("Xf"); case AnyFunctionType::Representation::Swift: + if (fn->getDifferentiabilityKind() == DifferentiabilityKind::Normal) { + if (fn->isNoEscape()) + return appendOperator("XF"); + else + return appendOperator("XG"); + } + if (fn->getDifferentiabilityKind() == DifferentiabilityKind::Linear) { + if (fn->isNoEscape()) + return appendOperator("XH"); + else + return appendOperator("XI"); + } if (isAutoClosure) { if (fn->isNoEscape()) return appendOperator("XK"); diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index 6a3265a606b6c..093fd3a894c9f 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -1121,7 +1121,7 @@ ASTScopeImpl::expandAndBeCurrentDetectingRecursion(ScopeCreator &scopeCreator) { ExpandASTScopeRequest{this, &scopeCreator}, nullptr); } -llvm::Expected +ASTScopeImpl * ExpandASTScopeRequest::evaluate(Evaluator &evaluator, ASTScopeImpl *parent, ScopeCreator *scopeCreator) const { auto *insertionPoint = parent->expandAndBeCurrent(*scopeCreator); diff --git a/lib/AST/AccessRequests.cpp b/lib/AST/AccessRequests.cpp index 29908cfdddfe8..ef36b562e0fc6 100644 --- a/lib/AST/AccessRequests.cpp +++ b/lib/AST/AccessRequests.cpp @@ -36,7 +36,7 @@ namespace swift { //----------------------------------------------------------------------------// // AccessLevel computation //----------------------------------------------------------------------------// -llvm::Expected +AccessLevel AccessLevelRequest::evaluate(Evaluator &evaluator, ValueDecl *D) const { assert(!D->hasAccess()); @@ -168,7 +168,7 @@ static bool isStoredWithPrivateSetter(VarDecl *VD) { return true; } -llvm::Expected +AccessLevel SetterAccessLevelRequest::evaluate(Evaluator &evaluator, AbstractStorageDecl *ASD) const { assert(!ASD->Accessors.getInt().hasValue()); @@ -205,7 +205,7 @@ void SetterAccessLevelRequest::cacheResult(AccessLevel value) const { // DefaultAccessLevel computation //----------------------------------------------------------------------------// -llvm::Expected> +std::pair DefaultAndMaxAccessLevelRequest::evaluate(Evaluator &evaluator, ExtensionDecl *ED) const { auto &Ctx = ED->getASTContext(); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 597308fcdeb81..9cd85da7c5498 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -1394,7 +1394,7 @@ createExtensionGenericParams(ASTContext &ctx, return toParams; } -llvm::Expected +GenericParamList * GenericParamListRequest::evaluate(Evaluator &evaluator, GenericContext *value) const { if (auto *ext = dyn_cast(value)) { // Create the generic parameter list for the extension by cloning the @@ -1855,6 +1855,17 @@ bool Pattern::isNeverDefaultInitializable() const { return result; } +bool PatternBindingDecl::isDefaultInitializableViaPropertyWrapper(unsigned i) const { + if (auto singleVar = getSingleVar()) { + if (auto wrapperInfo = singleVar->getAttachedPropertyWrapperTypeInfo(0)) { + if (wrapperInfo.defaultInit) + return true; + } + } + + return false; +} + bool PatternBindingDecl::isDefaultInitializable(unsigned i) const { const auto entry = getPatternList()[i]; @@ -1864,14 +1875,14 @@ bool PatternBindingDecl::isDefaultInitializable(unsigned i) const { // If the outermost attached property wrapper vends an `init()`, use that // for default initialization. + if (isDefaultInitializableViaPropertyWrapper(i)) + return true; + + // If one of the attached wrappers is missing a wrappedValue + // initializer, cannot default-initialize. if (auto singleVar = getSingleVar()) { if (auto wrapperInfo = singleVar->getAttachedPropertyWrapperTypeInfo(0)) { - if (wrapperInfo.defaultInit) - return true; - - // If one of the attached wrappers is missing an initialValue - // initializer, cannot default-initialize. - if (!singleVar->allAttachedPropertyWrappersHaveInitialValueInit()) + if (!singleVar->allAttachedPropertyWrappersHaveWrappedValueInit()) return false; } } @@ -4125,7 +4136,7 @@ void NominalTypeDecl::synthesizeSemanticMembersIfNeeded(DeclName member) { if (auto actionToTake = action) { (void)evaluateOrDefault(Context.evaluator, - ResolveImplicitMemberRequest{this, actionToTake.getValue()}, false); + ResolveImplicitMemberRequest{this, actionToTake.getValue()}, {}); } } @@ -4203,7 +4214,7 @@ synthesizeEmptyFunctionBody(AbstractFunctionDecl *afd, void *context) { /*isTypeChecked=*/true }; } -llvm::Expected +DestructorDecl * GetDestructorRequest::evaluate(Evaluator &evaluator, ClassDecl *CD) const { auto &ctx = CD->getASTContext(); auto *DD = new (ctx) DestructorDecl(CD->getLoc(), CD); @@ -4268,8 +4279,9 @@ AncestryOptions ClassDecl::checkAncestry() const { AncestryFlags())); } -llvm::Expected -ClassAncestryFlagsRequest::evaluate(Evaluator &evaluator, ClassDecl *value) const { +AncestryFlags +ClassAncestryFlagsRequest::evaluate(Evaluator &evaluator, + ClassDecl *value) const { llvm::SmallPtrSet visited; AncestryOptions result; @@ -5021,7 +5033,8 @@ ArrayRef ProtocolDecl::getCachedRequirementSignature() const { void ProtocolDecl::computeKnownProtocolKind() const { auto module = getModuleContext(); if (module != module->getASTContext().getStdlibModule() && - !module->getName().is("Foundation")) { + !module->getName().is("Foundation") && + !module->getName().is("_Differentiation")) { const_cast(this)->Bits.ProtocolDecl.KnownProtocol = 1; return; } @@ -5815,7 +5828,7 @@ bool VarDecl::hasAttachedPropertyWrapper() const { /// Whether all of the attached property wrappers have an init(wrappedValue:) /// initializer. -bool VarDecl::allAttachedPropertyWrappersHaveInitialValueInit() const { +bool VarDecl::allAttachedPropertyWrappersHaveWrappedValueInit() const { for (unsigned i : indices(getAttachedPropertyWrappers())) { if (!getAttachedPropertyWrapperTypeInfo(i).wrappedValueInit) return false; @@ -5920,7 +5933,7 @@ bool VarDecl::isPropertyMemberwiseInitializedWithWrappedType() const { // If all property wrappers have a wrappedValue initializer, the property // wrapper will be initialized that way. - return allAttachedPropertyWrappersHaveInitialValueInit(); + return allAttachedPropertyWrappersHaveWrappedValueInit(); } bool VarDecl::isInnermostPropertyWrapperInitUsesEscapingAutoClosure() const { @@ -7099,8 +7112,10 @@ AbstractFunctionDecl::getDerivativeFunctionConfigurations() { prepareDerivativeFunctionConfigurations(); auto &ctx = getASTContext(); if (ctx.getCurrentGeneration() > DerivativeFunctionConfigGeneration) { - // TODO(TF-1100): Upstream derivative function configuration serialization - // logic. + unsigned previousGeneration = DerivativeFunctionConfigGeneration; + DerivativeFunctionConfigGeneration = ctx.getCurrentGeneration(); + ctx.loadDerivativeFunctionConfigurations(this, previousGeneration, + *DerivativeFunctionConfigs); } return DerivativeFunctionConfigs->getArrayRef(); } @@ -7486,7 +7501,7 @@ LiteralExpr *EnumElementDecl::getRawValueExpr() const { (void)evaluateOrDefault( getASTContext().evaluator, EnumRawValuesRequest{getParentEnum(), TypeResolutionStage::Interface}, - true); + {}); return RawValueExpr; } @@ -7496,7 +7511,7 @@ LiteralExpr *EnumElementDecl::getStructuralRawValueExpr() const { (void)evaluateOrDefault( getASTContext().evaluator, EnumRawValuesRequest{getParentEnum(), TypeResolutionStage::Structural}, - true); + {}); return RawValueExpr; } diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp index 17babf347fdcc..d0d2d8c7efb68 100644 --- a/lib/AST/DeclContext.cpp +++ b/lib/AST/DeclContext.cpp @@ -323,7 +323,7 @@ ResilienceExpansion DeclContext::getResilienceExpansion() const { ResilienceExpansion::Minimal); } -llvm::Expected +ResilienceExpansion swift::ResilienceExpansionRequest::evaluate(Evaluator &evaluator, DeclContext *context) const { for (const auto *dc = context->getLocalContext(); dc && dc->isLocalContext(); diff --git a/lib/AST/DiagnosticEngine.cpp b/lib/AST/DiagnosticEngine.cpp index eb21810df9222..01edba7079ee9 100644 --- a/lib/AST/DiagnosticEngine.cpp +++ b/lib/AST/DiagnosticEngine.cpp @@ -984,16 +984,15 @@ void DiagnosticEngine::emitDiagnostic(const Diagnostic &diagnostic) { info->ChildDiagnosticInfo = childInfoPtrs; SmallVector educationalNotePaths; - if (useEducationalNotes) { - auto associatedNotes = educationalNotes[(uint32_t)diagnostic.getID()]; - while (associatedNotes && *associatedNotes) { - SmallString<128> notePath(getDiagnosticDocumentationPath()); - llvm::sys::path::append(notePath, *associatedNotes); - educationalNotePaths.push_back(notePath.str().str()); - associatedNotes++; - } - info->EducationalNotePaths = educationalNotePaths; + + auto associatedNotes = educationalNotes[(uint32_t)diagnostic.getID()]; + while (associatedNotes && *associatedNotes) { + SmallString<128> notePath(getDiagnosticDocumentationPath()); + llvm::sys::path::append(notePath, *associatedNotes); + educationalNotePaths.push_back(notePath.str().str()); + associatedNotes++; } + info->EducationalNotePaths = educationalNotePaths; for (auto &consumer : Consumers) { consumer->handleDiagnostic(SourceMgr, *info); diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp index 4428fdad3da80..7939a303c1172 100644 --- a/lib/AST/GenericSignatureBuilder.cpp +++ b/lib/AST/GenericSignatureBuilder.cpp @@ -7392,7 +7392,7 @@ static bool isCanonicalRequest(GenericSignature baseSignature, return true; } -llvm::Expected +GenericSignature AbstractGenericSignatureRequest::evaluate( Evaluator &evaluator, GenericSignatureImpl *baseSignature, @@ -7450,7 +7450,7 @@ AbstractGenericSignatureRequest::evaluate( canBaseSignature.getPointer(), std::move(canAddedParameters), std::move(canAddedRequirements)}); if (!canSignatureResult || !*canSignatureResult) - return canSignatureResult; + return GenericSignature(); // Substitute in the original generic parameters to form a more-sugared // result closer to what the original request wanted. Note that this @@ -7505,7 +7505,7 @@ AbstractGenericSignatureRequest::evaluate( SourceLoc(), /*allowConcreteGenericParams=*/true); } -llvm::Expected +GenericSignature InferredGenericSignatureRequest::evaluate( Evaluator &evaluator, ModuleDecl *parentModule, GenericSignatureImpl *parentSig, diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp index 0ad2ed67e3424..bc6c9201ed498 100644 --- a/lib/AST/Module.cpp +++ b/lib/AST/Module.cpp @@ -136,8 +136,8 @@ SourceFile::~SourceFile() = default; class swift::SourceLookupCache { /// A lookup map for value decls. When declarations are added they are added /// under all variants of the name they can be found under. - class DeclMap { - llvm::DenseMap> Members; + class ValueDeclMap { + llvm::DenseMap> Members; public: void add(ValueDecl *VD) { @@ -156,10 +156,15 @@ class swift::SourceLookupCache { } }; - DeclMap TopLevelValues; - DeclMap ClassMembers; + ValueDeclMap TopLevelValues; + ValueDeclMap ClassMembers; bool MemberCachePopulated = false; + template + using OperatorMap = llvm::DenseMap>; + OperatorMap Operators; + OperatorMap PrecedenceGroups; + template void addToUnqualifiedLookupCache(Range decls, bool onlyOperators); template @@ -175,7 +180,28 @@ class swift::SourceLookupCache { void lookupValue(DeclName Name, NLKind LookupKind, SmallVectorImpl &Result); - + + /// Retrieves all the operator decls. The order of the results is not + /// guaranteed to be meaningful. + void getOperatorDecls(SmallVectorImpl &results); + + /// Retrieves all the precedence groups. The order of the results is not + /// guaranteed to be meaningful. + void getPrecedenceGroups(SmallVectorImpl &results); + + /// Look up an operator declaration. + /// + /// \param name The operator name ("+", ">>", etc.) + /// \param fixity The fixity of the operator (infix, prefix or postfix). + void lookupOperator(Identifier name, OperatorFixity fixity, + TinyPtrVector &results); + + /// Look up a precedence group. + /// + /// \param name The operator name ("+", ">>", etc.) + void lookupPrecedenceGroup(Identifier name, + TinyPtrVector &results); + void lookupVisibleDecls(AccessPathTy AccessPath, VisibleDeclConsumer &Consumer, NLKind LookupKind); @@ -224,6 +250,12 @@ void SourceLookupCache::addToUnqualifiedLookupCache(Range decls, if (!ED->hasUnparsedMembers() || ED->maybeHasOperatorDeclarations()) addToUnqualifiedLookupCache(ED->getMembers(), true); } + + if (auto *OD = dyn_cast(D)) + Operators[OD->getName()].push_back(OD); + + if (auto *PG = dyn_cast(D)) + PrecedenceGroups[PG->getName()].push_back(PG); } } @@ -300,6 +332,39 @@ void SourceLookupCache::lookupValue(DeclName Name, NLKind LookupKind, Result.push_back(Elt); } +void SourceLookupCache::getPrecedenceGroups( + SmallVectorImpl &results) { + for (auto &groups : PrecedenceGroups) + results.append(groups.second.begin(), groups.second.end()); +} + +void SourceLookupCache::getOperatorDecls( + SmallVectorImpl &results) { + for (auto &ops : Operators) + results.append(ops.second.begin(), ops.second.end()); +} + +void SourceLookupCache::lookupOperator(Identifier name, OperatorFixity fixity, + TinyPtrVector &results) { + auto ops = Operators.find(name); + if (ops == Operators.end()) + return; + + for (auto *op : ops->second) + if (op->getFixity() == fixity) + results.push_back(op); +} + +void SourceLookupCache::lookupPrecedenceGroup( + Identifier name, TinyPtrVector &results) { + auto groups = PrecedenceGroups.find(name); + if (groups == PrecedenceGroups.end()) + return; + + for (auto *group : groups->second) + results.push_back(group); +} + void SourceLookupCache::lookupVisibleDecls(AccessPathTy AccessPath, VisibleDeclConsumer &Consumer, NLKind LookupKind) { @@ -680,18 +745,36 @@ void SourceFile::getTopLevelDecls(SmallVectorImpl &Results) const { Results.append(decls.begin(), decls.end()); } +void ModuleDecl::getOperatorDecls( + SmallVectorImpl &results) const { + // For a parsed module, we can check the source cache on the module rather + // than doing an O(N) search over the source files. + if (isParsedModule(this)) { + getSourceLookupCache().getOperatorDecls(results); + return; + } + FORWARD(getOperatorDecls, (results)); +} + +void SourceFile::getOperatorDecls( + SmallVectorImpl &results) const { + getCache().getOperatorDecls(results); +} + void ModuleDecl::getPrecedenceGroups( - SmallVectorImpl &Results) const { - FORWARD(getPrecedenceGroups, (Results)); + SmallVectorImpl &results) const { + // For a parsed module, we can check the source cache on the module rather + // than doing an O(N) search over the source files. + if (isParsedModule(this)) { + getSourceLookupCache().getPrecedenceGroups(results); + return; + } + FORWARD(getPrecedenceGroups, (results)); } void SourceFile::getPrecedenceGroups( - SmallVectorImpl &Results) const { - for (auto pair : PrecedenceGroups) { - if (pair.second.getPointer() && pair.second.getInt()) { - Results.push_back(pair.second.getPointer()); - } - } + SmallVectorImpl &results) const { + getCache().getPrecedenceGroups(results); } void SourceFile::getLocalTypeDecls(SmallVectorImpl &Results) const { @@ -827,7 +910,7 @@ ProtocolConformanceRef ModuleDecl::lookupConformance(Type type, ProtocolConformanceRef::forInvalid()); } -llvm::Expected +ProtocolConformanceRef LookupConformanceInModuleRequest::evaluate( Evaluator &evaluator, LookupConformanceDescriptor desc) const { auto *mod = desc.Mod; @@ -943,9 +1026,6 @@ LookupConformanceInModuleRequest::evaluate( } namespace { - template - using OperatorMap = SourceFile::OperatorMap; - template struct OperatorLookup { // Don't fold this into the static_assert: this would trigger an MSVC bug @@ -956,7 +1036,6 @@ namespace { template <> struct OperatorLookup { - constexpr static auto map_ptr = &SourceFile::PrefixOperators; static PrefixOperatorDecl *lookup(Evaluator &eval, const OperatorLookupDescriptor &desc) { // We can return the first prefix operator. All prefix operators of the @@ -969,7 +1048,6 @@ namespace { template <> struct OperatorLookup { - constexpr static auto map_ptr = &SourceFile::InfixOperators; static InfixOperatorDecl *lookup(Evaluator &eval, const OperatorLookupDescriptor &desc) { // Return the first result if it exists. @@ -981,7 +1059,6 @@ namespace { template <> struct OperatorLookup { - constexpr static auto map_ptr = &SourceFile::PostfixOperators; static PostfixOperatorDecl *lookup(Evaluator &eval, const OperatorLookupDescriptor &desc) { // We can return the first postfix operator. All postfix operators of the @@ -994,7 +1071,6 @@ namespace { template <> struct OperatorLookup { - constexpr static auto map_ptr = &SourceFile::PrecedenceGroups; static PrecedenceGroupDecl *lookup(Evaluator &eval, const OperatorLookupDescriptor &desc) { // Return the first result if it exists. @@ -1089,6 +1165,10 @@ static Optional lookupOperatorDeclForName(const FileUnit &File, SourceLoc Loc, Identifier Name, bool includePrivate, bool isCascading) { + auto &eval = File.getASTContext().evaluator; + auto desc = OperatorLookupDescriptor::forFile(const_cast(&File), + Name, isCascading, + /*diagLoc*/ SourceLoc()); switch (File.getKind()) { case FileUnitKind::Builtin: // The Builtin module declares no operators. @@ -1097,23 +1177,16 @@ lookupOperatorDeclForName(const FileUnit &File, SourceLoc Loc, break; case FileUnitKind::SerializedAST: case FileUnitKind::ClangModule: - case FileUnitKind::DWARFModule: { - auto &eval = File.getASTContext().evaluator; - auto desc = OperatorLookupDescriptor::forFile(const_cast(&File), - Name, isCascading, - /*diagLoc*/ SourceLoc()); + case FileUnitKind::DWARFModule: return OperatorLookup::lookup(eval, desc); } - } auto &SF = cast(File); assert(SF.ASTStage >= SourceFile::NameBound); - // Look for an operator declaration in the current module. - const auto OP_MAP = OperatorLookup::map_ptr; - auto found = (SF.*OP_MAP).find(Name); - if (found != (SF.*OP_MAP).end() && (includePrivate || found->second.getInt())) - return found->second.getPointer(); + // Check if the decl exists on the file. + if (auto *op = OperatorLookup::lookup(eval, desc)) + return op; // Look for imported operator decls. // Record whether they come from re-exported modules. @@ -1141,8 +1214,9 @@ lookupOperatorDeclForName(const FileUnit &File, SourceLoc Loc, importedOperators[op] |= isExported; } - typename OperatorMap::mapped_type result = { nullptr, true }; - + llvm::PointerIntPair result = {nullptr, + true}; + if (!importedOperators.empty()) { auto start = checkOperatorConflicts(SF, Loc, importedOperators); if (start == importedOperators.end()) @@ -1150,15 +1224,6 @@ lookupOperatorDeclForName(const FileUnit &File, SourceLoc Loc, result = { start->first, start->second }; } - if (includePrivate) { - // Cache the mapping so we don't need to troll imports next time. - // It's not safe to cache the non-private results because we didn't search - // private imports there, but in most non-private cases the result will - // be cached in the final lookup. - auto &mutableOpMap = const_cast &>(SF.*OP_MAP); - mutableOpMap[Name] = result; - } - if (includePrivate || result.getInt()) return result.getPointer(); return nullptr; @@ -1185,7 +1250,7 @@ lookupOperatorDeclForName(ModuleDecl *M, SourceLoc Loc, Identifier Name, } template -llvm::Expected LookupOperatorRequest::evaluate( +OperatorType *LookupOperatorRequest::evaluate( Evaluator &evaluator, OperatorLookupDescriptor desc) const { auto *file = desc.fileOrModule.get(); auto result = @@ -1214,7 +1279,7 @@ llvm::Expected LookupOperatorRequest::evaluate( /*isCascading*/ false); \ return result ? *result : nullptr; \ } \ - template llvm::Expected \ + template Kind##Decl * \ LookupOperatorRequest::evaluate(Evaluator &e, \ OperatorLookupDescriptor d) const; @@ -1224,73 +1289,58 @@ LOOKUP_OPERATOR(PostfixOperator) LOOKUP_OPERATOR(PrecedenceGroup) #undef LOOKUP_OPERATOR -llvm::Expected> +TinyPtrVector DirectOperatorLookupRequest::evaluate(Evaluator &evaluator, OperatorLookupDescriptor descriptor, OperatorFixity fixity) const { - // Query each file. - // TODO: Module-level caching. + // For a parsed module, we can check the source cache on the module rather + // than doing an O(N) search over the source files. TinyPtrVector results; + if (auto module = descriptor.getModule()) { + if (isParsedModule(module)) { + module->getSourceLookupCache().lookupOperator(descriptor.name, fixity, + results); + return results; + } + } + + // Otherwise query each file. for (auto *file : descriptor.getFiles()) file->lookupOperatorDirect(descriptor.name, fixity, results); - return std::move(results); + return results; } void SourceFile::lookupOperatorDirect( Identifier name, OperatorFixity fixity, TinyPtrVector &results) const { - OperatorDecl *op = nullptr; - switch (fixity) { - case OperatorFixity::Infix: { - auto result = InfixOperators.find(name); - if (result != InfixOperators.end()) - op = result->second.getPointer(); - break; - } - case OperatorFixity::Postfix: { - auto result = PostfixOperators.find(name); - if (result != PostfixOperators.end()) - op = result->second.getPointer(); - break; - } - case OperatorFixity::Prefix: { - auto result = PrefixOperators.find(name); - if (result != PrefixOperators.end()) - op = result->second.getPointer(); - break; - } - } - - // We currently can use the operator maps to cache lookup results from other - // modules. Make sure we only return results from the source file. - if (op && op->getDeclContext()->getParentSourceFile() == this) - results.push_back(op); + getCache().lookupOperator(name, fixity, results); } -llvm::Expected> +TinyPtrVector DirectPrecedenceGroupLookupRequest::evaluate( Evaluator &evaluator, OperatorLookupDescriptor descriptor) const { - // Query each file. - // TODO: Module-level caching. + // For a parsed module, we can check the source cache on the module rather + // than doing an O(N) search over the source files. TinyPtrVector results; + if (auto module = descriptor.getModule()) { + if (isParsedModule(module)) { + module->getSourceLookupCache().lookupPrecedenceGroup(descriptor.name, + results); + return results; + } + } + + // Otherwise query each file. for (auto *file : descriptor.getFiles()) file->lookupPrecedenceGroupDirect(descriptor.name, results); - return std::move(results); + return results; } void SourceFile::lookupPrecedenceGroupDirect( Identifier name, TinyPtrVector &results) const { - auto result = PrecedenceGroups.find(name); - if (result == PrecedenceGroups.end()) - return; - - // We currently can use the operator maps to cache lookup results from other - // modules. Make sure we only return results from the source file. - auto *group = result->second.getPointer(); - if (group->getDeclContext()->getParentSourceFile() == this) - results.push_back(group); + getCache().lookupPrecedenceGroup(name, results); } void ModuleDecl::getImportedModules(SmallVectorImpl &modules, @@ -2049,7 +2099,7 @@ ArrayRef Decl::getSPIGroups() const { ArrayRef()); } -llvm::Expected> +llvm::ArrayRef SPIGroupsRequest::evaluate(Evaluator &evaluator, const Decl *decl) const { // Applies only to public ValueDecls and ExtensionDecls. if (auto vd = dyn_cast(decl)) diff --git a/lib/AST/ModuleNameLookup.cpp b/lib/AST/ModuleNameLookup.cpp index 1de9eb97491bc..243772d710163 100644 --- a/lib/AST/ModuleNameLookup.cpp +++ b/lib/AST/ModuleNameLookup.cpp @@ -243,7 +243,8 @@ void ModuleNameLookup::lookupInModule( decls.end()); } -llvm::Expected LookupInModuleRequest::evaluate( +QualifiedLookupResult +LookupInModuleRequest::evaluate( Evaluator &evaluator, const DeclContext *moduleOrFile, DeclName name, NLKind lookupKind, ResolutionKind resolutionKind, const DeclContext *moduleScopeContext) const { diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index ef23b20fbbb14..9a44137186d3b 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -1242,7 +1242,7 @@ NominalTypeDecl::lookupDirect(DeclName name, DirectLookupRequest({this, name, flags}), {}); } -llvm::Expected> +TinyPtrVector DirectLookupRequest::evaluate(Evaluator &evaluator, DirectLookupDescriptor desc) const { const auto &name = desc.Name; @@ -1570,7 +1570,7 @@ bool DeclContext::lookupQualified(ArrayRef typeDecls, return !decls.empty(); } -llvm::Expected +QualifiedLookupResult QualifiedLookupRequest::evaluate(Evaluator &eval, const DeclContext *DC, SmallVector typeDecls, DeclNameRef member, NLOptions options) const { @@ -1709,7 +1709,7 @@ bool DeclContext::lookupQualified(ModuleDecl *module, DeclNameRef member, return !decls.empty(); } -llvm::Expected +QualifiedLookupResult ModuleQualifiedLookupRequest::evaluate(Evaluator &eval, const DeclContext *DC, ModuleDecl *module, DeclNameRef member, NLOptions options) const { @@ -1762,7 +1762,7 @@ ModuleQualifiedLookupRequest::evaluate(Evaluator &eval, const DeclContext *DC, return decls; } -llvm::Expected +QualifiedLookupResult AnyObjectLookupRequest::evaluate(Evaluator &evaluator, const DeclContext *dc, DeclNameRef member, NLOptions options) const { using namespace namelookup; @@ -2188,7 +2188,7 @@ DirectlyReferencedTypeDecls UnderlyingTypeDeclsReferencedRequest::evaluate( } /// Evaluate a superclass declaration request. -llvm::Expected +ClassDecl * SuperclassDeclRequest::evaluate(Evaluator &evaluator, NominalTypeDecl *subject) const { auto &Ctx = subject->getASTContext(); @@ -2252,7 +2252,7 @@ InheritedProtocolsRequest::evaluate(Evaluator &evaluator, return PD->getASTContext().AllocateCopy(result); } -llvm::Expected +NominalTypeDecl * ExtendedNominalRequest::evaluate(Evaluator &evaluator, ExtensionDecl *ext) const { auto typeRepr = ext->getExtendedTypeRepr(); @@ -2289,7 +2289,7 @@ static bool declsAreAssociatedTypes(ArrayRef decls) { return true; } -llvm::Expected +NominalTypeDecl * CustomAttrNominalRequest::evaluate(Evaluator &evaluator, CustomAttr *attr, DeclContext *dc) const { // Find the types referenced by the custom attribute. diff --git a/lib/AST/NameLookupRequests.cpp b/lib/AST/NameLookupRequests.cpp index 9db327cb6b3c4..b0f50f34edc9b 100644 --- a/lib/AST/NameLookupRequests.cpp +++ b/lib/AST/NameLookupRequests.cpp @@ -101,7 +101,7 @@ void HasMissingDesignatedInitializersRequest::cacheResult(bool result) const { classDecl->setHasMissingDesignatedInitializers(result); } -llvm::Expected +bool HasMissingDesignatedInitializersRequest::evaluate(Evaluator &evaluator, ClassDecl *subject) const { // Short-circuit and check for the attribute here. diff --git a/lib/AST/Pattern.cpp b/lib/AST/Pattern.cpp index 9f2924ac2945c..862dbb2794291 100644 --- a/lib/AST/Pattern.cpp +++ b/lib/AST/Pattern.cpp @@ -516,8 +516,10 @@ PatternBindingDecl *ContextualPattern::getPatternBindingDecl() const { } bool ContextualPattern::allowsInference() const { - if (auto pbd = getPatternBindingDecl()) - return pbd->isInitialized(index); + if (auto pbd = getPatternBindingDecl()) { + return pbd->isInitialized(index) || + pbd->isDefaultInitializableViaPropertyWrapper(index); + } return true; } diff --git a/lib/AST/TypeCheckRequests.cpp b/lib/AST/TypeCheckRequests.cpp index 3f61c9970df9a..55f37aa115ebf 100644 --- a/lib/AST/TypeCheckRequests.cpp +++ b/lib/AST/TypeCheckRequests.cpp @@ -863,14 +863,14 @@ bool EnumRawValuesRequest::isCached() const { return std::get<1>(getStorage()) == TypeResolutionStage::Interface; } -Optional EnumRawValuesRequest::getCachedResult() const { +Optional EnumRawValuesRequest::getCachedResult() const { auto *ED = std::get<0>(getStorage()); if (ED->LazySemanticInfo.hasCheckedRawValues()) - return true; + return std::make_tuple<>(); return None; } -void EnumRawValuesRequest::cacheResult(bool) const { +void EnumRawValuesRequest::cacheResult(evaluator::SideEffect) const { auto *ED = std::get<0>(getStorage()); auto flags = ED->LazySemanticInfo.RawTypeAndFlags.getInt() | EnumDecl::HasFixedRawValues | @@ -1264,19 +1264,35 @@ void DifferentiableAttributeTypeCheckRequest::cacheResult( attr->ParameterIndicesAndBit.setPointerAndInt(parameterIndices, true); } +//----------------------------------------------------------------------------// +// CheckRedeclarationRequest computation. +//----------------------------------------------------------------------------// + +Optional +CheckRedeclarationRequest::getCachedResult() const { + if (!std::get<0>(getStorage())->alreadyCheckedRedeclaration()) + return None; + return std::make_tuple<>(); +} + +void CheckRedeclarationRequest::cacheResult(evaluator::SideEffect) const { + std::get<0>(getStorage())->setCheckedRedeclaration(); +} + //----------------------------------------------------------------------------// // TypeCheckSourceFileRequest computation. //----------------------------------------------------------------------------// -Optional TypeCheckSourceFileRequest::getCachedResult() const { +Optional +TypeCheckSourceFileRequest::getCachedResult() const { auto *SF = std::get<0>(getStorage()); if (SF->ASTStage == SourceFile::TypeChecked) - return true; + return std::make_tuple<>(); return None; } -void TypeCheckSourceFileRequest::cacheResult(bool result) const { +void TypeCheckSourceFileRequest::cacheResult(evaluator::SideEffect) const { auto *SF = std::get<0>(getStorage()); // Verify that we've checked types correctly. diff --git a/lib/AST/USRGeneration.cpp b/lib/AST/USRGeneration.cpp index a19fca6cf5b11..80bdfe3722859 100644 --- a/lib/AST/USRGeneration.cpp +++ b/lib/AST/USRGeneration.cpp @@ -166,7 +166,7 @@ static bool shouldUseObjCUSR(const Decl *D) { return false; } -llvm::Expected +std::string swift::USRGenerationRequest::evaluate(Evaluator &evaluator, const ValueDecl *D) const { if (auto *VD = dyn_cast(D)) @@ -254,7 +254,7 @@ swift::USRGenerationRequest::evaluate(Evaluator &evaluator, return NewMangler.mangleDeclAsUSR(D, getUSRSpacePrefix()); } -llvm::Expected +std::string swift::MangleLocalTypeDeclRequest::evaluate(Evaluator &evaluator, const TypeDecl *D) const { if (isa(D)) diff --git a/lib/AST/UnqualifiedLookup.cpp b/lib/AST/UnqualifiedLookup.cpp index 773d5e493bcce..2f17010821790 100644 --- a/lib/AST/UnqualifiedLookup.cpp +++ b/lib/AST/UnqualifiedLookup.cpp @@ -1274,7 +1274,7 @@ bool ASTScopeDeclConsumerForUnqualifiedLookup::lookInMembers( return factory.isFirstResultEnough(); } -llvm::Expected +LookupResult UnqualifiedLookupRequest::evaluate(Evaluator &evaluator, UnqualifiedLookupDescriptor desc) const { SmallVector results; diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp index 42dc1b29685a3..979c58b530732 100644 --- a/lib/Demangling/Demangler.cpp +++ b/lib/Demangling/Demangler.cpp @@ -1773,6 +1773,11 @@ NodePointer Demangler::demangleImplFunctionType() { if (nextIf('e')) type->addChild(createNode(Node::Kind::ImplEscaping), *this); + if (nextIf('d')) + type->addChild(createNode(Node::Kind::ImplDifferentiable), *this); + if (nextIf('l')) + type->addChild(createNode(Node::Kind::ImplLinear), *this); + const char *CAttr = nullptr; switch (nextChar()) { case 'y': CAttr = "@callee_unowned"; break; @@ -2791,6 +2796,14 @@ NodePointer Demangler::demangleSpecialType() { return popFunctionType(Node::Kind::ObjCBlock); case 'C': return popFunctionType(Node::Kind::CFunctionPointer); + case 'F': + return popFunctionType(Node::Kind::DifferentiableFunctionType); + case 'G': + return popFunctionType(Node::Kind::EscapingDifferentiableFunctionType); + case 'H': + return popFunctionType(Node::Kind::LinearFunctionType); + case 'I': + return popFunctionType(Node::Kind::EscapingLinearFunctionType); case 'o': return createType(createWithChild(Node::Kind::Unowned, popNode(Node::Kind::Type))); diff --git a/lib/Demangling/NodePrinter.cpp b/lib/Demangling/NodePrinter.cpp index 81ea9f6ec13f9..53b015b8bfebe 100644 --- a/lib/Demangling/NodePrinter.cpp +++ b/lib/Demangling/NodePrinter.cpp @@ -351,6 +351,10 @@ class NodePrinter { case Node::Kind::DependentPseudogenericSignature: case Node::Kind::Destructor: case Node::Kind::DidSet: + case Node::Kind::DifferentiableFunctionType: + case Node::Kind::EscapingDifferentiableFunctionType: + case Node::Kind::LinearFunctionType: + case Node::Kind::EscapingLinearFunctionType: case Node::Kind::DirectMethodReferenceAttribute: case Node::Kind::Directness: case Node::Kind::DynamicAttribute: @@ -386,6 +390,8 @@ class NodePrinter { case Node::Kind::Index: case Node::Kind::IVarInitializer: case Node::Kind::IVarDestroyer: + case Node::Kind::ImplDifferentiable: + case Node::Kind::ImplLinear: case Node::Kind::ImplEscaping: case Node::Kind::ImplConvention: case Node::Kind::ImplFunctionAttribute: @@ -1234,6 +1240,22 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) { Printer << "@convention(thin) "; printFunctionType(nullptr, Node); return nullptr; + case Node::Kind::DifferentiableFunctionType: + Printer << "@differentiable "; + printFunctionType(nullptr, Node); + return nullptr; + case Node::Kind::EscapingDifferentiableFunctionType: + Printer << "@escaping @differentiable "; + printFunctionType(nullptr, Node); + return nullptr; + case Node::Kind::LinearFunctionType: + Printer << "@differentiable(linear) "; + printFunctionType(nullptr, Node); + return nullptr; + case Node::Kind::EscapingLinearFunctionType: + Printer << "@escaping @differentiable(linear) "; + printFunctionType(nullptr, Node); + return nullptr; case Node::Kind::FunctionType: case Node::Kind::UncurriedFunctionType: printFunctionType(nullptr, Node); @@ -2026,6 +2048,12 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) { return nullptr; case Node::Kind::LabelList: return nullptr; + case Node::Kind::ImplDifferentiable: + Printer << "@differentiable"; + return nullptr; + case Node::Kind::ImplLinear: + Printer << "@differentiable(linear)"; + return nullptr; case Node::Kind::ImplEscaping: Printer << "@escaping"; return nullptr; @@ -2527,6 +2555,14 @@ void NodePrinter::printEntityType(NodePointer Entity, NodePointer type, Printer << ' '; type = dependentType->getFirstChild(); } + if (type->getKind() == Node::Kind::DifferentiableFunctionType) + Printer << "@differentiable "; + else if (type->getKind() == Node::Kind::EscapingDifferentiableFunctionType) + Printer << "@escaping @differentiable "; + else if (type->getKind() == Node::Kind::LinearFunctionType) + Printer << "@differentiable(linear) "; + else if (type->getKind() == Node::Kind::EscapingLinearFunctionType) + Printer << "@escaping @differentiable(linear) "; printFunctionType(labelList, type); } else { print(type); diff --git a/lib/Demangling/OldRemangler.cpp b/lib/Demangling/OldRemangler.cpp index d79102b60c56d..4da4cb52a509b 100644 --- a/lib/Demangling/OldRemangler.cpp +++ b/lib/Demangling/OldRemangler.cpp @@ -1168,6 +1168,26 @@ void Remangler::mangleThinFunctionType(Node *node) { mangleChildNodes(node); // argument tuple, result type } +void Remangler::mangleDifferentiableFunctionType(Node *node) { + Buffer << "XF"; + mangleChildNodes(node); // argument tuple, result type +} + +void Remangler::mangleEscapingDifferentiableFunctionType(Node *node) { + Buffer << "XG"; + mangleChildNodes(node); // argument tuple, result type +} + +void Remangler::mangleLinearFunctionType(Node *node) { + Buffer << "XH"; + mangleChildNodes(node); // argument tuple, result type +} + +void Remangler::mangleEscapingLinearFunctionType(Node *node) { + Buffer << "XI"; + mangleChildNodes(node); // argument tuple, result type +} + void Remangler::mangleArgumentTuple(Node *node) { mangleSingleChildNode(node); } @@ -1258,6 +1278,16 @@ void Remangler::mangleImplYield(Node *node) { mangleChildNodes(node); // impl convention, type } +void Remangler::mangleImplDifferentiable(Node *node) { + // TODO(TF-750): Check if this code path actually triggers and add a test. + Buffer << 'd'; +} + +void Remangler::mangleImplLinear(Node *node) { + // TODO(TF-750): Check if this code path actually triggers and add a test. + Buffer << 'l'; +} + void Remangler::mangleImplEscaping(Node *node) { // The old mangler does not encode escaping. } diff --git a/lib/Demangling/Remangler.cpp b/lib/Demangling/Remangler.cpp index cb9b6e97e27e2..17e8078746e62 100644 --- a/lib/Demangling/Remangler.cpp +++ b/lib/Demangling/Remangler.cpp @@ -1221,6 +1221,26 @@ void Remangler::mangleFunctionType(Node *node) { Buffer << 'c'; } +void Remangler::mangleDifferentiableFunctionType(Node *node) { + mangleFunctionSignature(node); + Buffer << "XF"; +} + +void Remangler::mangleEscapingDifferentiableFunctionType(Node *node) { + mangleFunctionSignature(node); + Buffer << "XG"; +} + +void Remangler::mangleLinearFunctionType(Node *node) { + mangleFunctionSignature(node); + Buffer << "XH"; +} + +void Remangler::mangleEscapingLinearFunctionType(Node *node) { + mangleFunctionSignature(node); + Buffer << "XI"; +} + void Remangler::mangleGenericProtocolWitnessTable(Node *node) { mangleSingleChildNode(node); Buffer << "WG"; @@ -1378,6 +1398,14 @@ void Remangler::mangleIVarDestroyer(Node *node) { Buffer << "fE"; } +void Remangler::mangleImplDifferentiable(Node *node) { + Buffer << 'd'; +} + +void Remangler::mangleImplLinear(Node *node) { + Buffer << 'l'; +} + void Remangler::mangleImplEscaping(Node *node) { Buffer << 'e'; } @@ -1459,6 +1487,12 @@ void Remangler::mangleImplFunctionType(Node *node) { Buffer << PseudoGeneric; for (NodePointer Child : *node) { switch (Child->getKind()) { + case Node::Kind::ImplDifferentiable: + Buffer << 'd'; + break; + case Node::Kind::ImplLinear: + Buffer << 'l'; + break; case Node::Kind::ImplEscaping: Buffer << 'e'; break; diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index a534da97a23b7..10c381f450d5a 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -249,6 +249,7 @@ static void addCommonFrontendArgs(const ToolChain &TC, const OutputInfo &OI, inputArgs.AddLastArg(arguments, options::OPT_package_description_version); inputArgs.AddLastArg(arguments, options::OPT_serialize_diagnostics_path); inputArgs.AddLastArg(arguments, options::OPT_debug_diagnostic_names); + inputArgs.AddLastArg(arguments, options::OPT_print_educational_notes); inputArgs.AddLastArg(arguments, options::OPT_enable_astscope_lookup); inputArgs.AddLastArg(arguments, options::OPT_disable_astscope_lookup); inputArgs.AddLastArg(arguments, options::OPT_disable_parser_lookup); diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 3054aa2ef4a4a..fdf38e0d9124c 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -821,7 +821,7 @@ static bool ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, Opts.SuppressWarnings |= Args.hasArg(OPT_suppress_warnings); Opts.WarningsAsErrors |= Args.hasArg(OPT_warnings_as_errors); Opts.PrintDiagnosticNames |= Args.hasArg(OPT_debug_diagnostic_names); - Opts.EnableEducationalNotes |= Args.hasArg(OPT_enable_educational_notes); + Opts.PrintEducationalNotes |= Args.hasArg(OPT_print_educational_notes); Opts.EnableExperimentalFormatting |= Args.hasArg(OPT_enable_experimental_diagnostic_formatting); if (Arg *A = Args.getLastArg(OPT_diagnostic_documentation_path)) { diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index 6785e2cb15d1f..aef9c0df47803 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -410,9 +410,6 @@ void CompilerInstance::setUpDiagnosticOptions() { if (Invocation.getDiagnosticOptions().PrintDiagnosticNames) { Diagnostics.setPrintDiagnosticNames(true); } - if (Invocation.getDiagnosticOptions().EnableEducationalNotes) { - Diagnostics.setUseEducationalNotes(true); - } Diagnostics.setDiagnosticDocumentationPath( Invocation.getDiagnosticOptions().DiagnosticDocumentationPath); } diff --git a/lib/Frontend/PrintingDiagnosticConsumer.cpp b/lib/Frontend/PrintingDiagnosticConsumer.cpp index 9257a0910db65..04d5f703c012f 100644 --- a/lib/Frontend/PrintingDiagnosticConsumer.cpp +++ b/lib/Frontend/PrintingDiagnosticConsumer.cpp @@ -898,17 +898,21 @@ void PrintingDiagnosticConsumer::handleDiagnostic(SourceManager &SM, currentSnippet = std::make_unique(SM); annotateSnippetWithInfo(SM, Info, *currentSnippet); } - for (auto path : Info.EducationalNotePaths) { - if (auto buffer = SM.getFileSystem()->getBufferForFile(path)) - BufferedEducationalNotes.push_back(buffer->get()->getBuffer().str()); + if (PrintEducationalNotes) { + for (auto path : Info.EducationalNotePaths) { + if (auto buffer = SM.getFileSystem()->getBufferForFile(path)) + BufferedEducationalNotes.push_back(buffer->get()->getBuffer().str()); + } } } else { printDiagnostic(SM, Info); - for (auto path : Info.EducationalNotePaths) { - if (auto buffer = SM.getFileSystem()->getBufferForFile(path)) { - printMarkdown(buffer->get()->getBuffer(), Stream, ForceColors); - Stream << "\n"; + if (PrintEducationalNotes) { + for (auto path : Info.EducationalNotePaths) { + if (auto buffer = SM.getFileSystem()->getBufferForFile(path)) { + printMarkdown(buffer->get()->getBuffer(), Stream, ForceColors); + Stream << "\n"; + } } } diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index 7256ea1dc43a5..ab3139a7d4f02 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -655,10 +655,14 @@ static void countStatsOfSourceFile(UnifiedStatsReporter &Stats, C.NumDecls += SF->getTopLevelDecls().size(); C.NumLocalTypeDecls += SF->LocalTypeDecls.size(); C.NumObjCMethods += SF->ObjCMethods.size(); - C.NumInfixOperators += SF->InfixOperators.size(); - C.NumPostfixOperators += SF->PostfixOperators.size(); - C.NumPrefixOperators += SF->PrefixOperators.size(); - C.NumPrecedenceGroups += SF->PrecedenceGroups.size(); + + SmallVector operators; + SF->getOperatorDecls(operators); + C.NumOperators += operators.size(); + + SmallVector groups; + SF->getPrecedenceGroups(groups); + C.NumPrecedenceGroups += groups.size(); auto bufID = SF->getBufferID(); if (bufID.hasValue()) { @@ -2146,6 +2150,9 @@ int swift::performFrontend(ArrayRef Args, if (Invocation.getDiagnosticOptions().UseColor) PDC.forceColors(); + PDC.setPrintEducationalNotes( + Invocation.getDiagnosticOptions().PrintEducationalNotes); + // Temporarily stage the new diagnostic formatting style behind // -enable-descriptive-diagnostics if (Invocation.getDiagnosticOptions().EnableExperimentalFormatting) diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index c494f8745aaf6..5a9b36fc86a6c 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -3421,56 +3421,10 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { IncludeInstanceMembers); } - template - void collectOperatorsFromMap(SourceFile::OperatorMap &map, - bool includePrivate, - std::vector &results) { - for (auto &pair : map) { - if (pair.second.getPointer() && - (pair.second.getInt() || includePrivate)) { - results.push_back(pair.second.getPointer()); - } - } - } - - void collectOperatorsFrom(SourceFile *SF, - std::vector &results) { - bool includePrivate = CurrDeclContext->getParentSourceFile() == SF; - collectOperatorsFromMap(SF->PrefixOperators, includePrivate, results); - collectOperatorsFromMap(SF->PostfixOperators, includePrivate, results); - collectOperatorsFromMap(SF->InfixOperators, includePrivate, results); - } - - void collectOperatorsFrom(LoadedFile *F, - std::vector &results) { - SmallVector topLevelDecls; - F->getTopLevelDecls(topLevelDecls); - for (auto D : topLevelDecls) { - if (auto op = dyn_cast(D)) - results.push_back(op); - } - } - - std::vector collectOperators() { - std::vector results; + void collectOperators(SmallVectorImpl &results) { assert(CurrDeclContext); - for (auto import : namelookup::getAllImports(CurrDeclContext)) { - for (auto fileUnit : import.second->getFiles()) { - switch (fileUnit->getKind()) { - case FileUnitKind::Builtin: - case FileUnitKind::ClangModule: - case FileUnitKind::DWARFModule: - continue; - case FileUnitKind::Source: - collectOperatorsFrom(cast(fileUnit), results); - break; - case FileUnitKind::SerializedAST: - collectOperatorsFrom(cast(fileUnit), results); - break; - } - } - } - return results; + for (auto import : namelookup::getAllImports(CurrDeclContext)) + import.second->getOperatorDecls(results); } void addPostfixBang(Type resultType) { @@ -3618,7 +3572,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { Expr *foldedExpr = typeCheckLeadingSequence(LHS, leadingSequence); - std::vector operators = collectOperators(); + SmallVector operators; + collectOperators(operators); // FIXME: this always chooses the first operator with the given name. llvm::DenseSet seenPostfixOperators; llvm::DenseSet seenInfixOperators; diff --git a/lib/IDE/IDERequests.cpp b/lib/IDE/IDERequests.cpp index 339d6398ae571..024723eb990a4 100644 --- a/lib/IDE/IDERequests.cpp +++ b/lib/IDE/IDERequests.cpp @@ -303,7 +303,7 @@ bool CursorInfoResolver::rangeContainsLoc(CharSourceRange Range) const { return Range.contains(LocToResolve); } -llvm::Expected +ide::ResolvedCursorInfo CursorInfoRequest::evaluate(Evaluator &eval, CursorInfoOwner CI) const { if (!CI.isValid()) return ResolvedCursorInfo(); @@ -1066,7 +1066,7 @@ RangeInfoOwner::RangeInfoOwner(SourceFile *File, unsigned Offset, EndLoc = SM.getLocForOffset(BufferId, Offset + Length); } -llvm::Expected +ide::ResolvedRangeInfo RangeInfoRequest::evaluate(Evaluator &eval, RangeInfoOwner CI) const { if (!CI.isValid()) return ResolvedRangeInfo(); @@ -1092,7 +1092,7 @@ static Type getContextFreeInterfaceType(ValueDecl *VD) { return VD->getInterfaceType(); } -llvm::Expected> +ArrayRef ProvideDefaultImplForRequest::evaluate(Evaluator &eval, ValueDecl* VD) const { // Skip decls that don't have valid names. if (!VD->getFullName()) @@ -1126,7 +1126,7 @@ ProvideDefaultImplForRequest::evaluate(Evaluator &eval, ValueDecl* VD) const { //----------------------------------------------------------------------------// // CollectOverriddenDeclsRequest //----------------------------------------------------------------------------// -llvm::Expected> +ArrayRef CollectOverriddenDeclsRequest::evaluate(Evaluator &evaluator, OverridenDeclsOwner Owner) const { std::vector results; @@ -1155,7 +1155,7 @@ CollectOverriddenDeclsRequest::evaluate(Evaluator &evaluator, //----------------------------------------------------------------------------// // ResolveProtocolNameRequest //----------------------------------------------------------------------------// -llvm::Expected +ProtocolDecl * ResolveProtocolNameRequest::evaluate(Evaluator &evaluator, ProtocolNameOwner Input) const { auto &ctx = Input.DC->getASTContext(); diff --git a/lib/IRGen/GenClass.cpp b/lib/IRGen/GenClass.cpp index 6c39e4b72c701..dcbaa6dfec5d0 100644 --- a/lib/IRGen/GenClass.cpp +++ b/lib/IRGen/GenClass.cpp @@ -1520,33 +1520,27 @@ namespace { } void buildMethod(ConstantArrayBuilder &descriptors, - MethodDescriptor descriptor, - llvm::StringSet<> &uniqueSelectors) { + MethodDescriptor descriptor) { switch (descriptor.getKind()) { case MethodDescriptor::Kind::Method: - return buildMethod(descriptors, descriptor.getMethod(), - uniqueSelectors); + return buildMethod(descriptors, descriptor.getMethod()); case MethodDescriptor::Kind::IVarInitializer: emitObjCIVarInitDestroyDescriptor(IGM, descriptors, getClass(), - descriptor.getImpl(), false, - uniqueSelectors); + descriptor.getImpl(), false); return; case MethodDescriptor::Kind::IVarDestroyer: emitObjCIVarInitDestroyDescriptor(IGM, descriptors, getClass(), - descriptor.getImpl(), true, - uniqueSelectors); + descriptor.getImpl(), true); return; } llvm_unreachable("bad method descriptor kind"); } void buildMethod(ConstantArrayBuilder &descriptors, - AbstractFunctionDecl *method, - llvm::StringSet<> &uniqueSelectors) { + AbstractFunctionDecl *method) { auto accessor = dyn_cast(method); if (!accessor) - return emitObjCMethodDescriptor(IGM, descriptors, method, - uniqueSelectors); + return emitObjCMethodDescriptor(IGM, descriptors, method); switch (accessor->getAccessorKind()) { case AccessorKind::Get: @@ -1615,9 +1609,7 @@ namespace { namePrefix = "_PROTOCOL_INSTANCE_METHODS_OPT_"; break; } - llvm::StringSet<> uniqueSelectors; - llvm::Constant *methodListPtr = - buildMethodList(methods, namePrefix, uniqueSelectors); + llvm::Constant *methodListPtr = buildMethodList(methods, namePrefix); builder.add(methodListPtr); } @@ -1643,15 +1635,12 @@ namespace { void buildExtMethodTypes(ConstantArrayBuilder &array, ArrayRef methods) { assert(isBuildingProtocol()); - llvm::StringSet<> uniqueSelectors; + for (auto descriptor : methods) { assert(descriptor.getKind() == MethodDescriptor::Kind::Method && "cannot emit descriptor for non-method"); auto method = descriptor.getMethod(); - auto *encodingOrNullIfDuplicate = - getMethodTypeExtendedEncoding(IGM, method, uniqueSelectors); - if (encodingOrNullIfDuplicate != nullptr) - array.add(encodingOrNullIfDuplicate); + array.add(getMethodTypeExtendedEncoding(IGM, method)); } } @@ -1663,12 +1652,11 @@ namespace { /// /// This method does not return a value of a predictable type. llvm::Constant *buildMethodList(ArrayRef methods, - StringRef name, - llvm::StringSet<> &uniqueSelectors) { + StringRef name) { return buildOptionalList(methods, 3 * IGM.getPointerSize(), name, [&](ConstantArrayBuilder &descriptors, MethodDescriptor descriptor) { - buildMethod(descriptors, descriptor, uniqueSelectors); + buildMethod(descriptors, descriptor); }); } diff --git a/lib/IRGen/GenObjC.cpp b/lib/IRGen/GenObjC.cpp index 0041e3ef3e68c..9da425db298ff 100644 --- a/lib/IRGen/GenObjC.cpp +++ b/lib/IRGen/GenObjC.cpp @@ -1100,41 +1100,9 @@ static llvm::Constant *getObjCEncodingForTypes(IRGenModule &IGM, return IGM.getAddrOfGlobalString(encodingString); } -static llvm::Constant * -getObjectEncodingFromClangNode(IRGenModule &IGM, Decl *d, - bool useExtendedEncoding) { - // Use the clang node's encoding if there is a clang node. - if (d->getClangNode()) { - auto clangDecl = d->getClangNode().castAsDecl(); - auto &clangASTContext = IGM.getClangASTContext(); - std::string typeStr; - if (auto objcMethodDecl = dyn_cast(clangDecl)) { - typeStr = clangASTContext.getObjCEncodingForMethodDecl( - objcMethodDecl, useExtendedEncoding /*extended*/); - } - if (auto objcPropertyDecl = dyn_cast(clangDecl)) { - typeStr = clangASTContext.getObjCEncodingForPropertyDecl(objcPropertyDecl, - nullptr); - } - if (!typeStr.empty()) { - return IGM.getAddrOfGlobalString(typeStr.c_str()); - } - } - return nullptr; -} - -static llvm::Constant *getObjCEncodingForMethod(IRGenModule &IGM, - CanSILFunctionType fnType, - bool useExtendedEncoding, - Decl *optionalDecl) { - // Use the decl's ClangNode to get the encoding if possible. - if (optionalDecl) { - if (auto *enc = getObjectEncodingFromClangNode(IGM, optionalDecl, - useExtendedEncoding)) { - return enc; - } - } - +static llvm::Constant *getObjCEncodingForMethodType(IRGenModule &IGM, + CanSILFunctionType fnType, + bool useExtendedEncoding) { // Get the inputs without 'self'. auto inputs = fnType->getParameters().drop_back(); @@ -1160,13 +1128,11 @@ irgen::emitObjCMethodDescriptorParts(IRGenModule &IGM, /// The first element is the selector. descriptor.selectorRef = IGM.getAddrOfObjCMethodName(selector.str()); - /// The second element is the method signature. A method signature is made - /// of the return type @encoding and every parameter type @encoding, glued - /// with numbers that used to represent stack offsets for each of these - /// elements. + /// The second element is the method signature. A method signature is made of + /// the return type @encoding and every parameter type @encoding, glued with + /// numbers that used to represent stack offsets for each of these elements. CanSILFunctionType methodType = getObjCMethodType(IGM, method); - descriptor.typeEncoding = - getObjCEncodingForMethod(IGM, methodType, /*extended*/ false, method); + descriptor.typeEncoding = getObjCEncodingForMethodType(IGM, methodType, /*extended*/false); /// The third element is the method implementation pointer. if (!concrete) { @@ -1225,13 +1191,10 @@ irgen::emitObjCGetterDescriptorParts(IRGenModule &IGM, Selector getterSel(subscript, Selector::ForGetter); ObjCMethodDescriptor descriptor{}; descriptor.selectorRef = IGM.getAddrOfObjCMethodName(getterSel.str()); - - auto methodTy = - getObjCMethodType(IGM, subscript->getOpaqueAccessor(AccessorKind::Get)); - descriptor.typeEncoding = - getObjCEncodingForMethod(IGM, methodTy, - /*extended*/ false, subscript); - + auto methodTy = getObjCMethodType(IGM, + subscript->getOpaqueAccessor(AccessorKind::Get)); + descriptor.typeEncoding = getObjCEncodingForMethodType(IGM, methodTy, + /*extended*/false); descriptor.silFunction = nullptr; descriptor.impl = getObjCGetterPointer(IGM, subscript, descriptor.silFunction); @@ -1303,9 +1266,8 @@ irgen::emitObjCSetterDescriptorParts(IRGenModule &IGM, descriptor.selectorRef = IGM.getAddrOfObjCMethodName(setterSel.str()); auto methodTy = getObjCMethodType(IGM, subscript->getOpaqueAccessor(AccessorKind::Set)); - descriptor.typeEncoding = - getObjCEncodingForMethod(IGM, methodTy, - /*extended*/ false, subscript); + descriptor.typeEncoding = getObjCEncodingForMethodType(IGM, methodTy, + /*extended*/false); descriptor.silFunction = nullptr; descriptor.impl = getObjCSetterPointer(IGM, subscript, descriptor.silFunction); @@ -1361,33 +1323,23 @@ static void emitObjCDescriptor(IRGenModule &IGM, /// }; void irgen::emitObjCMethodDescriptor(IRGenModule &IGM, ConstantArrayBuilder &descriptors, - AbstractFunctionDecl *method, - llvm::StringSet<> &uniqueSelectors) { - // Don't emit a selector twice. - Selector selector(method); - if (!uniqueSelectors.insert(selector.str()).second) - return; - + AbstractFunctionDecl *method) { ObjCMethodDescriptor descriptor( emitObjCMethodDescriptorParts(IGM, method, /*concrete*/ true)); emitObjCDescriptor(IGM, descriptors, descriptor); } -void irgen::emitObjCIVarInitDestroyDescriptor( - IRGenModule &IGM, ConstantArrayBuilder &descriptors, ClassDecl *cd, - llvm::Function *objcImpl, bool isDestroyer, - llvm::StringSet<> &uniqueSelectors) { +void irgen::emitObjCIVarInitDestroyDescriptor(IRGenModule &IGM, + ConstantArrayBuilder &descriptors, + ClassDecl *cd, + llvm::Function *objcImpl, + bool isDestroyer) { /// The first element is the selector. SILDeclRef declRef = SILDeclRef(cd, isDestroyer? SILDeclRef::Kind::IVarDestroyer : SILDeclRef::Kind::IVarInitializer, /*foreign*/ true); Selector selector(declRef); - - // Don't emit a selector twice. - if (!uniqueSelectors.insert(selector.str()).second) - return; - ObjCMethodDescriptor descriptor{}; descriptor.selectorRef = IGM.getAddrOfObjCMethodName(selector.str()); @@ -1406,18 +1358,11 @@ void irgen::emitObjCIVarInitDestroyDescriptor( buildMethodDescriptor(IGM, descriptors, descriptor); } - llvm::Constant * irgen::getMethodTypeExtendedEncoding(IRGenModule &IGM, - AbstractFunctionDecl *method, - llvm::StringSet<> &uniqueSelectors) { - // Don't emit a selector twice. - Selector selector(method); - if (!uniqueSelectors.insert(selector.str()).second) - return nullptr; - + AbstractFunctionDecl *method) { CanSILFunctionType methodType = getObjCMethodType(IGM, method); - return getObjCEncodingForMethod(IGM, methodType, true /*Extended*/, method); + return getObjCEncodingForMethodType(IGM, methodType, true/*Extended*/); } llvm::Constant * diff --git a/lib/IRGen/GenObjC.h b/lib/IRGen/GenObjC.h index 33d582d59eee5..64ec654afc3b2 100644 --- a/lib/IRGen/GenObjC.h +++ b/lib/IRGen/GenObjC.h @@ -155,8 +155,7 @@ namespace irgen { /// constructor, or destructor implementation. void emitObjCMethodDescriptor(IRGenModule &IGM, ConstantArrayBuilder &descriptors, - AbstractFunctionDecl *method, - llvm::StringSet<> &uniqueSelectors); + AbstractFunctionDecl *method); /// Build an Objective-C method descriptor for the ivar initializer /// or destroyer of a class (-.cxx_construct or -.cxx_destruct). @@ -164,8 +163,7 @@ namespace irgen { ConstantArrayBuilder &descriptors, ClassDecl *cd, llvm::Function *impl, - bool isDestroyer, - llvm::StringSet<> &uniqueSelectors); + bool isDestroyer); /// Get the type encoding for an ObjC property. void getObjCEncodingForPropertyType(IRGenModule &IGM, VarDecl *property, @@ -177,12 +175,10 @@ namespace irgen { CanSILFunctionType invokeTy); /// Produces extended encoding of method type. - /// \returns the encoded type or null if it is a duplicate (exists in - /// \p uniqueSelectors). - llvm::Constant * - getMethodTypeExtendedEncoding(IRGenModule &IGM, AbstractFunctionDecl *method, - llvm::StringSet<> &uniqueSelectors); - + /// \returns the encoded type. + llvm::Constant *getMethodTypeExtendedEncoding(IRGenModule &IGM, + AbstractFunctionDecl *method); + /// Build an Objective-C method descriptor for the given getter method. void emitObjCGetterDescriptor(IRGenModule &IGM, ConstantArrayBuilder &descriptors, diff --git a/lib/IRGen/IRGen.cpp b/lib/IRGen/IRGen.cpp index 1d81024a4da14..27621774850f6 100644 --- a/lib/IRGen/IRGen.cpp +++ b/lib/IRGen/IRGen.cpp @@ -1373,7 +1373,7 @@ std::unique_ptr swift::performIRGeneration( M->getASTContext().evaluator(IRGenWholeModuleRequest{desc})); } -llvm::Expected> +std::unique_ptr IRGenWholeModuleRequest::evaluate(Evaluator &evaluator, IRGenDescriptor desc) const { auto *M = desc.Ctx.get(); @@ -1408,7 +1408,7 @@ performIRGeneration(const IRGenOptions &Opts, SourceFile &SF, SF.getASTContext().evaluator(IRGenSourceFileRequest{desc})); } -llvm::Expected> +std::unique_ptr IRGenSourceFileRequest::evaluate(Evaluator &evaluator, IRGenDescriptor desc) const { auto *SF = desc.Ctx.get(); diff --git a/lib/IRGen/MetadataRequest.cpp b/lib/IRGen/MetadataRequest.cpp index 4a54601b263d8..2a1bbb7183bb3 100644 --- a/lib/IRGen/MetadataRequest.cpp +++ b/lib/IRGen/MetadataRequest.cpp @@ -1231,12 +1231,30 @@ namespace { break; } + FunctionMetadataDifferentiabilityKind metadataDifferentiabilityKind; + switch (type->getDifferentiabilityKind()) { + case DifferentiabilityKind::NonDifferentiable: + metadataDifferentiabilityKind = + FunctionMetadataDifferentiabilityKind::NonDifferentiable; + break; + case DifferentiabilityKind::Normal: + metadataDifferentiabilityKind = + FunctionMetadataDifferentiabilityKind::Normal; + break; + case DifferentiabilityKind::Linear: + metadataDifferentiabilityKind = + FunctionMetadataDifferentiabilityKind::Linear; + break; + } + auto flagsVal = FunctionTypeFlags() .withNumParameters(numParams) .withConvention(metadataConvention) .withThrows(type->throws()) .withParameterFlags(hasFlags) - .withEscaping(isEscaping); + .withEscaping(isEscaping) + .withDifferentiabilityKind( + metadataDifferentiabilityKind); auto flags = llvm::ConstantInt::get(IGF.IGM.SizeTy, flagsVal.getIntValue()); diff --git a/lib/Index/IndexRecord.cpp b/lib/Index/IndexRecord.cpp index d85633e236c4c..9d4856801b517 100644 --- a/lib/Index/IndexRecord.cpp +++ b/lib/Index/IndexRecord.cpp @@ -425,13 +425,13 @@ static void addModuleDependencies(ArrayRef imports, case FileUnitKind::ClangModule: { auto *LFU = cast(FU); if (auto F = fileMgr.getFile(LFU->getFilename())) { - std::string moduleName = mod->getNameStr().str(); + StringRef moduleName = mod->getNameStr(); bool withoutUnitName = true; if (FU->getKind() == FileUnitKind::ClangModule) { withoutUnitName = false; auto clangModUnit = cast(LFU); if (auto clangMod = clangModUnit->getUnderlyingClangModule()) { - moduleName = clangMod->getTopLevelModuleName().str(); + moduleName = clangMod->getTopLevelModuleName(); // FIXME: clang's -Rremarks do not seem to go through Swift's // diagnostic emitter. clang::index::emitIndexDataForModuleFile(clangMod, @@ -482,7 +482,7 @@ emitDataForSwiftSerializedModule(ModuleDecl *module, StringRef filename = module->getModuleFilename(); // If this is a cross-import overlay, make sure we use the name of the // underlying module instead. - std::string moduleName = getUnderlyingModuleName(module, initialFile); + std::string moduleName = getUnderlyingModuleName(module, initialFile).str(); std::string error; auto isUptodateOpt = parentUnitWriter.isUnitUpToDateForOutputFile(/*FilePath=*/filename, diff --git a/lib/SIL/SILFunctionBuilder.cpp b/lib/SIL/SILFunctionBuilder.cpp index 903655b58bca3..e30dde44ec358 100644 --- a/lib/SIL/SILFunctionBuilder.cpp +++ b/lib/SIL/SILFunctionBuilder.cpp @@ -66,6 +66,25 @@ void SILFunctionBuilder::addFunctionAttributes( if (Attrs.hasAttribute() || Attrs.hasAttribute()) F->setHasCReferences(true); + // Validate `@differentiable` attributes by calling `getParameterIndices`. + // This is important for: + // - Skipping invalid `@differentiable` attributes in non-primary files. + // - Preventing duplicate SIL differentiability witness creation for + // `@differentiable` attributes on `AbstractStorageDecl` declarations. + // Such `@differentiable` attributes are deleted and recreated on the getter + // `AccessorDecl` of the `AbstractStorageDecl`. + for (auto *A : Attrs.getAttributes()) + (void)A->getParameterIndices(); + + // Propagate `@noDerivative` as `[_semantics "autodiff.nonvarying"]`. + // + // `@noDerivative` implies non-varying semantics for differentiable activity + // analysis. SIL values produced from references to `@noDerivative` + // declarations will not be marked as varying; these values do not need a + // derivative. + if (Attrs.hasAttribute()) + F->addSemanticsAttr("autodiff.nonvarying"); + // Propagate @_dynamicReplacement(for:). if (constant.isNull()) return; diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp index 8d182ab9c77d7..79f4185915ddb 100644 --- a/lib/SILGen/SILGen.cpp +++ b/lib/SILGen/SILGen.cpp @@ -1850,7 +1850,7 @@ class SILGenModuleRAII { }; } // end anonymous namespace -llvm::Expected> +std::unique_ptr SILGenSourceFileRequest::evaluate(Evaluator &evaluator, SILGenDescriptor desc) const { auto *unit = desc.context.get(); @@ -1866,10 +1866,10 @@ SILGenSourceFileRequest::evaluate(Evaluator &evaluator, M->getSILLoader()->getAllForModule(mod->getName(), file); } - return std::move(M); + return M; } -llvm::Expected> +std::unique_ptr SILGenWholeModuleRequest::evaluate(Evaluator &evaluator, SILGenDescriptor desc) const { auto *mod = desc.context.get(); @@ -1894,7 +1894,7 @@ SILGenWholeModuleRequest::evaluate(Evaluator &evaluator, if (hasSIB) M->getSILLoader()->getAllForModule(mod->getName(), nullptr); - return std::move(M); + return M; } std::unique_ptr diff --git a/lib/SILOptimizer/PassManager/PassManager.cpp b/lib/SILOptimizer/PassManager/PassManager.cpp index 6c07168e14688..3190e63503527 100644 --- a/lib/SILOptimizer/PassManager/PassManager.cpp +++ b/lib/SILOptimizer/PassManager/PassManager.cpp @@ -276,11 +276,11 @@ class PassManagerDeserializationNotificationHandler final } // end anonymous namespace -llvm::Expected ExecuteSILPipelineRequest::evaluate( +evaluator::SideEffect ExecuteSILPipelineRequest::evaluate( Evaluator &evaluator, SILPipelineExecutionDescriptor desc) const { SILPassManager PM(desc.SM, desc.IsMandatory, desc.IRMod); PM.executePassPipelinePlan(desc.Plan); - return false; + return std::make_tuple<>(); } void swift::executePassPipelinePlan(SILModule *SM, diff --git a/lib/Sema/BuilderTransform.cpp b/lib/Sema/BuilderTransform.cpp index a63c2c697cb7c..15c98974193b4 100644 --- a/lib/Sema/BuilderTransform.cpp +++ b/lib/Sema/BuilderTransform.cpp @@ -1548,7 +1548,7 @@ class PreCheckFunctionBuilderApplication : public ASTWalker { } -llvm::Expected +FunctionBuilderBodyPreCheck PreCheckFunctionBuilderRequest::evaluate(Evaluator &eval, AnyFunctionRef fn) const { return PreCheckFunctionBuilderApplication(fn, false).run(); diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index f7a9958c76c1e..0f7f77608449c 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -19,6 +19,7 @@ add_swift_host_library(swiftSema STATIC DerivedConformanceCaseIterable.cpp DerivedConformanceCodable.cpp DerivedConformanceCodingKey.cpp + DerivedConformanceDifferentiable.cpp DerivedConformanceEquatableHashable.cpp DerivedConformanceComparable.cpp DerivedConformanceError.cpp diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 1546b99a2d84a..8c64fe4e03277 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -2978,8 +2978,8 @@ namespace { // Add a conversion constraint for the direct conversion between // types. - CS.addExplicitConversionConstraint(fromType, toType, - /*allowFixes=*/true, locator); + CS.addExplicitConversionConstraint(fromType, toType, RememberChoice, + locator); // If the result type was declared IUO, add a disjunction for // bindings for the result of the coercion. diff --git a/lib/Sema/CSRanking.cpp b/lib/Sema/CSRanking.cpp index 1100a309608b3..c4874a0676f94 100644 --- a/lib/Sema/CSRanking.cpp +++ b/lib/Sema/CSRanking.cpp @@ -385,7 +385,7 @@ static bool isDeclAsSpecializedAs(DeclContext *dc, ValueDecl *decl1, false); } -llvm::Expected CompareDeclSpecializationRequest::evaluate( +bool CompareDeclSpecializationRequest::evaluate( Evaluator &eval, DeclContext *dc, ValueDecl *decl1, ValueDecl *decl2, bool isDynamicOverloadComparison) const { auto &C = decl1->getASTContext(); diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 1228cd95c04d9..3a08f1d7a93b3 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -7291,13 +7291,13 @@ ConstraintSystem::simplifyBridgingConstraint(Type type1, if (auto fromKeyValue = isDictionaryType(unwrappedFromType)) { if (auto toKeyValue = isDictionaryType(unwrappedToType)) { addExplicitConversionConstraint(fromKeyValue->first, toKeyValue->first, - /*allowFixes=*/false, + ForgetChoice, locator.withPathElement( LocatorPathElt::GenericArgument(0))); addExplicitConversionConstraint(fromKeyValue->second, toKeyValue->second, - /*allowFixes=*/false, + ForgetChoice, locator.withPathElement( - LocatorPathElt::GenericArgument(0))); + LocatorPathElt::GenericArgument(1))); countOptionalInjections(); return SolutionKind::Solved; } @@ -9701,9 +9701,8 @@ void ConstraintSystem::addFixConstraint(ConstraintFix *fix, ConstraintKind kind, } void ConstraintSystem::addExplicitConversionConstraint( - Type fromType, Type toType, - bool allowFixes, - ConstraintLocatorBuilder locator) { + Type fromType, Type toType, RememberChoice_t rememberChoice, + ConstraintLocatorBuilder locator) { SmallVector constraints; auto locatorPtr = getConstraintLocator(locator); @@ -9721,9 +9720,7 @@ void ConstraintSystem::addExplicitConversionConstraint( fromType, toType, locatorPtr); constraints.push_back(bridgingConstraint); - addDisjunctionConstraint(constraints, locator, - allowFixes ? RememberChoice - : ForgetChoice); + addDisjunctionConstraint(constraints, locator, rememberChoice); } ConstraintSystem::SolutionKind diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp index c24ca5c075a63..0ab1dae81bf43 100644 --- a/lib/Sema/CodeSynthesis.cpp +++ b/lib/Sema/CodeSynthesis.cpp @@ -795,7 +795,7 @@ static void diagnoseMissingRequiredInitializer( diag::required_initializer_here); } -llvm::Expected AreAllStoredPropertiesDefaultInitableRequest::evaluate( +bool AreAllStoredPropertiesDefaultInitableRequest::evaluate( Evaluator &evaluator, NominalTypeDecl *decl) const { assert(!decl->hasClangNode()); @@ -849,7 +849,7 @@ static bool areAllStoredPropertiesDefaultInitializable(Evaluator &eval, eval, AreAllStoredPropertiesDefaultInitableRequest{decl}, false); } -llvm::Expected +bool HasUserDefinedDesignatedInitRequest::evaluate(Evaluator &evaluator, NominalTypeDecl *decl) const { assert(!decl->hasClangNode()); @@ -1015,7 +1015,7 @@ static void addImplicitInheritedConstructorsToClass(ClassDecl *decl) { } } -llvm::Expected +bool InheritsSuperclassInitializersRequest::evaluate(Evaluator &eval, ClassDecl *decl) const { // Check if we parsed the @_inheritsConvenienceInitializers attribute. @@ -1085,7 +1085,7 @@ void TypeChecker::addImplicitConstructors(NominalTypeDecl *decl) { (void)decl->getDefaultInitializer(); } -llvm::Expected +evaluator::SideEffect ResolveImplicitMemberRequest::evaluate(Evaluator &evaluator, NominalTypeDecl *target, ImplicitMemberAction action) const { @@ -1162,10 +1162,10 @@ ResolveImplicitMemberRequest::evaluate(Evaluator &evaluator, } break; } - return true; + return std::make_tuple<>(); } -llvm::Expected +bool HasMemberwiseInitRequest::evaluate(Evaluator &evaluator, StructDecl *decl) const { if (!shouldAttemptInitializerSynthesis(decl)) @@ -1190,7 +1190,7 @@ HasMemberwiseInitRequest::evaluate(Evaluator &evaluator, return false; } -llvm::Expected +ConstructorDecl * SynthesizeMemberwiseInitRequest::evaluate(Evaluator &evaluator, NominalTypeDecl *decl) const { // Create the implicit memberwise constructor. @@ -1201,7 +1201,7 @@ SynthesizeMemberwiseInitRequest::evaluate(Evaluator &evaluator, return ctor; } -llvm::Expected +ConstructorDecl * ResolveEffectiveMemberwiseInitRequest::evaluate(Evaluator &evaluator, NominalTypeDecl *decl) const { // Compute the access level for the memberwise initializer. The minimum of: @@ -1288,7 +1288,7 @@ ResolveEffectiveMemberwiseInitRequest::evaluate(Evaluator &evaluator, return memberwiseInitDecl; } -llvm::Expected +bool HasDefaultInitRequest::evaluate(Evaluator &evaluator, NominalTypeDecl *decl) const { assert(isa(decl) || isa(decl)); @@ -1328,7 +1328,7 @@ synthesizeSingleReturnFunctionBody(AbstractFunctionDecl *afd, void *) { /*isTypeChecked=*/true }; } -llvm::Expected +ConstructorDecl * SynthesizeDefaultInitRequest::evaluate(Evaluator &evaluator, NominalTypeDecl *decl) const { auto &ctx = decl->getASTContext(); @@ -1369,3 +1369,21 @@ bool swift::hasLetStoredPropertyWithInitialValue(NominalTypeDecl *nominal) { return v->isLet() && v->hasInitialValue(); }); } + +void swift::addFixedLayoutAttr(NominalTypeDecl *nominal) { + auto &C = nominal->getASTContext(); + // If nominal already has `@_fixed_layout`, return. + if (nominal->getAttrs().hasAttribute()) + return; + auto access = nominal->getEffectiveAccess(); + // If nominal does not have at least internal access, return. + if (access < AccessLevel::Internal) + return; + // If nominal is internal, it should have the `@usableFromInline` attribute. + if (access == AccessLevel::Internal && + !nominal->getAttrs().hasAttribute()) { + nominal->getAttrs().add(new (C) UsableFromInlineAttr(/*Implicit*/ true)); + } + // Add `@_fixed_layout` to the nominal. + nominal->getAttrs().add(new (C) FixedLayoutAttr(/*Implicit*/ true)); +} diff --git a/lib/Sema/CodeSynthesis.h b/lib/Sema/CodeSynthesis.h index 189773002d508..de332f363ea01 100644 --- a/lib/Sema/CodeSynthesis.h +++ b/lib/Sema/CodeSynthesis.h @@ -67,6 +67,9 @@ ValueDecl *getProtocolRequirement(ProtocolDecl *protocol, Identifier name); // with an initial value. bool hasLetStoredPropertyWithInitialValue(NominalTypeDecl *nominal); +/// Add `@_fixed_layout` attribute to the nominal type, if possible. +void addFixedLayoutAttr(NominalTypeDecl *nominal); + } // end namespace swift #endif diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index b2ed04447aad4..0dfc851d05598 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -4182,18 +4182,27 @@ void SolutionApplicationTarget::maybeApplyPropertyWrapper() { if (Expr *initializer = expression.expression) { // Form init(wrappedValue:) call(s). Expr *wrappedInitializer = - buildPropertyWrapperInitialValueCall( + buildPropertyWrapperWrappedValueCall( singleVar, Type(), initializer, /*ignoreAttributeArgs=*/false); if (!wrappedInitializer) return; backingInitializer = wrappedInitializer; - } else if (auto outermostArg = outermostWrapperAttr->getArg()) { + } else { Type outermostWrapperType = singleVar->getAttachedPropertyWrapperType(0); if (!outermostWrapperType) return; + // Retrieve the outermost wrapper argument. If there isn't one, we're + // performing default initialization. + auto outermostArg = outermostWrapperAttr->getArg(); + if (!outermostArg) { + SourceLoc fakeParenLoc = outermostWrapperAttr->getRange().End; + outermostArg = TupleExpr::createEmpty( + ctx, fakeParenLoc, fakeParenLoc, /*Implicit=*/true); + } + auto typeExpr = TypeExpr::createImplicitHack( outermostWrapperAttr->getTypeLoc().getLoc(), outermostWrapperType, ctx); @@ -4203,8 +4212,6 @@ void SolutionApplicationTarget::maybeApplyPropertyWrapper() { outermostWrapperAttr->getArgumentLabelLocs(), /*hasTrailingClosure=*/false, /*implicit=*/false); - } else { - llvm_unreachable("No initializer anywhere?"); } wrapperAttrs[0]->setSemanticInit(backingInitializer); @@ -4369,9 +4376,6 @@ bool ConstraintSystem::isDeclUnavailable(const Decl *D, ConstraintLocator *locator) const { auto &ctx = getASTContext(); - if (ctx.LangOpts.DisableAvailabilityChecking) - return false; - // First check whether this declaration is universally unavailable. if (D->getAttrs().isUnavailable(ctx)) return true; @@ -4384,8 +4388,8 @@ bool ConstraintSystem::isDeclUnavailable(const Decl *D, } // If not, let's check contextual unavailability. - AvailabilityContext result = AvailabilityContext::alwaysAvailable(); - return !TypeChecker::isDeclAvailable(D, loc, DC, result); + auto result = TypeChecker::checkDeclarationAvailability(D, loc, DC); + return result.hasValue(); } /// If we aren't certain that we've emitted a diagnostic, emit a fallback diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index 4498a2e519c91..41c2e97589c05 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -2855,8 +2855,14 @@ class ConstraintSystem { } /// Add an explicit conversion constraint (e.g., \c 'x as T'). + /// + /// \param fromType The type of the expression being converted. + /// \param toType The type to convert to. + /// \param rememberChoice Whether the conversion disjunction should record its + /// choice. + /// \param locator The locator. void addExplicitConversionConstraint(Type fromType, Type toType, - bool allowFixes, + RememberChoice_t rememberChoice, ConstraintLocatorBuilder locator); /// Add a disjunction constraint. diff --git a/lib/Sema/DerivedConformanceDifferentiable.cpp b/lib/Sema/DerivedConformanceDifferentiable.cpp new file mode 100644 index 0000000000000..d0c4d2f4cd3e0 --- /dev/null +++ b/lib/Sema/DerivedConformanceDifferentiable.cpp @@ -0,0 +1,652 @@ +//===--- DerivedConformanceDifferentiable.cpp - Derived Differentiable ----===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2019 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file implements explicit derivation of the Differentiable protocol for +// struct and class types. +// +//===----------------------------------------------------------------------===// + +#include "CodeSynthesis.h" +#include "TypeChecker.h" +#include "DerivedConformances.h" +#include "swift/AST/AutoDiff.h" +#include "swift/AST/Decl.h" +#include "swift/AST/Expr.h" +#include "swift/AST/Module.h" +#include "swift/AST/ParameterList.h" +#include "swift/AST/Pattern.h" +#include "swift/AST/ProtocolConformance.h" +#include "swift/AST/Stmt.h" +#include "swift/AST/Types.h" +#include "DerivedConformances.h" + +using namespace swift; + +/// Get the stored properties of a nominal type that are relevant for +/// differentiation, except the ones tagged `@noDerivative`. +static void +getStoredPropertiesForDifferentiation(NominalTypeDecl *nominal, DeclContext *DC, + SmallVectorImpl &result) { + auto &C = nominal->getASTContext(); + auto *diffableProto = C.getProtocol(KnownProtocolKind::Differentiable); + for (auto *vd : nominal->getStoredProperties()) { + // Skip stored properties with `@noDerivative` attribute. + if (vd->getAttrs().hasAttribute()) + continue; + // For property wrapper backing storage properties, skip if original + // property has `@noDerivative` attribute. + if (auto *originalProperty = vd->getOriginalWrappedProperty()) + if (originalProperty->getAttrs().hasAttribute()) + continue; + // Skip `let` stored properties. `mutating func move(along:)` cannot be + // synthesized to update these properties. + if (vd->isLet()) + continue; + if (vd->getInterfaceType()->hasError()) + continue; + auto varType = DC->mapTypeIntoContext(vd->getValueInterfaceType()); + if (!TypeChecker::conformsToProtocol(varType, diffableProto, nominal, None)) + continue; + result.push_back(vd); + } +} + +/// Convert the given `ValueDecl` to a `StructDecl` if it is a `StructDecl` or a +/// `TypeDecl` with an underlying struct type. Otherwise, return `nullptr`. +static StructDecl *convertToStructDecl(ValueDecl *v) { + if (auto *structDecl = dyn_cast(v)) + return structDecl; + auto *typeDecl = dyn_cast(v); + if (!typeDecl) + return nullptr; + return dyn_cast_or_null( + typeDecl->getDeclaredInterfaceType()->getAnyNominal()); +} + +/// Get the `Differentiable` protocol `TangentVector` associated type for the +/// given `VarDecl`. +/// TODO: Generalize and move function to shared place for use with other +/// derived conformances. +static Type getTangentVectorType(VarDecl *decl, DeclContext *DC) { + auto &C = decl->getASTContext(); + auto *diffableProto = C.getProtocol(KnownProtocolKind::Differentiable); + auto varType = DC->mapTypeIntoContext(decl->getValueInterfaceType()); + auto conf = TypeChecker::conformsToProtocol(varType, diffableProto, DC, None); + if (!conf) + return nullptr; + Type tangentType = conf.getTypeWitnessByName(varType, C.Id_TangentVector); + return tangentType; +} + +// Get the `Differentiable` protocol associated `TangentVector` struct for the +// given nominal `DeclContext`. Asserts that the `TangentVector` struct type +// exists. +static StructDecl *getTangentVectorStructDecl(DeclContext *DC) { + assert(DC->getSelfNominalTypeDecl() && "Must be a nominal `DeclContext`"); + auto &C = DC->getASTContext(); + auto *diffableProto = C.getProtocol(KnownProtocolKind::Differentiable); + assert(diffableProto && "`Differentiable` protocol not found"); + auto conf = TypeChecker::conformsToProtocol(DC->getSelfTypeInContext(), + diffableProto, DC, None); + assert(conf && "Nominal must conform to `Differentiable`"); + auto assocType = + conf.getTypeWitnessByName(DC->getSelfTypeInContext(), C.Id_TangentVector); + assert(assocType && "`Differentiable.TangentVector` type not found"); + auto *structDecl = dyn_cast(assocType->getAnyNominal()); + assert(structDecl && "Associated type must be a struct type"); + return structDecl; +} + +bool DerivedConformance::canDeriveDifferentiable(NominalTypeDecl *nominal, + DeclContext *DC) { + // Experimental differentiable programming must be enabled. + auto &ctx = nominal->getASTContext(); + if (!ctx.LangOpts.EnableExperimentalDifferentiableProgramming) + return false; + // Nominal type must be a struct or class. (No stored properties is okay.) + if (!isa(nominal) && !isa(nominal)) + return false; + auto &C = nominal->getASTContext(); + auto *diffableProto = C.getProtocol(KnownProtocolKind::Differentiable); + auto *addArithProto = C.getProtocol(KnownProtocolKind::AdditiveArithmetic); + + // Nominal type must not customize `TangentVector` to anything other than + // `Self`. Otherwise, synthesis is semantically unsupported. + auto tangentDecls = nominal->lookupDirect(C.Id_TangentVector); + auto nominalTypeInContext = + DC->mapTypeIntoContext(nominal->getDeclaredInterfaceType()); + + auto isValidAssocTypeCandidate = [&](ValueDecl *v) -> StructDecl * { + // Valid candidate must be a struct or a typealias to a struct. + auto *structDecl = convertToStructDecl(v); + if (!structDecl) + return nullptr; + // Valid candidate must either: + // 1. Be implicit (previously synthesized). + if (structDecl->isImplicit()) + return structDecl; + // 2. Equal nominal's implicit parent. + // This can occur during mutually recursive constraints. Example: + // `X == X.TangentVector`. + if (nominal->isImplicit() && structDecl == nominal->getDeclContext() && + TypeChecker::conformsToProtocol(structDecl->getDeclaredInterfaceType(), + diffableProto, DC, None)) + return structDecl; + // 3. Equal nominal and conform to `AdditiveArithmetic`. + if (structDecl == nominal) { + // Check conformance to `AdditiveArithmetic`. + if (TypeChecker::conformsToProtocol(nominalTypeInContext, addArithProto, + DC, None)) + return structDecl; + } + // Otherwise, candidate is invalid. + return nullptr; + }; + + auto invalidTangentDecls = llvm::partition( + tangentDecls, [&](ValueDecl *v) { return isValidAssocTypeCandidate(v); }); + + auto validTangentDeclCount = + std::distance(tangentDecls.begin(), invalidTangentDecls); + auto invalidTangentDeclCount = + std::distance(invalidTangentDecls, tangentDecls.end()); + + // There cannot be any invalid `TangentVector` types. + // There can be at most one valid `TangentVector` type. + if (invalidTangentDeclCount != 0 || validTangentDeclCount > 1) + return false; + + // All stored properties not marked with `@noDerivative`: + // - Must conform to `Differentiable`. + // - Must not have any `let` stored properties with an initial value. + // - This restriction may be lifted later with support for "true" memberwise + // initializers that initialize all stored properties, including initial + // value information. + SmallVector diffProperties; + getStoredPropertiesForDifferentiation(nominal, DC, diffProperties); + return llvm::all_of(diffProperties, [&](VarDecl *v) { + if (v->getInterfaceType()->hasError()) + return false; + auto varType = DC->mapTypeIntoContext(v->getValueInterfaceType()); + return (bool)TypeChecker::conformsToProtocol(varType, diffableProto, DC, + None); + }); +} + +/// Synthesize body for a `Differentiable` method requirement. +static std::pair +deriveBodyDifferentiable_method(AbstractFunctionDecl *funcDecl, + Identifier methodName, + Identifier methodParamLabel) { + auto *parentDC = funcDecl->getParent(); + auto *nominal = parentDC->getSelfNominalTypeDecl(); + auto &C = nominal->getASTContext(); + + // Get method protocol requirement. + auto *diffProto = C.getProtocol(KnownProtocolKind::Differentiable); + auto *methodReq = getProtocolRequirement(diffProto, methodName); + + // Get references to `self` and parameter declarations. + auto *selfDecl = funcDecl->getImplicitSelfDecl(); + auto *selfDRE = + new (C) DeclRefExpr(selfDecl, DeclNameLoc(), /*Implicit*/ true); + auto *paramDecl = funcDecl->getParameters()->get(0); + auto *paramDRE = + new (C) DeclRefExpr(paramDecl, DeclNameLoc(), /*Implicit*/ true); + + SmallVector diffProperties; + getStoredPropertiesForDifferentiation(nominal, parentDC, diffProperties); + + // Create call expression applying a member method to a parameter member. + // Format: `.method(.)`. + // Example: `x.move(along: direction.x)`. + auto createMemberMethodCallExpr = [&](VarDecl *member) -> Expr * { + auto *module = nominal->getModuleContext(); + auto memberType = + parentDC->mapTypeIntoContext(member->getValueInterfaceType()); + auto confRef = module->lookupConformance(memberType, diffProto); + assert(confRef && "Member does not conform to `Differentiable`"); + + // Get member type's method, e.g. `Member.move(along:)`. + // Use protocol requirement declaration for the method by default: this + // will be dynamically dispatched. + ValueDecl *memberMethodDecl = methodReq; + // If conformance reference is concrete, then use concrete witness + // declaration for the operator. + if (confRef.isConcrete()) + memberMethodDecl = confRef.getConcrete()->getWitnessDecl(methodReq); + assert(memberMethodDecl && "Member method declaration must exist"); + auto memberMethodDRE = + new (C) DeclRefExpr(memberMethodDecl, DeclNameLoc(), /*Implicit*/ true); + memberMethodDRE->setFunctionRefKind(FunctionRefKind::SingleApply); + + // Create reference to member method: `x.move(along:)`. + auto memberExpr = + new (C) MemberRefExpr(selfDRE, SourceLoc(), member, DeclNameLoc(), + /*Implicit*/ true); + auto memberMethodExpr = + new (C) DotSyntaxCallExpr(memberMethodDRE, SourceLoc(), memberExpr); + + // Create reference to parameter member: `direction.x`. + VarDecl *paramMember = nullptr; + auto *paramNominal = paramDecl->getType()->getAnyNominal(); + assert(paramNominal && "Parameter should have a nominal type"); + // Find parameter member corresponding to returned nominal member. + for (auto *candidate : paramNominal->getStoredProperties()) { + if (candidate->getName() == member->getName()) { + paramMember = candidate; + break; + } + } + assert(paramMember && "Could not find corresponding parameter member"); + auto *paramMemberExpr = + new (C) MemberRefExpr(paramDRE, SourceLoc(), paramMember, DeclNameLoc(), + /*Implicit*/ true); + // Create expression: `x.move(along: direction.x)`. + return CallExpr::createImplicit(C, memberMethodExpr, {paramMemberExpr}, + {methodParamLabel}); + }; + + // Create array of member method call expressions. + llvm::SmallVector memberMethodCallExprs; + llvm::SmallVector memberNames; + for (auto *member : diffProperties) { + memberMethodCallExprs.push_back(createMemberMethodCallExpr(member)); + memberNames.push_back(member->getName()); + } + auto *braceStmt = BraceStmt::create(C, SourceLoc(), memberMethodCallExprs, + SourceLoc(), true); + return std::pair(braceStmt, false); +} + +/// Synthesize body for `move(along:)`. +static std::pair +deriveBodyDifferentiable_move(AbstractFunctionDecl *funcDecl, void *) { + auto &C = funcDecl->getASTContext(); + return deriveBodyDifferentiable_method(funcDecl, C.Id_move, C.Id_along); +} + +/// Synthesize function declaration for a `Differentiable` method requirement. +static ValueDecl *deriveDifferentiable_method( + DerivedConformance &derived, Identifier methodName, Identifier argumentName, + Identifier parameterName, Type parameterType, Type returnType, + AbstractFunctionDecl::BodySynthesizer bodySynthesizer) { + auto *nominal = derived.Nominal; + auto &C = derived.Context; + auto *parentDC = derived.getConformanceContext(); + + auto *param = new (C) ParamDecl(SourceLoc(), SourceLoc(), argumentName, + SourceLoc(), parameterName, parentDC); + param->setSpecifier(ParamDecl::Specifier::Default); + param->setInterfaceType(parameterType); + ParameterList *params = ParameterList::create(C, {param}); + + DeclName declName(C, methodName, params); + auto *funcDecl = FuncDecl::create(C, SourceLoc(), StaticSpellingKind::None, + SourceLoc(), declName, SourceLoc(), + /*Throws*/ false, SourceLoc(), + /*GenericParams=*/nullptr, params, + TypeLoc::withoutLoc(returnType), parentDC); + if (!nominal->getSelfClassDecl()) + funcDecl->setSelfAccessKind(SelfAccessKind::Mutating); + funcDecl->setImplicit(); + funcDecl->setBodySynthesizer(bodySynthesizer.Fn, bodySynthesizer.Context); + + funcDecl->setGenericSignature(parentDC->getGenericSignatureOfContext()); + funcDecl->copyFormalAccessFrom(nominal, /*sourceIsParentContext*/ true); + + derived.addMembersToConformanceContext({funcDecl}); + return funcDecl; +} + +/// Synthesize the `move(along:)` function declaration. +static ValueDecl *deriveDifferentiable_move(DerivedConformance &derived) { + auto &C = derived.Context; + auto *parentDC = derived.getConformanceContext(); + + auto *tangentDecl = getTangentVectorStructDecl(parentDC); + auto tangentType = tangentDecl->getDeclaredInterfaceType(); + + return deriveDifferentiable_method( + derived, C.Id_move, C.Id_along, C.Id_direction, tangentType, + C.TheEmptyTupleType, {deriveBodyDifferentiable_move, nullptr}); +} + +/// Return associated `TangentVector` struct for a nominal type, if it exists. +/// If not, synthesize the struct. +static StructDecl * +getOrSynthesizeTangentVectorStruct(DerivedConformance &derived, Identifier id) { + auto *parentDC = derived.getConformanceContext(); + auto *nominal = derived.Nominal; + auto &C = nominal->getASTContext(); + + // If the associated struct already exists, return it. + auto lookup = nominal->lookupDirect(C.Id_TangentVector); + assert(lookup.size() < 2 && + "Expected at most one associated type named `TangentVector`"); + if (lookup.size() == 1) { + auto *structDecl = convertToStructDecl(lookup.front()); + assert(structDecl && "Expected lookup result to be a struct"); + return structDecl; + } + + // Otherwise, synthesize a new struct. + auto *diffableProto = C.getProtocol(KnownProtocolKind::Differentiable); + auto diffableType = TypeLoc::withoutLoc(diffableProto->getDeclaredType()); + auto *addArithProto = C.getProtocol(KnownProtocolKind::AdditiveArithmetic); + auto addArithType = TypeLoc::withoutLoc(addArithProto->getDeclaredType()); + + // By definition, `TangentVector` must conform to `Differentiable` and + // `AdditiveArithmetic`. + SmallVector inherited{diffableType, addArithType}; + + // Cache original members and their associated types for later use. + SmallVector diffProperties; + getStoredPropertiesForDifferentiation(nominal, parentDC, diffProperties); + + auto *structDecl = + new (C) StructDecl(SourceLoc(), C.Id_TangentVector, SourceLoc(), + /*Inherited*/ C.AllocateCopy(inherited), + /*GenericParams*/ {}, parentDC); + structDecl->setImplicit(); + structDecl->copyFormalAccessFrom(nominal, /*sourceIsParentContext*/ true); + + // Add members to `TangentVector` struct. + for (auto *member : diffProperties) { + // Add this member's corresponding `TangentVector` type to the parent's + // `TangentVector` struct. + auto *newMember = new (C) VarDecl( + member->isStatic(), member->getIntroducer(), member->isCaptureList(), + /*NameLoc*/ SourceLoc(), member->getName(), structDecl); + // NOTE: `newMember` is not marked as implicit here, because that affects + // memberwise initializer synthesis. + + auto memberAssocType = getTangentVectorType(member, parentDC); + auto memberAssocInterfaceType = memberAssocType->hasArchetype() + ? memberAssocType->mapTypeOutOfContext() + : memberAssocType; + auto memberAssocContextualType = + parentDC->mapTypeIntoContext(memberAssocInterfaceType); + newMember->setInterfaceType(memberAssocInterfaceType); + Pattern *memberPattern = new (C) NamedPattern(newMember, /*implicit*/ true); + memberPattern->setType(memberAssocContextualType); + memberPattern = TypedPattern::createImplicit(C, memberPattern, + memberAssocContextualType); + memberPattern->setType(memberAssocContextualType); + auto *memberBinding = PatternBindingDecl::createImplicit( + C, StaticSpellingKind::None, memberPattern, /*initExpr*/ nullptr, + structDecl); + structDecl->addMember(newMember); + structDecl->addMember(memberBinding); + newMember->copyFormalAccessFrom(member, /*sourceIsParentContext*/ true); + newMember->setSetterAccess(member->getFormalAccess()); + + // Now that this member is in the `TangentVector` type, it should be marked + // `@differentiable` so that the differentiation transform will synthesize + // derivative functions for it. We only add this to public stored + // properties, because their access outside the module will go through a + // call to the getter. + if (member->getEffectiveAccess() > AccessLevel::Internal && + !member->getAttrs().hasAttribute()) { + auto *getter = member->getSynthesizedAccessor(AccessorKind::Get); + (void)getter->getInterfaceType(); + // If member or its getter already has a `@differentiable` attribute, + // continue. + if (member->getAttrs().hasAttribute() || + getter->getAttrs().hasAttribute()) + continue; + GenericSignature derivativeGenericSignature = + getter->getGenericSignature(); + // If the parent declaration context is an extension, the nominal type may + // conditionally conform to `Differentiable`. Use the extension generic + // requirements in getter `@differentiable` attributes. + if (auto *extDecl = dyn_cast(parentDC->getAsDecl())) + if (auto extGenSig = extDecl->getGenericSignature()) + derivativeGenericSignature = extGenSig; + auto *diffableAttr = DifferentiableAttr::create( + getter, /*implicit*/ true, SourceLoc(), SourceLoc(), + /*linear*/ false, /*parameterIndices*/ IndexSubset::get(C, 1, {0}), + derivativeGenericSignature); + member->getAttrs().add(diffableAttr); + } + } + + // If nominal type is `@_fixed_layout`, also mark `TangentVector` struct as + // `@_fixed_layout`. + if (nominal->getAttrs().hasAttribute()) + addFixedLayoutAttr(structDecl); + + // If nominal type is `@frozen`, also mark `TangentVector` struct as + // `@frozen`. + if (nominal->getAttrs().hasAttribute()) + structDecl->getAttrs().add(new (C) FrozenAttr(/*implicit*/ true)); + + // If nominal type is `@usableFromInline`, also mark `TangentVector` struct as + // `@usableFromInline`. + if (nominal->getAttrs().hasAttribute()) + structDecl->getAttrs().add(new (C) UsableFromInlineAttr(/*implicit*/ true)); + + // The implicit memberwise constructor must be explicitly created so that it + // can called in `AdditiveArithmetic` and `Differentiable` methods. Normally, + // the memberwise constructor is synthesized during SILGen, which is too late. + TypeChecker::addImplicitConstructors(structDecl); + + // After memberwise initializer is synthesized, mark members as implicit. + for (auto *member : structDecl->getStoredProperties()) + member->setImplicit(); + + derived.addMembersToConformanceContext({structDecl}); + return structDecl; +} + +/// Add a typealias declaration with the given name and underlying target +/// struct type to the given source nominal declaration context. +static void addAssociatedTypeAliasDecl(Identifier name, DeclContext *sourceDC, + StructDecl *target, + ASTContext &Context) { + auto *nominal = sourceDC->getSelfNominalTypeDecl(); + assert(nominal && "Expected `DeclContext` to be a nominal type"); + auto lookup = nominal->lookupDirect(name); + assert(lookup.size() < 2 && + "Expected at most one associated type named member"); + // If implicit type declaration with the given name already exists in source + // struct, return it. + if (lookup.size() == 1) { + auto existingTypeDecl = dyn_cast(lookup.front()); + assert(existingTypeDecl && existingTypeDecl->isImplicit() && + "Expected lookup result to be an implicit type declaration"); + return; + } + // Otherwise, create a new typealias. + auto *aliasDecl = new (Context) + TypeAliasDecl(SourceLoc(), SourceLoc(), name, SourceLoc(), {}, sourceDC); + aliasDecl->setUnderlyingType(target->getDeclaredInterfaceType()); + aliasDecl->setImplicit(); + aliasDecl->setGenericSignature(sourceDC->getGenericSignatureOfContext()); + cast(sourceDC->getAsDecl())->addMember(aliasDecl); + aliasDecl->copyFormalAccessFrom(nominal, /*sourceIsParentContext*/ true); +}; + +/// Diagnose stored properties in the nominal that do not have an explicit +/// `@noDerivative` attribute, but either: +/// - Do not conform to `Differentiable`. +/// - Are a `let` stored property. +/// Emit a warning and a fixit so that users will make the attribute explicit. +static void checkAndDiagnoseImplicitNoDerivative(ASTContext &Context, + NominalTypeDecl *nominal, + DeclContext *DC) { + auto *diffableProto = Context.getProtocol(KnownProtocolKind::Differentiable); + bool nominalCanDeriveAdditiveArithmetic = + DerivedConformance::canDeriveAdditiveArithmetic(nominal, DC); + for (auto *vd : nominal->getStoredProperties()) { + if (vd->getInterfaceType()->hasError()) + continue; + // Skip stored properties with `@noDerivative` attribute. + if (vd->getAttrs().hasAttribute()) + continue; + // For property wrapper backing storage properties, skip if original + // property has `@noDerivative` attribute. + if (auto *originalProperty = vd->getOriginalWrappedProperty()) + if (originalProperty->getAttrs().hasAttribute()) + continue; + // Check whether to diagnose stored property. + auto varType = DC->mapTypeIntoContext(vd->getValueInterfaceType()); + bool conformsToDifferentiable = + !TypeChecker::conformsToProtocol(varType, diffableProto, nominal, None) + .isInvalid(); + // If stored property should not be diagnosed, continue. + if (conformsToDifferentiable && !vd->isLet()) + continue; + // Otherwise, add an implicit `@noDerivative` attribute. + vd->getAttrs().add(new (Context) NoDerivativeAttr(/*Implicit*/ true)); + auto loc = vd->getAttributeInsertionLoc(/*forModifier*/ false); + if (auto *originalProperty = vd->getOriginalWrappedProperty()) + loc = originalProperty->getAttributeInsertionLoc(/*forModifier*/ false); + assert(loc.isValid() && "Expected valid source location"); + // If nominal type can conform to `AdditiveArithmetic`, suggest conforming + // adding a conformance to `AdditiveArithmetic`. + // `Differentiable` protocol requirements all have default implementations + // when `Self` conforms to `AdditiveArithmetic`, so `Differentiable` + // derived conformances will no longer be necessary. + if (!conformsToDifferentiable) { + Context.Diags + .diagnose( + loc, + diag::differentiable_nondiff_type_implicit_noderivative_fixit, + vd->getName(), vd->getType(), nominal->getName(), + nominalCanDeriveAdditiveArithmetic) + .fixItInsert(loc, "@noDerivative "); + continue; + } + Context.Diags + .diagnose(loc, + diag::differentiable_let_property_implicit_noderivative_fixit, + vd->getName(), nominal->getName(), + nominalCanDeriveAdditiveArithmetic) + .fixItInsert(loc, "@noDerivative "); + } +} + +/// Get or synthesize `TangentVector` struct type. +static Type +getOrSynthesizeTangentVectorStructType(DerivedConformance &derived) { + auto *parentDC = derived.getConformanceContext(); + auto *nominal = derived.Nominal; + auto &C = nominal->getASTContext(); + + // Get or synthesize `TangentVector` struct. + auto *tangentStruct = + getOrSynthesizeTangentVectorStruct(derived, C.Id_TangentVector); + if (!tangentStruct) + return nullptr; + // Check and emit warnings for implicit `@noDerivative` members. + checkAndDiagnoseImplicitNoDerivative(C, nominal, parentDC); + // Add `TangentVector` typealias for `TangentVector` struct. + addAssociatedTypeAliasDecl(C.Id_TangentVector, tangentStruct, tangentStruct, + C); + + // Sanity checks for synthesized struct. + assert(DerivedConformance::canDeriveAdditiveArithmetic(tangentStruct, + parentDC) && + "Should be able to derive `AdditiveArithmetic`"); + assert(DerivedConformance::canDeriveDifferentiable(tangentStruct, parentDC) && + "Should be able to derive `Differentiable`"); + + // Return the `TangentVector` struct type. + return parentDC->mapTypeIntoContext( + tangentStruct->getDeclaredInterfaceType()); +} + +/// Synthesize the `TangentVector` struct type. +static Type +deriveDifferentiable_TangentVectorStruct(DerivedConformance &derived) { + auto *parentDC = derived.getConformanceContext(); + auto *nominal = derived.Nominal; + auto &C = nominal->getASTContext(); + + // Get all stored properties for differentation. + SmallVector diffProperties; + getStoredPropertiesForDifferentiation(nominal, parentDC, diffProperties); + + // If any member has an invalid `TangentVector` type, return nullptr. + for (auto *member : diffProperties) + if (!getTangentVectorType(member, parentDC)) + return nullptr; + + // Prevent re-synthesis during repeated calls. + // FIXME: Investigate why this is necessary to prevent duplicate synthesis. + auto lookup = nominal->lookupDirect(C.Id_TangentVector); + if (lookup.size() == 1) + if (auto *structDecl = convertToStructDecl(lookup.front())) + if (structDecl->isImplicit()) + return structDecl->getDeclaredInterfaceType(); + + // Check whether at least one `@noDerivative` stored property exists. + unsigned numStoredProperties = + std::distance(nominal->getStoredProperties().begin(), + nominal->getStoredProperties().end()); + bool hasNoDerivativeStoredProp = diffProperties.size() != numStoredProperties; + + // Check conditions for returning `Self`. + // - `Self` is not a class type. + // - No `@noDerivative` stored properties exist. + // - All stored properties must have `TangentVector` type equal to `Self`. + // - Parent type must also conform to `AdditiveArithmetic`. + bool allMembersAssocTypeEqualsSelf = + llvm::all_of(diffProperties, [&](VarDecl *member) { + auto memberAssocType = getTangentVectorType(member, parentDC); + return member->getType()->isEqual(memberAssocType); + }); + + auto *addArithProto = C.getProtocol(KnownProtocolKind::AdditiveArithmetic); + auto nominalConformsToAddArith = TypeChecker::conformsToProtocol( + parentDC->getSelfTypeInContext(), addArithProto, parentDC, None); + + // Return `Self` if conditions are met. + if (!hasNoDerivativeStoredProp && !nominal->getSelfClassDecl() && + allMembersAssocTypeEqualsSelf && nominalConformsToAddArith) { + auto selfType = parentDC->getSelfTypeInContext(); + auto *aliasDecl = + new (C) TypeAliasDecl(SourceLoc(), SourceLoc(), C.Id_TangentVector, + SourceLoc(), {}, parentDC); + aliasDecl->setUnderlyingType(selfType); + aliasDecl->setImplicit(); + aliasDecl->copyFormalAccessFrom(nominal, /*sourceIsParentContext*/ true); + derived.addMembersToConformanceContext({aliasDecl}); + return selfType; + } + + // Otherwise, get or synthesize `TangentVector` struct type. + return getOrSynthesizeTangentVectorStructType(derived); +} + +ValueDecl *DerivedConformance::deriveDifferentiable(ValueDecl *requirement) { + // Diagnose conformances in disallowed contexts. + if (checkAndDiagnoseDisallowedContext(requirement)) + return nullptr; + if (requirement->getBaseName() == Context.Id_move) + return deriveDifferentiable_move(*this); + Context.Diags.diagnose(requirement->getLoc(), + diag::broken_differentiable_requirement); + return nullptr; +} + +Type DerivedConformance::deriveDifferentiable(AssociatedTypeDecl *requirement) { + // Diagnose conformances in disallowed contexts. + if (checkAndDiagnoseDisallowedContext(requirement)) + return nullptr; + if (requirement->getBaseName() == Context.Id_TangentVector) + return deriveDifferentiable_TangentVectorStruct(*this); + Context.Diags.diagnose(requirement->getLoc(), + diag::broken_differentiable_requirement); + return nullptr; +} diff --git a/lib/Sema/DerivedConformances.cpp b/lib/Sema/DerivedConformances.cpp index ae2130163656b..0ed81748b8f85 100644 --- a/lib/Sema/DerivedConformances.cpp +++ b/lib/Sema/DerivedConformances.cpp @@ -69,6 +69,9 @@ bool DerivedConformance::derivesProtocolConformance(DeclContext *DC, if (*knownProtocol == KnownProtocolKind::AdditiveArithmetic) return canDeriveAdditiveArithmetic(Nominal, DC); + if (*knownProtocol == KnownProtocolKind::Differentiable) + return canDeriveDifferentiable(Nominal, DC); + if (auto *enumDecl = dyn_cast(Nominal)) { switch (*knownProtocol) { // The presence of a raw type is an explicit declaration that @@ -242,6 +245,13 @@ ValueDecl *DerivedConformance::getDerivableRequirement(NominalTypeDecl *nominal, return getRequirement(KnownProtocolKind::AdditiveArithmetic); } + // Differentiable.move(along:) + if (name.isCompoundName() && name.getBaseName() == ctx.Id_move) { + auto argumentNames = name.getArgumentNames(); + if (argumentNames.size() == 1 && argumentNames[0] == ctx.Id_along) + return getRequirement(KnownProtocolKind::Differentiable); + } + // Encodable.encode(to: Encoder) if (name.isCompoundName() && name.getBaseName() == ctx.Id_encode) { auto argumentNames = name.getArgumentNames(); @@ -291,6 +301,10 @@ ValueDecl *DerivedConformance::getDerivableRequirement(NominalTypeDecl *nominal, if (name.isSimpleName(ctx.Id_AllCases)) return getRequirement(KnownProtocolKind::CaseIterable); + // Differentiable.TangentVector + if (name.isSimpleName(ctx.Id_TangentVector)) + return getRequirement(KnownProtocolKind::Differentiable); + return nullptr; } diff --git a/lib/Sema/DerivedConformances.h b/lib/Sema/DerivedConformances.h index 5a3465dd1594c..0073f8edbbfd3 100644 --- a/lib/Sema/DerivedConformances.h +++ b/lib/Sema/DerivedConformances.h @@ -107,6 +107,21 @@ class DerivedConformance { /// \returns the derived member, which will also be added to the type. ValueDecl *deriveAdditiveArithmetic(ValueDecl *requirement); + /// Determine if a Differentiable requirement can be derived for a type. + /// + /// \returns True if the requirement can be derived. + static bool canDeriveDifferentiable(NominalTypeDecl *type, DeclContext *DC); + + /// Derive a Differentiable requirement for a nominal type. + /// + /// \returns the derived member, which will also be added to the type. + ValueDecl *deriveDifferentiable(ValueDecl *requirement); + + /// Derive a Differentiable type witness for a nominal type. + /// + /// \returns the derived member, which will also be added to the type. + Type deriveDifferentiable(AssociatedTypeDecl *assocType); + /// Derive a CaseIterable requirement for an enum if it has no associated /// values for any of its cases. /// diff --git a/lib/Sema/IDETypeCheckingRequests.cpp b/lib/Sema/IDETypeCheckingRequests.cpp index f4760dcf5bee1..60fec61c517c4 100644 --- a/lib/Sema/IDETypeCheckingRequests.cpp +++ b/lib/Sema/IDETypeCheckingRequests.cpp @@ -84,7 +84,7 @@ static bool isMemberDeclAppliedInternal(const DeclContext *DC, Type BaseTy, /*isExtension=*/false); } -llvm::Expected +bool IsDeclApplicableRequest::evaluate(Evaluator &evaluator, DeclApplicabilityOwner Owner) const { if (auto *VD = dyn_cast(Owner.ExtensionOrMember)) { @@ -96,7 +96,7 @@ IsDeclApplicableRequest::evaluate(Evaluator &evaluator, } } -llvm::Expected +bool TypeRelationCheckRequest::evaluate(Evaluator &evaluator, TypeRelationCheckInput Owner) const { Optional CKind; @@ -112,7 +112,7 @@ TypeRelationCheckRequest::evaluate(Evaluator &evaluator, *CKind, Owner.DC); } -llvm::Expected +TypePair RootAndResultTypeOfKeypathDynamicMemberRequest::evaluate(Evaluator &evaluator, SubscriptDecl *subscript) const { if (!isValidKeyPathDynamicMemberLookup(subscript)) diff --git a/lib/Sema/NameBinding.cpp b/lib/Sema/NameBinding.cpp index 40e45d8f92274..69018ad651d54 100644 --- a/lib/Sema/NameBinding.cpp +++ b/lib/Sema/NameBinding.cpp @@ -10,8 +10,8 @@ // //===----------------------------------------------------------------------===// // -// This file binds the names in non-ValueDecls Decls like imports, operators, -// and precedence groups. +// This file performs import resolution. +// FIXME: Rename NameBinding to ImportResolution. // //===----------------------------------------------------------------------===// @@ -206,12 +206,8 @@ namespace { } private: - // Special behavior for these decls: + // We only need to visit import decls. void visitImportDecl(ImportDecl *ID); - void visitPrecedenceGroupDecl(PrecedenceGroupDecl *group); - void visitPrefixOperatorDecl(PrefixOperatorDecl *OpDecl); - void visitInfixOperatorDecl(InfixOperatorDecl *OpDecl); - void visitPostfixOperatorDecl(PostfixOperatorDecl *OpDecl); // Ignore other decls. void visitDecl(Decl *D) {} @@ -258,10 +254,6 @@ namespace { /// /// Returns null if no module can be loaded. ModuleDecl *getModule(ArrayRef> ModuleID); - - template - void insertOperatorDecl(SourceFile::OperatorMap &Operators, - OP_DECL *OpDecl); }; } // end anonymous namespace @@ -270,14 +262,12 @@ namespace { //===----------------------------------------------------------------------===// /// performNameBinding - Once parsing is complete, this walks the AST to -/// resolve names and do other top-level validation. +/// resolve imports. /// /// Most names are actually bound by the type checker, but before we can /// type-check a source file, we need to make declarations imported from other -/// modules available and build tables of the operators and precedecence groups -/// declared in that file. Name binding processes top-level \c ImportDecl, -/// \c OperatorDecl, and \c PrecedenceGroupDecl nodes to perform these tasks, -/// along with related validation. +/// modules available. Name binding processes top-level \c ImportDecl nodes +/// to perform this task, along with related validation. /// /// Name binding operates on a parsed but otherwise unvalidated AST. void swift::performNameBinding(SourceFile &SF) { @@ -293,7 +283,7 @@ void swift::performNameBinding(SourceFile &SF) { NameBinder Binder(SF); - // Bind each import and operator declaration. + // Resolve each import declaration. for (auto D : SF.getTopLevelDecls()) Binder.visit(D); @@ -303,52 +293,6 @@ void swift::performNameBinding(SourceFile &SF) { verify(SF); } -//===----------------------------------------------------------------------===// -// MARK: Operator declarations -//===----------------------------------------------------------------------===// - -template void -NameBinder::insertOperatorDecl(SourceFile::OperatorMap &Operators, - OP_DECL *OpDecl) { - auto previousDecl = Operators.find(OpDecl->getName()); - if (previousDecl != Operators.end()) { - diagnose(OpDecl->getLoc(), diag::operator_redeclared); - diagnose(previousDecl->second.getPointer(), - diag::previous_operator_decl); - return; - } - - // FIXME: The second argument indicates whether the given operator is visible - // outside the current file. - Operators[OpDecl->getName()] = { OpDecl, true }; -} - -void NameBinder::visitPrefixOperatorDecl(PrefixOperatorDecl *OpDecl) { - insertOperatorDecl(SF.PrefixOperators, OpDecl); -} - -void NameBinder::visitInfixOperatorDecl(InfixOperatorDecl *OpDecl) { - insertOperatorDecl(SF.InfixOperators, OpDecl); -} - -void NameBinder::visitPostfixOperatorDecl(PostfixOperatorDecl *OpDecl) { - insertOperatorDecl(SF.PostfixOperators, OpDecl); -} - -void NameBinder::visitPrecedenceGroupDecl(PrecedenceGroupDecl *group) { - auto previousDecl = SF.PrecedenceGroups.find(group->getName()); - if (previousDecl != SF.PrecedenceGroups.end()) { - diagnose(group->getLoc(), diag::precedence_group_redeclared); - diagnose(previousDecl->second.getPointer(), - diag::previous_precedence_group_decl); - return; - } - - // FIXME: The second argument indicates whether the given precedence - // group is visible outside the current file. - SF.PrecedenceGroups[group->getName()] = { group, true }; -} - //===----------------------------------------------------------------------===// // MARK: Import handling generally //===----------------------------------------------------------------------===// @@ -713,7 +657,7 @@ static const char *getImportKindString(ImportKind kind) { llvm_unreachable("Unhandled ImportKind in switch."); } -llvm::Expected> +ArrayRef ScopedImportLookupRequest::evaluate(Evaluator &evaluator, ImportDecl *import) const { using namespace namelookup; diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 1aa1385fb6b1b..1bf0f5c292905 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -114,9 +114,7 @@ class AttributeChecker : public AttributeVisitor { IGNORED_ATTR(ProjectedValueProperty) IGNORED_ATTR(ReferenceOwnership) IGNORED_ATTR(OriginallyDefinedIn) - // TODO(TF-830): Upstream `@transpose` attribute type-checking from tensorflow - // branch. - IGNORED_ATTR(Transpose) + IGNORED_ATTR(NoDerivative) #undef IGNORED_ATTR void visitAlignmentAttr(AlignmentAttr *attr) { @@ -254,6 +252,7 @@ class AttributeChecker : public AttributeVisitor { void visitDifferentiableAttr(DifferentiableAttr *attr); void visitDerivativeAttr(DerivativeAttr *attr); + void visitTransposeAttr(TransposeAttr *attr); }; } // end anonymous namespace @@ -2395,7 +2394,7 @@ void AttributeChecker::visitDynamicReplacementAttr(DynamicReplacementAttr *attr) } } -llvm::Expected +bool TypeEraserHasViableInitRequest::evaluate(Evaluator &evaluator, TypeEraserAttr *attr, ProtocolDecl *protocol) const { @@ -3097,7 +3096,7 @@ void TypeChecker::addImplicitDynamicAttribute(Decl *D) { } } -llvm::Expected +ValueDecl * DynamicallyReplacedDeclRequest::evaluate(Evaluator &evaluator, ValueDecl *VD) const { // Dynamic replacements must be explicit. @@ -3598,6 +3597,105 @@ getDerivativeOriginalFunctionType(AnyFunctionType *derivativeFnTy) { return originalType; } +// Computes the original function type corresponding to the given transpose +// function type. Used for `@transpose` attribute type-checking. +static AnyFunctionType * +getTransposeOriginalFunctionType(AnyFunctionType *transposeFnType, + IndexSubset *linearParamIndices, + bool wrtSelf) { + unsigned transposeParamsIndex = 0; + + // Get the transpose function's parameters and result type. + auto transposeParams = transposeFnType->getParams(); + auto transposeResult = transposeFnType->getResult(); + bool isCurried = transposeResult->is(); + if (isCurried) { + auto methodType = transposeResult->castTo(); + transposeParams = methodType->getParams(); + transposeResult = methodType->getResult(); + } + + // Get the original function's result type. + // The original result type is always equal to the type of the last + // parameter of the transpose function type. + auto originalResult = transposeParams.back().getPlainType(); + + // Get transposed result types. + // The transpose function result type may be a singular type or a tuple type. + SmallVector transposeResultTypes; + if (auto transposeResultTupleType = transposeResult->getAs()) { + transposeResultTypes.append(transposeResultTupleType->getElements().begin(), + transposeResultTupleType->getElements().end()); + } else { + transposeResultTypes.push_back(transposeResult); + } + + // Get the `Self` type, if the transpose function type is curried. + // - If `self` is a linearity parameter, use the first transpose result type. + // - Otherwise, use the first transpose parameter type. + unsigned transposeResultTypesIndex = 0; + Type selfType; + if (isCurried && wrtSelf) { + selfType = transposeResultTypes.front().getType(); + transposeResultTypesIndex++; + } else if (isCurried) { + selfType = transposeFnType->getParams().front().getPlainType(); + } + + // Get the original function's parameters. + SmallVector originalParams; + // The number of original parameters is equal to the sum of: + // - The number of original non-transposed parameters. + // - This is the number of transpose parameters minus one. All transpose + // parameters come from the original function, except the last parameter + // (the transposed original result). + // - The number of original transposed parameters. + // - This is the number of linearity parameters. + unsigned originalParameterCount = + transposeParams.size() - 1 + linearParamIndices->getNumIndices(); + // Iterate over all original parameter indices. + for (auto i : range(originalParameterCount)) { + // Skip `self` parameter if `self` is a linearity parameter. + // The `self` is handled specially later to form a curried function type. + bool isSelfParameterAndWrtSelf = + wrtSelf && i == linearParamIndices->getCapacity() - 1; + if (isSelfParameterAndWrtSelf) + continue; + // If `i` is a linearity parameter index, the next original parameter is + // the next transpose result. + if (linearParamIndices->contains(i)) { + auto resultType = + transposeResultTypes[transposeResultTypesIndex++].getType(); + originalParams.push_back(AnyFunctionType::Param(resultType)); + } + // Otherwise, the next original parameter is the next transpose parameter. + else { + originalParams.push_back(transposeParams[transposeParamsIndex++]); + } + } + + // Compute the original function type. + AnyFunctionType *originalType; + // If the transpose type is curried, the original function type is: + // `(Self) -> () -> `. + if (isCurried) { + assert(selfType && "`Self` type should be resolved"); + originalType = makeFunctionType(originalParams, originalResult, nullptr); + originalType = + makeFunctionType(AnyFunctionType::Param(selfType), originalType, + transposeFnType->getOptGenericSignature()); + } + // Otherwise, the original function type is simply: + // `() -> `. + else { + originalType = makeFunctionType(originalParams, originalResult, + transposeFnType->getOptGenericSignature()); + } + return originalType; +} + + + /// Given a `@differentiable` attribute, attempts to resolve the original /// `AbstractFunctionDecl` for which it is registered, using the declaration /// on which it is actually declared. On error, emits diagnostic and returns @@ -3831,7 +3929,7 @@ bool checkIfDifferentiableProgrammingEnabled( return false; } -llvm::Expected DifferentiableAttributeTypeCheckRequest::evaluate( +IndexSubset *DifferentiableAttributeTypeCheckRequest::evaluate( Evaluator &evaluator, DifferentiableAttr *attr) const { // Skip type-checking for implicit `@differentiable` attributes. We currently // assume that all implicit `@differentiable` attributes are valid. @@ -3970,6 +4068,10 @@ llvm::Expected DifferentiableAttributeTypeCheckRequest::evaluate( return nullptr; } getterDecl->getAttrs().add(newAttr); + // Register derivative function configuration. + auto *resultIndices = IndexSubset::get(ctx, 1, {0}); + getterDecl->addDerivativeFunctionConfiguration( + {resolvedDiffParamIndices, resultIndices, derivativeGenSig}); return resolvedDiffParamIndices; } // Reject duplicate `@differentiable` attributes. @@ -4341,6 +4443,12 @@ static bool typeCheckDerivativeAttr(ASTContext &Ctx, Decl *D, return true; } + // Register derivative function configuration. + auto *resultIndices = IndexSubset::get(Ctx, 1, {0}); + originalAFD->addDerivativeFunctionConfiguration( + {resolvedDiffParamIndices, resultIndices, + derivative->getGenericSignature()}); + return false; } @@ -4348,3 +4456,365 @@ void AttributeChecker::visitDerivativeAttr(DerivativeAttr *attr) { if (typeCheckDerivativeAttr(Ctx, D, attr)) attr->setInvalid(); } + +/// Returns true if the given type's `TangentVector` is equal to itself in the +/// given module. +static bool tangentVectorEqualsSelf(Type type, DeclContext *DC) { + assert(conformsToDifferentiable(type, DC)); + auto &ctx = type->getASTContext(); + auto *differentiableProto = + ctx.getProtocol(KnownProtocolKind::Differentiable); + auto conf = TypeChecker::conformsToProtocol( + type, differentiableProto, DC, + ConformanceCheckFlags::InExpression); + auto tanType = conf.getTypeWitnessByName(type, ctx.Id_TangentVector); + return type->getCanonicalType() == tanType->getCanonicalType(); +}; + + +// Computes the linearity parameter indices from the given parsed linearity +// parameters for the given transpose function. On error, emits diagnostics and +// returns `nullptr`. +// +// The attribute location is used in diagnostics. +static IndexSubset * +computeLinearityParameters(ArrayRef parsedLinearParams, + AbstractFunctionDecl *transposeFunction, + SourceLoc attrLoc) { + auto &ctx = transposeFunction->getASTContext(); + auto &diags = ctx.Diags; + + // Get the transpose function type. + auto *transposeFunctionType = + transposeFunction->getInterfaceType()->castTo(); + bool isCurried = transposeFunctionType->getResult()->is(); + + // Get transposed result types. + // The transpose function result type may be a singular type or a tuple type. + ArrayRef transposeResultTypes; + auto transposeResultType = transposeFunctionType->getResult(); + if (isCurried) + transposeResultType = + transposeResultType->castTo()->getResult(); + if (auto resultTupleType = transposeResultType->getAs()) { + transposeResultTypes = resultTupleType->getElements(); + } else { + transposeResultTypes = ArrayRef(transposeResultType); + } + + // If `self` is a linearity parameter, the transpose function must be static. + auto isStaticMethod = transposeFunction->isStatic(); + bool wrtSelf = false; + if (!parsedLinearParams.empty()) + wrtSelf = parsedLinearParams.front().getKind() == + ParsedAutoDiffParameter::Kind::Self; + if (wrtSelf && !isStaticMethod) { + diags.diagnose(attrLoc, diag::transpose_attr_wrt_self_must_be_static); + return nullptr; + } + + // Build linearity parameter indices from parsed linearity parameters. + auto numUncurriedParams = transposeFunctionType->getNumParams(); + if (isCurried) { + auto *resultFnType = + transposeFunctionType->getResult()->castTo(); + numUncurriedParams += resultFnType->getNumParams(); + } + auto numParams = + numUncurriedParams + parsedLinearParams.size() - 1 - (unsigned)wrtSelf; + SmallBitVector parameterBits(numParams); + int lastIndex = -1; + for (unsigned i : indices(parsedLinearParams)) { + auto paramLoc = parsedLinearParams[i].getLoc(); + switch (parsedLinearParams[i].getKind()) { + case ParsedAutoDiffParameter::Kind::Named: { + diags.diagnose(paramLoc, diag::transpose_attr_cannot_use_named_wrt_params, + parsedLinearParams[i].getName()); + return nullptr; + } + case ParsedAutoDiffParameter::Kind::Self: { + // 'self' can only be the first in the list. + if (i > 0) { + diags.diagnose(paramLoc, diag::diff_params_clause_self_must_be_first); + return nullptr; + } + parameterBits.set(parameterBits.size() - 1); + break; + } + case ParsedAutoDiffParameter::Kind::Ordered: { + auto index = parsedLinearParams[i].getIndex(); + if (index >= numParams) { + diags.diagnose(paramLoc, + diag::diff_params_clause_param_index_out_of_range); + return nullptr; + } + // Parameter names must be specified in the original order. + if ((int)index <= lastIndex) { + diags.diagnose(paramLoc, + diag::diff_params_clause_params_not_original_order); + return nullptr; + } + parameterBits.set(index); + lastIndex = index; + break; + } + } + } + return IndexSubset::get(ctx, parameterBits); +} + +// Checks if the given linearity parameter types are valid for the given +// original function in the given derivative generic environment and module +// context. Returns true on error. +// +// The parsed differentiability parameters and attribute location are used in +// diagnostics. +static bool checkLinearityParameters( + AbstractFunctionDecl *originalAFD, + SmallVector linearParams, + GenericEnvironment *derivativeGenEnv, ModuleDecl *module, + ArrayRef parsedLinearParams, SourceLoc attrLoc) { + auto &ctx = originalAFD->getASTContext(); + auto &diags = ctx.Diags; + + // Check that linearity parameters have allowed types. + for (unsigned i : range(linearParams.size())) { + auto linearParamType = linearParams[i].getPlainType(); + if (!linearParamType->hasTypeParameter()) + linearParamType = linearParamType->mapTypeOutOfContext(); + if (derivativeGenEnv) + linearParamType = derivativeGenEnv->mapTypeIntoContext(linearParamType); + else + linearParamType = originalAFD->mapTypeIntoContext(linearParamType); + SourceLoc loc = + parsedLinearParams.empty() ? attrLoc : parsedLinearParams[i].getLoc(); + // Parameter must conform to `Differentiable` and satisfy + // `Self == Self.TangentVector`. + if (!conformsToDifferentiable(linearParamType, originalAFD) || + !tangentVectorEqualsSelf(linearParamType, originalAFD)) { + diags.diagnose(loc, + diag::transpose_attr_invalid_linearity_parameter_or_result, + linearParamType.getString(), /*isParameter*/ true); + return true; + } + } + return false; +} + +// Given a transpose function type where `self` is a linearity parameter, +// sets `staticSelfType` and `instanceSelfType` and returns true if they are +// equals. Otherwise, returns false. +static bool +doTransposeStaticAndInstanceSelfTypesMatch(AnyFunctionType *transposeType, + Type &staticSelfType, + Type &instanceSelfType) { + // Transpose type should have the form: + // `(StaticSelf) -> (...) -> (InstanceSelf, ...)`. + auto methodType = transposeType->getResult()->castTo(); + auto transposeResult = methodType->getResult(); + + // Get transposed result types. + // The transpose function result type may be a singular type or a tuple type. + SmallVector transposeResultTypes; + if (auto transposeResultTupleType = transposeResult->getAs()) { + transposeResultTypes.append(transposeResultTupleType->getElements().begin(), + transposeResultTupleType->getElements().end()); + } else { + transposeResultTypes.push_back(transposeResult); + } + assert(!transposeResultTypes.empty()); + + // Get the static and instance `Self` types. + staticSelfType = transposeType->getParams() + .front() + .getPlainType() + ->getMetatypeInstanceType(); + instanceSelfType = transposeResultTypes.front().getType(); + + // Return true if static and instance `Self` types are equal. + return staticSelfType->isEqual(instanceSelfType); +} + +void AttributeChecker::visitTransposeAttr(TransposeAttr *attr) { + auto *transpose = cast(D); + auto lookupConformance = + LookUpConformanceInModule(D->getDeclContext()->getParentModule()); + auto originalName = attr->getOriginalFunctionName(); + auto *transposeInterfaceType = + transpose->getInterfaceType()->castTo(); + bool isCurried = transposeInterfaceType->getResult()->is(); + + // Get the linearity parameter indices. + auto *linearParamIndices = attr->getParameterIndices(); + + // Get the parsed linearity parameter indices, which have not yet been + // resolved. Parsed linearity parameter indices are defined only for parsed + // attributes. + auto parsedLinearParams = attr->getParsedParameters(); + + // If linearity parameter indices are not resolved, compute them. + if (!linearParamIndices) + linearParamIndices = computeLinearityParameters( + parsedLinearParams, transpose, attr->getLocation()); + if (!linearParamIndices) { + attr->setInvalid(); + return; + } + + // Diagnose empty linearity parameter indices. This occurs when no `wrt:` + // clause is declared and no linearity parameters can be inferred. + if (linearParamIndices->isEmpty()) { + diagnoseAndRemoveAttr(attr, + diag::diff_params_clause_no_inferred_parameters); + return; + } + + bool wrtSelf = false; + if (!parsedLinearParams.empty()) + wrtSelf = parsedLinearParams.front().getKind() == + ParsedAutoDiffParameter::Kind::Self; + + // If the transpose function is curried and `self` is a linearity parameter, + // check that the instance and static `Self` types are equal. + Type staticSelfType, instanceSelfType; + if (isCurried && wrtSelf) { + bool doSelfTypesMatch = doTransposeStaticAndInstanceSelfTypesMatch( + transposeInterfaceType, staticSelfType, instanceSelfType); + if (!doSelfTypesMatch) { + diagnose(attr->getLocation(), + diag::transpose_attr_wrt_self_must_be_static); + diagnose(attr->getLocation(), + diag::transpose_attr_wrt_self_self_type_mismatch_note, + staticSelfType, instanceSelfType); + attr->setInvalid(); + return; + } + } + + auto *expectedOriginalFnType = getTransposeOriginalFunctionType( + transposeInterfaceType, linearParamIndices, wrtSelf); + + // `R` result type must conform to `Differentiable` and satisfy + // `Self == Self.TangentVector`. + auto expectedOriginalResultType = expectedOriginalFnType->getResult(); + if (isCurried) + expectedOriginalResultType = + expectedOriginalResultType->castTo()->getResult(); + if (expectedOriginalResultType->hasTypeParameter()) + expectedOriginalResultType = transpose->mapTypeIntoContext( + expectedOriginalResultType); + if (!conformsToDifferentiable(expectedOriginalResultType, transpose) || + !tangentVectorEqualsSelf(expectedOriginalResultType, transpose)) { + diagnoseAndRemoveAttr( + attr, diag::transpose_attr_invalid_linearity_parameter_or_result, + expectedOriginalResultType.getString(), /*isParameter*/ false); + return; + } + + // Returns true if the generic parameters in `source` satisfy the generic + // requirements in `target`. + std::function + checkGenericSignatureSatisfied = [&](GenericSignature source, + GenericSignature target) { + // If target is null, then its requirements are satisfied. + if (!target) + return true; + // If source is null but target is not null, then target's + // requirements are not satisfied. + if (!source) + return false; + // Check if target's requirements are satisfied by source. + // Cancel diagnostics using `DiagnosticTransaction`. + // Diagnostics should not be emitted because this function is used to + // check candidates; if no candidates match, a separate diagnostic will + // be produced. + DiagnosticTransaction transaction(Ctx.Diags); + SWIFT_DEFER { transaction.abort(); }; + return TypeChecker::checkGenericArguments( + transpose, originalName.Loc.getBaseNameLoc(), + originalName.Loc.getBaseNameLoc(), Type(), + source->getGenericParams(), target->getRequirements(), + [](SubstitutableType *dependentType) { + return Type(dependentType); + }, + lookupConformance, None) == RequirementCheckResult::Success; + }; + + auto isValidOriginal = [&](AbstractFunctionDecl *originalCandidate) { + return checkFunctionSignature( + cast(expectedOriginalFnType->getCanonicalType()), + originalCandidate->getInterfaceType()->getCanonicalType(), + checkGenericSignatureSatisfied); + }; + + auto noneValidDiagnostic = [&]() { + diagnose(originalName.Loc, + diag::autodiff_attr_original_decl_none_valid_found, + originalName.Name, expectedOriginalFnType); + }; + auto ambiguousDiagnostic = [&]() { + diagnose(originalName.Loc, diag::attr_ambiguous_reference_to_decl, + originalName.Name, attr->getAttrName()); + }; + auto notFunctionDiagnostic = [&]() { + diagnose(originalName.Loc, + diag::autodiff_attr_original_decl_invalid_kind, + originalName.Name); + }; + std::function invalidTypeContextDiagnostic = [&]() { + diagnose(originalName.Loc, + diag::autodiff_attr_original_decl_not_same_type_context, + originalName.Name); + }; + + // Returns true if the transpose function and original function candidate are + // defined in compatible type contexts. If the transpose function and the + // original function candidate have different parents, return false. + std::function hasValidTypeContext = + [&](AbstractFunctionDecl *decl) { return true; }; + + auto resolution = TypeResolution::forContextual(transpose->getDeclContext()); + Type baseType; + if (attr->getBaseTypeRepr()) + baseType = resolution.resolveType(attr->getBaseTypeRepr(), None); + auto lookupOptions = + (attr->getBaseTypeRepr() ? defaultMemberLookupOptions + : defaultUnqualifiedLookupOptions) | + NameLookupFlags::IgnoreAccessControl; + auto transposeTypeCtx = transpose->getInnermostTypeContext(); + if (!transposeTypeCtx) transposeTypeCtx = transpose->getParent(); + assert(transposeTypeCtx); + + // Look up original function. + auto funcLoc = originalName.Loc.getBaseNameLoc(); + if (attr->getBaseTypeRepr()) + funcLoc = attr->getBaseTypeRepr()->getLoc(); + auto *originalAFD = findAbstractFunctionDecl( + originalName.Name, funcLoc, baseType, transposeTypeCtx, isValidOriginal, + noneValidDiagnostic, ambiguousDiagnostic, notFunctionDiagnostic, + lookupOptions, hasValidTypeContext, invalidTypeContextDiagnostic); + if (!originalAFD) { + attr->setInvalid(); + return; + } + + attr->setOriginalFunction(originalAFD); + + // Get the linearity parameter types. + SmallVector linearParams; + expectedOriginalFnType->getSubsetParameters(linearParamIndices, linearParams, + /*reverseCurryLevels*/ true); + + // Check if linearity parameter indices are valid. + if (checkLinearityParameters(originalAFD, linearParams, + transpose->getGenericEnvironment(), + transpose->getModuleContext(), + parsedLinearParams, attr->getLocation())) { + D->getAttrs().removeAttribute(attr); + attr->setInvalid(); + return; + } + + // Set the resolved linearity parameter indices in the attribute. + attr->setParameterIndices(linearParamIndices); +} diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index c6202c8f838c4..fe79350f15fa7 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -4197,7 +4197,7 @@ ForcedCheckedCastExpr *swift::findForcedDowncast(ASTContext &ctx, Expr *expr) { return nullptr; } -llvm::Expected +bool IsCallableNominalTypeRequest::evaluate(Evaluator &evaluator, CanType ty, DeclContext *dc) const { auto options = defaultMemberLookupOptions; @@ -4269,7 +4269,7 @@ static bool checkForDynamicAttribute(CanType ty, return false; } -llvm::Expected +bool HasDynamicMemberLookupAttributeRequest::evaluate(Evaluator &evaluator, CanType ty) const { return checkForDynamicAttribute(ty, [](Type type) { @@ -4277,7 +4277,7 @@ HasDynamicMemberLookupAttributeRequest::evaluate(Evaluator &evaluator, }); } -llvm::Expected +bool HasDynamicCallableAttributeRequest::evaluate(Evaluator &evaluator, CanType ty) const { return checkForDynamicAttribute(ty, [](Type type) { diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 055a12f91df27..79dee1f60add4 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -231,7 +231,7 @@ static bool canSkipCircularityCheck(NominalTypeDecl *decl) { return decl->hasClangNode() || decl->wasDeserialized(); } -llvm::Expected +bool HasCircularInheritanceRequest::evaluate(Evaluator &evaluator, ClassDecl *decl) const { if (canSkipCircularityCheck(decl) || !decl->hasSuperclass()) @@ -246,10 +246,10 @@ HasCircularInheritanceRequest::evaluate(Evaluator &evaluator, llvm::handleAllErrors(result.takeError(), [](const Error &E) {}); return true; } - return result; + return result.get(); } -llvm::Expected +bool HasCircularInheritedProtocolsRequest::evaluate(Evaluator &evaluator, ProtocolDecl *decl) const { if (canSkipCircularityCheck(decl)) @@ -277,7 +277,7 @@ HasCircularInheritedProtocolsRequest::evaluate(Evaluator &evaluator, return false; } -llvm::Expected +bool HasCircularRawValueRequest::evaluate(Evaluator &evaluator, EnumDecl *decl) const { if (canSkipCircularityCheck(decl) || !decl->hasRawType()) @@ -294,7 +294,7 @@ HasCircularRawValueRequest::evaluate(Evaluator &evaluator, llvm::handleAllErrors(result.takeError(), [](const Error &E) {}); return true; } - return result; + return result.get(); } namespace { @@ -399,7 +399,7 @@ static bool doesAccessorNeedDynamicAttribute(AccessorDecl *accessor) { llvm_unreachable("covered switch"); } -llvm::Expected +CtorInitializerKind InitKindRequest::evaluate(Evaluator &evaluator, ConstructorDecl *decl) const { auto &diags = decl->getASTContext().Diags; @@ -470,7 +470,7 @@ InitKindRequest::evaluate(Evaluator &evaluator, ConstructorDecl *decl) const { return CtorInitializerKind::Designated; } -llvm::Expected +bool ProtocolRequiresClassRequest::evaluate(Evaluator &evaluator, ProtocolDecl *decl) const { // Quick check: @objc protocols require a class. @@ -503,7 +503,7 @@ ProtocolRequiresClassRequest::evaluate(Evaluator &evaluator, return false; } -llvm::Expected +bool ExistentialConformsToSelfRequest::evaluate(Evaluator &evaluator, ProtocolDecl *decl) const { // If it's not @objc, it conforms to itself only if it has a self-conformance @@ -531,7 +531,7 @@ ExistentialConformsToSelfRequest::evaluate(Evaluator &evaluator, return true; } -llvm::Expected +bool ExistentialTypeSupportedRequest::evaluate(Evaluator &evaluator, ProtocolDecl *decl) const { // ObjC protocols can always be existential. @@ -559,7 +559,7 @@ ExistentialTypeSupportedRequest::evaluate(Evaluator &evaluator, return true; } -llvm::Expected +bool IsFinalRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const { if (isa(decl)) return decl->getAttrs().hasAttribute(); @@ -655,7 +655,7 @@ IsFinalRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const { return false; } -llvm::Expected +bool IsStaticRequest::evaluate(Evaluator &evaluator, FuncDecl *decl) const { if (auto *accessor = dyn_cast(decl)) return accessor->getStorage()->isStatic(); @@ -685,7 +685,7 @@ IsStaticRequest::evaluate(Evaluator &evaluator, FuncDecl *decl) const { return result; } -llvm::Expected +bool IsDynamicRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const { // If we can't infer dynamic here, don't. if (!DeclAttribute::canAttributeAppearOnDecl(DAK_Dynamic, decl)) @@ -745,7 +745,7 @@ IsDynamicRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const { return false; } -llvm::Expected> +ArrayRef RequirementSignatureRequest::evaluate(Evaluator &evaluator, ProtocolDecl *proto) const { ASTContext &ctx = proto->getASTContext(); @@ -794,7 +794,7 @@ RequirementSignatureRequest::evaluate(Evaluator &evaluator, return reqSignature->getRequirements(); } -llvm::Expected +Type DefaultDefinitionTypeRequest::evaluate(Evaluator &evaluator, AssociatedTypeDecl *assocType) const { if (assocType->Resolver) { @@ -813,7 +813,7 @@ DefaultDefinitionTypeRequest::evaluate(Evaluator &evaluator, return Type(); } -llvm::Expected +bool NeedsNewVTableEntryRequest::evaluate(Evaluator &evaluator, AbstractFunctionDecl *decl) const { auto *dc = decl->getDeclContext(); @@ -973,22 +973,22 @@ swift::computeAutomaticEnumValueKind(EnumDecl *ED) { } } -llvm::Expected +evaluator::SideEffect EnumRawValuesRequest::evaluate(Evaluator &eval, EnumDecl *ED, TypeResolutionStage stage) const { Type rawTy = ED->getRawType(); if (!rawTy) { - return true; + return std::make_tuple<>(); } if (!computeAutomaticEnumValueKind(ED)) { - return true; + return std::make_tuple<>(); } if (ED->getGenericEnvironmentOfContext() != nullptr) rawTy = ED->mapTypeIntoContext(rawTy); if (rawTy->hasError()) - return true; + return std::make_tuple<>(); // Check the raw values of the cases. LiteralExpr *prevValue = nullptr; @@ -1017,7 +1017,7 @@ EnumRawValuesRequest::evaluate(Evaluator &eval, EnumDecl *ED, valueKind = computeAutomaticEnumValueKind(ED); if (!valueKind) { elt->setInvalid(); - return true; + return std::make_tuple<>(); } } @@ -1107,7 +1107,7 @@ EnumRawValuesRequest::evaluate(Evaluator &eval, EnumDecl *ED, diag::enum_raw_value_incrementing_from_zero); } } - return true; + return std::make_tuple<>(); } const ConstructorDecl * @@ -1336,7 +1336,7 @@ void swift::validatePrecedenceGroup(PrecedenceGroupDecl *PGD) { checkPrecedenceCircularity(Diags, PGD); } -llvm::Expected ValidatePrecedenceGroupRequest::evaluate( +PrecedenceGroupDecl * ValidatePrecedenceGroupRequest::evaluate( Evaluator &eval, PrecedenceGroupDescriptor descriptor) const { if (auto *group = lookupPrecedenceGroup(descriptor)) { validatePrecedenceGroup(group); @@ -1398,7 +1398,7 @@ bool swift::checkDesignatedTypes(OperatorDecl *OD, /// This establishes key invariants, such as an InfixOperatorDecl's /// reference to its precedence group and the transitive validity of that /// group. -llvm::Expected +PrecedenceGroupDecl * OperatorPrecedenceGroupRequest::evaluate(Evaluator &evaluator, InfixOperatorDecl *IOD) const { auto enableOperatorDesignatedTypes = @@ -1464,7 +1464,7 @@ OperatorPrecedenceGroupRequest::evaluate(Evaluator &evaluator, return group; } -llvm::Expected +SelfAccessKind SelfAccessKindRequest::evaluate(Evaluator &evaluator, FuncDecl *FD) const { if (FD->getAttrs().getAttribute(true)) { if (!FD->isInstanceMember() || !FD->getDeclContext()->hasValueSemantics()) { @@ -1597,7 +1597,7 @@ static ParamDecl *getOriginalParamFromAccessor(AbstractStorageDecl *storage, return subscriptParams->get(index - startIndex); } -llvm::Expected +bool IsImplicitlyUnwrappedOptionalRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const { TypeRepr *TyR = nullptr; @@ -1670,7 +1670,7 @@ IsImplicitlyUnwrappedOptionalRequest::evaluate(Evaluator &evaluator, } /// Validate the underlying type of the given typealias. -llvm::Expected +Type UnderlyingTypeRequest::evaluate(Evaluator &evaluator, TypeAliasDecl *typeAlias) const { TypeResolutionOptions options((typeAlias->getGenericParams() @@ -1702,7 +1702,7 @@ UnderlyingTypeRequest::evaluate(Evaluator &evaluator, /// Bind the given function declaration, which declares an operator, to the /// corresponding operator declaration. -llvm::Expected +OperatorDecl * FunctionOperatorRequest::evaluate(Evaluator &evaluator, FuncDecl *FD) const { auto &C = FD->getASTContext(); auto &diags = C.Diags; @@ -1893,7 +1893,7 @@ static Type buildAddressorResultType(AccessorDecl *addressor, return valueType->wrapInPointer(pointerKind); } -llvm::Expected +Type ResultTypeRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const { auto &ctx = decl->getASTContext(); @@ -1946,7 +1946,7 @@ ResultTypeRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const { resultTyRepr, TypeResolverContext::FunctionResult); } -llvm::Expected +ParamSpecifier ParamSpecifierRequest::evaluate(Evaluator &evaluator, ParamDecl *param) const { auto *dc = param->getDeclContext(); @@ -2071,7 +2071,7 @@ static Type validateParameterType(ParamDecl *decl) { return TL.getType(); } -llvm::Expected +Type InterfaceTypeRequest::evaluate(Evaluator &eval, ValueDecl *D) const { auto &Context = D->getASTContext(); @@ -2278,7 +2278,7 @@ InterfaceTypeRequest::evaluate(Evaluator &eval, ValueDecl *D) const { } } -llvm::Expected +NamedPattern * NamingPatternRequest::evaluate(Evaluator &evaluator, VarDecl *VD) const { auto &Context = VD->getASTContext(); auto *PBD = VD->getParentPatternBinding(); @@ -2336,7 +2336,7 @@ NamingPatternRequest::evaluate(Evaluator &evaluator, VarDecl *VD) const { return namingPattern; } -llvm::Expected +DeclRange EmittedMembersRequest::evaluate(Evaluator &evaluator, ClassDecl *CD) const { if (!CD->getParentSourceFile()) @@ -2437,7 +2437,7 @@ static bool isNonGenericTypeAliasType(Type type) { return false; } -llvm::Expected +Type ExtendedTypeRequest::evaluate(Evaluator &eval, ExtensionDecl *ext) const { auto error = [&ext]() { ext->setInvalid(); diff --git a/lib/Sema/TypeCheckDeclObjC.cpp b/lib/Sema/TypeCheckDeclObjC.cpp index 25e354373fe27..d6855b647498c 100644 --- a/lib/Sema/TypeCheckDeclObjC.cpp +++ b/lib/Sema/TypeCheckDeclObjC.cpp @@ -1283,8 +1283,7 @@ static void markAsObjC(ValueDecl *D, ObjCReason reason, Optional errorConvention); -llvm::Expected -IsObjCRequest::evaluate(Evaluator &evaluator, ValueDecl *VD) const { +bool IsObjCRequest::evaluate(Evaluator &evaluator, ValueDecl *VD) const { auto dc = VD->getDeclContext(); Optional isObjC; if (dc->getSelfClassDecl() && !isa(VD)) { diff --git a/lib/Sema/TypeCheckDeclOverride.cpp b/lib/Sema/TypeCheckDeclOverride.cpp index afe783e5c7f12..027044e2aac05 100644 --- a/lib/Sema/TypeCheckDeclOverride.cpp +++ b/lib/Sema/TypeCheckDeclOverride.cpp @@ -1453,6 +1453,7 @@ namespace { UNINTERESTING_ATTR(Differentiable) UNINTERESTING_ATTR(Derivative) UNINTERESTING_ATTR(Transpose) + UNINTERESTING_ATTR(NoDerivative) // These can't appear on overridable declarations. UNINTERESTING_ATTR(Prefix) @@ -1967,7 +1968,7 @@ computeOverriddenAssociatedTypes(AssociatedTypeDecl *assocType) { return overriddenAssocTypes; } -llvm::Expected> +llvm::TinyPtrVector OverriddenDeclsRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const { // Value to return in error cases auto noResults = llvm::TinyPtrVector(); @@ -2082,9 +2083,8 @@ OverriddenDeclsRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const { OverrideCheckingAttempt::PerfectMatch); } -llvm::Expected -IsABICompatibleOverrideRequest::evaluate(Evaluator &evaluator, - ValueDecl *decl) const { +bool IsABICompatibleOverrideRequest::evaluate(Evaluator &evaluator, + ValueDecl *decl) const { auto base = decl->getOverriddenDecl(); if (!base) return false; diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index 2f18f2d829884..e7cc9f2707b0c 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -37,6 +37,7 @@ #include "swift/AST/GenericSignatureBuilder.h" #include "swift/AST/Initializer.h" #include "swift/AST/NameLookup.h" +#include "swift/AST/NameLookupRequests.h" #include "swift/AST/PrettyStackTrace.h" #include "swift/AST/PropertyWrappers.h" #include "swift/AST/ProtocolConformance.h" @@ -336,7 +337,7 @@ static void checkInheritanceClause( static void installCodingKeysIfNecessary(NominalTypeDecl *NTD) { auto req = ResolveImplicitMemberRequest{NTD, ImplicitMemberAction::ResolveCodingKeys}; - (void)evaluateOrDefault(NTD->getASTContext().evaluator, req, false); + (void)evaluateOrDefault(NTD->getASTContext().evaluator, req, {}); } // Check for static properties that produce empty option sets @@ -418,25 +419,78 @@ static void checkGenericParams(GenericContext *ownerCtx) { [](Requirement, RequirementRepr *) { return false; }); } -/// Check whether \c current is a redeclaration. -static void checkRedeclaration(ASTContext &ctx, ValueDecl *current) { - // If we've already checked this declaration, don't do it again. - if (current->alreadyCheckedRedeclaration()) +template +static void checkOperatorOrPrecedenceGroupRedeclaration( + T *decl, Diag<> diagID, Diag<> noteID, + llvm::function_ref(OperatorLookupDescriptor)> + lookupOthers) { + if (decl->isInvalid()) return; - // Make sure we don't do this checking again. - current->setCheckedRedeclaration(true); + auto *currentFile = decl->getDeclContext()->getParentSourceFile(); + assert(currentFile); + + auto *module = currentFile->getParentModule(); + auto &ctx = module->getASTContext(); + auto desc = OperatorLookupDescriptor::forModule(module, decl->getName(), + /*cascades*/ true, + /*diagLoc*/ SourceLoc()); + auto otherDecls = lookupOthers(desc); + for (auto *other : otherDecls) { + if (other == decl || other->isInvalid()) + continue; + + // Emit a redeclaration error if the two declarations occur in the same + // source file. We currently allow redeclarations across source files to + // allow the user to shadow operator decls from imports, as we currently + // favor those decls over ones from other files. + // FIXME: Once we prefer operator decls from the same module, start + // diagnosing redeclarations across files. + if (currentFile == other->getDeclContext()->getParentSourceFile()) { + // Make sure we get the diagnostic ordering to be sensible. + if (decl->getLoc().isValid() && other->getLoc().isValid() && + ctx.SourceMgr.isBeforeInBuffer(decl->getLoc(), other->getLoc())) { + std::swap(decl, other); + } + ctx.Diags.diagnose(decl, diagID); + ctx.Diags.diagnose(other, noteID); + decl->setInvalid(); + return; + } + } +} + +static void checkRedeclaration(OperatorDecl *op) { + checkOperatorOrPrecedenceGroupRedeclaration( + op, diag::operator_redeclared, diag::previous_operator_decl, + [&](OperatorLookupDescriptor desc) { + DirectOperatorLookupRequest req{desc, op->getFixity()}; + return evaluateOrDefault(op->getASTContext().evaluator, req, {}); + }); +} + +static void checkRedeclaration(PrecedenceGroupDecl *group) { + checkOperatorOrPrecedenceGroupRedeclaration( + group, diag::precedence_group_redeclared, + diag::previous_precedence_group_decl, [&](OperatorLookupDescriptor desc) { + DirectPrecedenceGroupLookupRequest req{desc}; + return evaluateOrDefault(group->getASTContext().evaluator, req, {}); + }); +} +/// Check whether \c current is a redeclaration. +evaluator::SideEffect +CheckRedeclarationRequest::evaluate(Evaluator &eval, ValueDecl *current) const { // Ignore invalid and anonymous declarations. if (current->isInvalid() || !current->hasName()) - return; + return std::make_tuple<>(); // If this declaration isn't from a source file, don't check it. // FIXME: Should restrict this to the source file we care about. DeclContext *currentDC = current->getDeclContext(); SourceFile *currentFile = currentDC->getParentSourceFile(); if (!currentFile || currentDC->isLocalContext()) - return; + return std::make_tuple<>(); ReferencedNameTracker *tracker = currentFile->getReferencedNameTracker(); bool isCascading = (current->getFormalAccess() > AccessLevel::FilePrivate); @@ -465,6 +519,7 @@ static void checkRedeclaration(ASTContext &ctx, ValueDecl *current) { OverloadSignature currentSig = current->getOverloadSignature(); CanType currentSigType = current->getOverloadSignatureType(); ModuleDecl *currentModule = current->getModuleContext(); + auto &ctx = current->getASTContext(); for (auto other : otherDefinitions) { // Skip invalid declarations and ourselves. // @@ -666,10 +721,11 @@ static void checkRedeclaration(ASTContext &ctx, ValueDecl *current) { // set this at the beginning of the function, but we might have swapped // the decls for diagnostics; so ensure we also set this for the actual // decl we diagnosed on. - current->setCheckedRedeclaration(true); + current->setCheckedRedeclaration(); break; } } + return std::make_tuple<>(); } static Optional @@ -723,9 +779,8 @@ static void checkDefaultArguments(ParameterList *params) { (void)param->getTypeCheckedDefaultExpr(); } -llvm::Expected -DefaultArgumentExprRequest::evaluate(Evaluator &evaluator, - ParamDecl *param) const { +Expr *DefaultArgumentExprRequest::evaluate(Evaluator &evaluator, + ParamDecl *param) const { if (param->getDefaultArgumentKind() == DefaultArgumentKind::Inherited) { // Inherited default arguments don't have expressions, but we need to // perform a couple of semantic checks to make sure they're valid. @@ -757,7 +812,7 @@ DefaultArgumentExprRequest::evaluate(Evaluator &evaluator, return initExpr; } -llvm::Expected +Initializer * DefaultArgumentInitContextRequest::evaluate(Evaluator &eval, ParamDecl *param) const { auto &ctx = param->getASTContext(); @@ -1191,11 +1246,13 @@ class DeclChecker : public DeclVisitor { if (auto VD = dyn_cast(decl)) { auto &Context = getASTContext(); TypeChecker::checkForForbiddenPrefix(Context, VD->getBaseName()); - - checkRedeclaration(Context, VD); // Force some requests, which can produce diagnostics. + // Check redeclaration. + (void) evaluateOrDefault(decl->getASTContext().evaluator, + CheckRedeclarationRequest{VD}, {}); + // Compute access level. (void) VD->getFormalAccess(); @@ -1244,6 +1301,7 @@ class DeclChecker : public DeclVisitor { void visitOperatorDecl(OperatorDecl *OD) { TypeChecker::checkDeclAttributes(OD); + checkRedeclaration(OD); auto &Ctx = OD->getASTContext(); if (auto *IOD = dyn_cast(OD)) { (void)IOD->getPrecedenceGroup(); @@ -1265,6 +1323,7 @@ class DeclChecker : public DeclVisitor { void visitPrecedenceGroupDecl(PrecedenceGroupDecl *PGD) { TypeChecker::checkDeclAttributes(PGD); validatePrecedenceGroup(PGD); + checkRedeclaration(PGD); checkAccessControl(PGD); } diff --git a/lib/Sema/TypeCheckExpr.cpp b/lib/Sema/TypeCheckExpr.cpp index f1350fbeb1b57..896f326c136f8 100644 --- a/lib/Sema/TypeCheckExpr.cpp +++ b/lib/Sema/TypeCheckExpr.cpp @@ -684,7 +684,7 @@ static std::pair lookupDefaultTypeInfoForKnownProtocol( } } -llvm::Expected +Type swift::DefaultTypeRequest::evaluate(Evaluator &evaluator, KnownProtocolKind knownProtocolKind, const DeclContext *dc) const { @@ -782,7 +782,7 @@ static Expr *synthesizeCallerSideDefault(const ParamDecl *param, llvm_unreachable("Unhandled case in switch"); } -llvm::Expected CallerSideDefaultArgExprRequest::evaluate( +Expr *CallerSideDefaultArgExprRequest::evaluate( Evaluator &evaluator, DefaultArgumentExpr *defaultExpr) const { auto *param = defaultExpr->getParamDecl(); auto paramTy = defaultExpr->getType(); @@ -810,9 +810,8 @@ llvm::Expected CallerSideDefaultArgExprRequest::evaluate( return initExpr; } -llvm::Expected -ClosureHasExplicitResultRequest::evaluate(Evaluator &evaluator, - ClosureExpr *closure) const { +bool ClosureHasExplicitResultRequest::evaluate(Evaluator &evaluator, + ClosureExpr *closure) const { // A walker that looks for 'return' statements that aren't // nested within closures or nested declarations. class FindReturns : public ASTWalker { diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp index cb121d0e849dd..b9daf294c21a8 100644 --- a/lib/Sema/TypeCheckGeneric.cpp +++ b/lib/Sema/TypeCheckGeneric.cpp @@ -83,7 +83,7 @@ TypeChecker::gatherGenericParamBindingsText( /// Get the opaque type representing the return type of a declaration, or /// create it if it does not yet exist. -llvm::Expected +OpaqueTypeDecl * OpaqueResultTypeRequest::evaluate(Evaluator &evaluator, ValueDecl *originatingDecl) const { auto *repr = originatingDecl->getOpaqueResultTypeRepr(); @@ -577,7 +577,7 @@ static unsigned getExtendedTypeGenericDepth(ExtensionDecl *ext) { return sig->getGenericParams().back()->getDepth(); } -llvm::Expected +GenericSignature GenericSignatureRequest::evaluate(Evaluator &evaluator, GenericContext *GC) const { // The signature of a Protocol is trivial (Self: TheProtocol) so let's compute @@ -919,7 +919,7 @@ RequirementCheckResult TypeChecker::checkGenericArguments( return RequirementCheckResult::SubstitutionFailure; } -llvm::Expected +Requirement RequirementRequest::evaluate(Evaluator &evaluator, WhereClauseOwner owner, unsigned index, @@ -974,9 +974,8 @@ RequirementRequest::evaluate(Evaluator &evaluator, llvm_unreachable("unhandled kind"); } -llvm::Expected -StructuralTypeRequest::evaluate(Evaluator &evaluator, - TypeAliasDecl *typeAlias) const { +Type StructuralTypeRequest::evaluate(Evaluator &evaluator, + TypeAliasDecl *typeAlias) const { TypeResolutionOptions options((typeAlias->getGenericParams() ? TypeResolverContext::GenericTypeAliasDecl : TypeResolverContext::TypeAliasDecl)); diff --git a/lib/Sema/TypeCheckPattern.cpp b/lib/Sema/TypeCheckPattern.cpp index 5b400d6e946d6..82ce6320e32c6 100644 --- a/lib/Sema/TypeCheckPattern.cpp +++ b/lib/Sema/TypeCheckPattern.cpp @@ -723,8 +723,8 @@ static TypeResolutionOptions applyContextualPatternOptions( return options; } -llvm::Expected PatternTypeRequest::evaluate( - Evaluator &evaluator, ContextualPattern pattern) const { +Type PatternTypeRequest::evaluate(Evaluator &evaluator, + ContextualPattern pattern) const { Pattern *P = pattern.getPattern(); DeclContext *dc = pattern.getDeclContext(); diff --git a/lib/Sema/TypeCheckPropertyWrapper.cpp b/lib/Sema/TypeCheckPropertyWrapper.cpp index 75b56a180b108..7ea20736e331f 100644 --- a/lib/Sema/TypeCheckPropertyWrapper.cpp +++ b/lib/Sema/TypeCheckPropertyWrapper.cpp @@ -28,7 +28,8 @@ using namespace swift; /// The kind of property initializer to look for enum class PropertyWrapperInitKind { - /// An initial-value initializer (i.e. `init(initialValue:)`) + /// An initial-value initializer (i.e. `init(initialValue:)`), which is + /// deprecated. InitialValue, /// An wrapped-value initializer (i.e. `init(wrappedValue:)`) WrappedValue, @@ -327,7 +328,7 @@ static bool isEscapingAutoclosureArgument(const ConstructorDecl *init, return false; } -llvm::Expected +PropertyWrapperTypeInfo PropertyWrapperTypeInfoRequest::evaluate( Evaluator &eval, NominalTypeDecl *nominal) const { // We must have the @propertyWrapper attribute to continue. @@ -404,7 +405,7 @@ PropertyWrapperTypeInfoRequest::evaluate( return result; } -llvm::Expected> +llvm::TinyPtrVector AttachedPropertyWrappersRequest::evaluate(Evaluator &evaluator, VarDecl *var) const { ASTContext &ctx = var->getASTContext(); @@ -519,21 +520,18 @@ AttachedPropertyWrappersRequest::evaluate(Evaluator &evaluator, return result; } -llvm::Expected -AttachedPropertyWrapperTypeRequest::evaluate(Evaluator &evaluator, - VarDecl *var, - unsigned index) const { +Type AttachedPropertyWrapperTypeRequest::evaluate(Evaluator &evaluator, + VarDecl *var, + unsigned index) const { // Find the custom attributes for the attached property wrapper. - llvm::Expected> customAttrVal = - evaluator(AttachedPropertyWrappersRequest{var}); - if (!customAttrVal) - return customAttrVal.takeError(); + llvm::TinyPtrVector customAttrVal = + evaluateOrDefault(evaluator, AttachedPropertyWrappersRequest{var}, {}); // If there isn't an attached property wrapper at this index, we're done. - if (index >= customAttrVal->size()) + if (index >= customAttrVal.size()) return Type(); - auto customAttr = (*customAttrVal)[index]; + auto customAttr = customAttrVal[index]; if (!customAttr) return Type(); @@ -551,15 +549,13 @@ AttachedPropertyWrapperTypeRequest::evaluate(Evaluator &evaluator, return customAttr->getTypeLoc().getType(); } -llvm::Expected +Type PropertyWrapperBackingPropertyTypeRequest::evaluate( - Evaluator &evaluator, VarDecl *var) const { - llvm::Expected rawTypeResult = - evaluator(AttachedPropertyWrapperTypeRequest{var, 0}); - if (!rawTypeResult) - return rawTypeResult; + Evaluator &evaluator, VarDecl *var) const { + Type rawType = + evaluateOrDefault(evaluator, + AttachedPropertyWrapperTypeRequest{var, 0}, Type()); - Type rawType = *rawTypeResult; if (!rawType || rawType->hasError()) return Type(); @@ -684,7 +680,7 @@ static bool isOpaquePlaceholderClosure(const Expr *value) { return false; } -Expr *swift::buildPropertyWrapperInitialValueCall( +Expr *swift::buildPropertyWrapperWrappedValueCall( VarDecl *var, Type backingStorageType, Expr *value, bool ignoreAttributeArgs) { // From the innermost wrapper type out, form init(wrapperValue:) calls. diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index 175652ab3090a..1380baad92f76 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -438,6 +438,11 @@ matchWitnessDifferentiableAttr(DeclContext *dc, ValueDecl *req, } else { witness->getAttrs().add(newAttr); success = true; + // Register derivative function configuration. + auto *resultIndices = IndexSubset::get(ctx, 1, {0}); + witnessAFD->addDerivativeFunctionConfiguration( + {newAttr->getParameterIndices(), resultIndices, + newAttr->getDerivativeGenericSignature()}); } } if (!success) { @@ -5066,7 +5071,7 @@ diagnoseMissingAppendInterpolationMethod(NominalTypeDecl *typeDecl) { } } -llvm::Expected> +SmallVector LookupAllConformancesInContextRequest::evaluate( Evaluator &eval, const DeclContext *DC) const { return DC->getLocalConformances(ConformanceLookupKind::All); @@ -5511,7 +5516,7 @@ swift::findWitnessedObjCRequirements(const ValueDecl *witness, return result; } -llvm::Expected +TypeWitnessAndDecl TypeWitnessRequest::evaluate(Evaluator &eval, NormalProtocolConformance *conformance, AssociatedTypeDecl *requirement) const { @@ -5529,7 +5534,7 @@ TypeWitnessRequest::evaluate(Evaluator &eval, return known->second; } -llvm::Expected +Witness ValueWitnessRequest::evaluate(Evaluator &eval, NormalProtocolConformance *conformance, ValueDecl *requirement) const { @@ -5600,6 +5605,9 @@ ValueDecl *TypeChecker::deriveProtocolRequirement(DeclContext *DC, case KnownProtocolKind::AdditiveArithmetic: return derived.deriveAdditiveArithmetic(Requirement); + case KnownProtocolKind::Differentiable: + return derived.deriveDifferentiable(Requirement); + default: return nullptr; } @@ -5624,6 +5632,8 @@ Type TypeChecker::deriveTypeWitness(DeclContext *DC, return derived.deriveRawRepresentable(AssocType); case KnownProtocolKind::CaseIterable: return derived.deriveCaseIterable(AssocType); + case KnownProtocolKind::Differentiable: + return derived.deriveDifferentiable(AssocType); default: return nullptr; } diff --git a/lib/Sema/TypeCheckRequestFunctions.cpp b/lib/Sema/TypeCheckRequestFunctions.cpp index 548e5add22f63..f865f3712e8f9 100644 --- a/lib/Sema/TypeCheckRequestFunctions.cpp +++ b/lib/Sema/TypeCheckRequestFunctions.cpp @@ -24,7 +24,7 @@ using namespace swift; -llvm::Expected +Type InheritedTypeRequest::evaluate( Evaluator &evaluator, llvm::PointerUnion decl, unsigned index, @@ -62,7 +62,7 @@ InheritedTypeRequest::evaluate( evaluator(InheritedTypeRequest{decl, index, TypeResolutionStage::Interface}); if (!result) - return result; + return Type(); return dc->mapTypeIntoContext(*result); } @@ -79,7 +79,7 @@ InheritedTypeRequest::evaluate( return inheritedType ? inheritedType : ErrorType::get(dc->getASTContext()); } -llvm::Expected +Type SuperclassTypeRequest::evaluate(Evaluator &evaluator, NominalTypeDecl *nominalDecl, TypeResolutionStage stage) const { @@ -129,7 +129,7 @@ SuperclassTypeRequest::evaluate(Evaluator &evaluator, return Type(); } -llvm::Expected +Type EnumRawTypeRequest::evaluate(Evaluator &evaluator, EnumDecl *enumDecl, TypeResolutionStage stage) const { for (unsigned int idx : indices(enumDecl->getInherited())) { @@ -158,7 +158,7 @@ EnumRawTypeRequest::evaluate(Evaluator &evaluator, EnumDecl *enumDecl, return Type(); } -llvm::Expected +CustomAttr * AttachedFunctionBuilderRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const { ASTContext &ctx = decl->getASTContext(); @@ -182,9 +182,8 @@ AttachedFunctionBuilderRequest::evaluate(Evaluator &evaluator, return nullptr; } -llvm::Expected -FunctionBuilderTypeRequest::evaluate(Evaluator &evaluator, - ValueDecl *decl) const { +Type FunctionBuilderTypeRequest::evaluate(Evaluator &evaluator, + ValueDecl *decl) const { // Look for a function-builder custom attribute. auto attr = decl->getAttachedFunctionBuilder(); if (!attr) return Type(); diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index 55c981d257c86..2165307789eb6 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -1895,7 +1895,7 @@ static void checkClassConstructorBody(ClassDecl *classDecl, } } -llvm::Expected +bool TypeCheckFunctionBodyUntilRequest::evaluate(Evaluator &evaluator, AbstractFunctionDecl *AFD, SourceLoc endTypeCheckLoc) const { diff --git a/lib/Sema/TypeCheckStorage.cpp b/lib/Sema/TypeCheckStorage.cpp index b3a005501ba8f..c009d2755262c 100644 --- a/lib/Sema/TypeCheckStorage.cpp +++ b/lib/Sema/TypeCheckStorage.cpp @@ -115,7 +115,7 @@ static void computeLoweredStoredProperties(NominalTypeDecl *decl) { } } -llvm::Expected> +ArrayRef StoredPropertiesRequest::evaluate(Evaluator &evaluator, NominalTypeDecl *decl) const { if (!hasStoredProperties(decl)) @@ -137,7 +137,7 @@ StoredPropertiesRequest::evaluate(Evaluator &evaluator, return decl->getASTContext().AllocateCopy(results); } -llvm::Expected> +ArrayRef StoredPropertiesAndMissingMembersRequest::evaluate(Evaluator &evaluator, NominalTypeDecl *decl) const { if (!hasStoredProperties(decl)) @@ -164,7 +164,7 @@ StoredPropertiesAndMissingMembersRequest::evaluate(Evaluator &evaluator, } /// Validate the \c entryNumber'th entry in \c binding. -llvm::Expected +const PatternBindingEntry * PatternBindingEntryRequest::evaluate(Evaluator &eval, PatternBindingDecl *binding, unsigned entryNumber) const { @@ -199,23 +199,9 @@ PatternBindingEntryRequest::evaluate(Evaluator &eval, } } - // Check the pattern. We treat type-checking a PatternBindingDecl like - // type-checking an expression because that's how the initial binding is - // checked, and they have the same effect on the file's dependencies. - // - // In particular, it's /not/ correct to check the PBD's DeclContext because - // top-level variables in a script file are accessible from other files, - // even though the PBD is inside a TopLevelCodeDecl. + // Check the pattern. auto contextualPattern = ContextualPattern::forPatternBindingDecl(binding, entryNumber); - TypeResolutionOptions options(TypeResolverContext::PatternBindingDecl); - - if (binding->isInitialized(entryNumber)) { - // If we have an initializer, we can also have unknown types. - options |= TypeResolutionFlags::AllowUnspecifiedTypes; - options |= TypeResolutionFlags::AllowUnboundGenerics; - } - Type patternType = TypeChecker::typeCheckPattern(contextualPattern); if (patternType->hasError()) { swift::setBoundVarsTypeError(pattern, Context); @@ -288,7 +274,7 @@ PatternBindingEntryRequest::evaluate(Evaluator &eval, return &pbe; } -llvm::Expected +bool IsGetterMutatingRequest::evaluate(Evaluator &evaluator, AbstractStorageDecl *storage) const { auto storageDC = storage->getDeclContext(); @@ -342,7 +328,7 @@ IsGetterMutatingRequest::evaluate(Evaluator &evaluator, llvm_unreachable("bad impl kind"); } -llvm::Expected +bool IsSetterMutatingRequest::evaluate(Evaluator &evaluator, AbstractStorageDecl *storage) const { // By default, the setter is mutating if we have an instance member of a @@ -415,7 +401,7 @@ IsSetterMutatingRequest::evaluate(Evaluator &evaluator, llvm_unreachable("bad storage kind"); } -llvm::Expected +OpaqueReadOwnership OpaqueReadOwnershipRequest::evaluate(Evaluator &evaluator, AbstractStorageDecl *storage) const { return (storage->getAttrs().hasAttribute() @@ -1878,7 +1864,7 @@ createModifyCoroutinePrototype(AbstractStorageDecl *storage, return createCoroutineAccessorPrototype(storage, AccessorKind::Modify, ctx); } -llvm::Expected +AccessorDecl * SynthesizeAccessorRequest::evaluate(Evaluator &evaluator, AbstractStorageDecl *storage, AccessorKind kind) const { @@ -1906,7 +1892,7 @@ SynthesizeAccessorRequest::evaluate(Evaluator &evaluator, llvm_unreachable("Unhandled AccessorKind in switch"); } -llvm::Expected +bool RequiresOpaqueAccessorsRequest::evaluate(Evaluator &evaluator, VarDecl *var) const { // Nameless vars from interface files should not have any accessors. @@ -1953,7 +1939,7 @@ RequiresOpaqueAccessorsRequest::evaluate(Evaluator &evaluator, return true; } -llvm::Expected +bool RequiresOpaqueModifyCoroutineRequest::evaluate(Evaluator &evaluator, AbstractStorageDecl *storage) const { // Only for mutable storage. @@ -1997,7 +1983,7 @@ RequiresOpaqueModifyCoroutineRequest::evaluate(Evaluator &evaluator, /// If the storage is for a global stored property or a stored property of a /// resilient type, we are synthesizing accessors to present a resilient /// interface to the storage and they should not be transparent. -llvm::Expected +bool IsAccessorTransparentRequest::evaluate(Evaluator &evaluator, AccessorDecl *accessor) const { auto *storage = accessor->getStorage(); @@ -2114,7 +2100,7 @@ IsAccessorTransparentRequest::evaluate(Evaluator &evaluator, return true; } -llvm::Expected +VarDecl * LazyStoragePropertyRequest::evaluate(Evaluator &evaluator, VarDecl *VD) const { assert(isa(VD->getDeclContext()->getModuleScopeContext())); @@ -2288,7 +2274,7 @@ getSetterMutatingness(VarDecl *var, DeclContext *dc) { : PropertyWrapperMutability::Nonmutating; } -llvm::Expected> +Optional PropertyWrapperMutabilityRequest::evaluate(Evaluator &, VarDecl *var) const { VarDecl *originalVar = var; @@ -2362,7 +2348,7 @@ PropertyWrapperMutabilityRequest::evaluate(Evaluator &, return result; } -llvm::Expected +PropertyWrapperBackingPropertyInfo PropertyWrapperBackingPropertyInfoRequest::evaluate(Evaluator &evaluator, VarDecl *var) const { // Determine the type of the backing property. @@ -2477,7 +2463,7 @@ PropertyWrapperBackingPropertyInfoRequest::evaluate(Evaluator &evaluator, } // Get the property wrapper information. - if (!var->allAttachedPropertyWrappersHaveInitialValueInit() && + if (!var->allAttachedPropertyWrappersHaveWrappedValueInit() && !originalInitialValue) { return PropertyWrapperBackingPropertyInfo( backingVar, storageVar, nullptr, nullptr, nullptr); @@ -2491,7 +2477,7 @@ PropertyWrapperBackingPropertyInfoRequest::evaluate(Evaluator &evaluator, OpaqueValueExpr *origValue = new (ctx) OpaqueValueExpr(var->getSourceRange(), origValueType, /*isPlaceholder=*/true); - Expr *initializer = buildPropertyWrapperInitialValueCall( + Expr *initializer = buildPropertyWrapperWrappedValueCall( var, storageType, origValue, /*ignoreAttributeArgs=*/!originalInitialValue); typeCheckSynthesizedWrapperInitializer( @@ -2750,7 +2736,7 @@ static StorageImplInfo classifyWithHasStorageAttr(VarDecl *var) { return StorageImplInfo(ReadImplKind::Stored, writeImpl, readWriteImpl); } -llvm::Expected +StorageImplInfo StorageImplInfoRequest::evaluate(Evaluator &evaluator, AbstractStorageDecl *storage) const { if (auto *param = dyn_cast(storage)) { diff --git a/lib/Sema/TypeChecker.cpp b/lib/Sema/TypeChecker.cpp index bea018385c161..9f2109abb7eae 100644 --- a/lib/Sema/TypeChecker.cpp +++ b/lib/Sema/TypeChecker.cpp @@ -316,10 +316,10 @@ static void typeCheckDelayedFunctions(SourceFile &SF) { void swift::performTypeChecking(SourceFile &SF) { return (void)evaluateOrDefault(SF.getASTContext().evaluator, - TypeCheckSourceFileRequest{&SF}, false); + TypeCheckSourceFileRequest{&SF}, {}); } -llvm::Expected +evaluator::SideEffect TypeCheckSourceFileRequest::evaluate(Evaluator &eval, SourceFile *SF) const { assert(SF && "Source file cannot be null!"); assert(SF->ASTStage != SourceFile::TypeChecked && @@ -388,7 +388,7 @@ TypeCheckSourceFileRequest::evaluate(Evaluator &eval, SourceFile *SF) const { performWholeModuleTypeChecking(*SF); } - return true; + return std::make_tuple<>(); } void swift::performWholeModuleTypeChecking(SourceFile &SF) { diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index 1a8ae7a51fe60..8e96c886aef2b 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -1486,7 +1486,7 @@ Type computeWrappedValueType(VarDecl *var, Type backingStorageType, /// Build a call to the init(wrappedValue:) initializers of the property /// wrappers, filling in the given \c value as the original value. -Expr *buildPropertyWrapperInitialValueCall(VarDecl *var, +Expr *buildPropertyWrapperWrappedValueCall(VarDecl *var, Type backingStorageType, Expr *value, bool ignoreAttributeArgs); diff --git a/lib/Serialization/DeclTypeRecordNodes.def b/lib/Serialization/DeclTypeRecordNodes.def index 3bb2f0bc6fcee..2ab062799f926 100644 --- a/lib/Serialization/DeclTypeRecordNodes.def +++ b/lib/Serialization/DeclTypeRecordNodes.def @@ -134,7 +134,7 @@ DECL(PRECEDENCE_GROUP) DECL(ACCESSOR) #ifndef DECL_ATTR -#define DECL_ATTR(NAME, CLASS, OPTIONS, CODE) RECORD_VAL(CLASS##_DECL_ATTR, 100+CODE) +#define DECL_ATTR(NAME, CLASS, OPTIONS, CODE) RECORD_VAL(CLASS##_DECL_ATTR, 90+CODE) #endif #include "swift/AST/Attr.def" @@ -192,6 +192,8 @@ OTHER(XREF_OPAQUE_RETURN_TYPE_PATH_PIECE, 252) OTHER(CLANG_TYPE, 253) +OTHER(DERIVATIVE_FUNCTION_CONFIGURATION, 254) + #undef RECORD #undef DECLTYPERECORDNODES_HAS_RECORD_VAL #undef RECORD_VAL diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 4dbce8844c407..ec6fa3c9637b9 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -4369,6 +4369,30 @@ llvm::Error DeclDeserializer::deserializeDeclAttributes() { break; } + case decls_block::Transpose_DECL_ATTR: { + bool isImplicit; + uint64_t origNameId; + DeclID origDeclId; + ArrayRef parameters; + + serialization::decls_block::TransposeDeclAttrLayout::readRecord( + scratch, isImplicit, origNameId, origDeclId, parameters); + + DeclNameRefWithLoc origName{ + DeclNameRef(MF.getDeclBaseName(origNameId)), DeclNameLoc()}; + auto *origDecl = cast(MF.getDecl(origDeclId)); + llvm::SmallBitVector parametersBitVector(parameters.size()); + for (unsigned i : indices(parameters)) + parametersBitVector[i] = parameters[i]; + auto *indices = IndexSubset::get(ctx, parametersBitVector); + auto *transposeAttr = + TransposeAttr::create(ctx, isImplicit, SourceLoc(), SourceRange(), + /*baseTypeRepr*/ nullptr, origName, indices); + transposeAttr->setOriginalFunction(origDecl); + Attr = transposeAttr; + break; + } + case decls_block::SPIAccessControl_DECL_ATTR: { ArrayRef spiIds; serialization::decls_block::SPIAccessControlDeclAttrLayout::readRecord( diff --git a/lib/Serialization/ModuleFile.cpp b/lib/Serialization/ModuleFile.cpp index b66a76d892039..f1fab8d01fcee 100644 --- a/lib/Serialization/ModuleFile.cpp +++ b/lib/Serialization/ModuleFile.cpp @@ -910,6 +910,66 @@ ModuleFile::readObjCMethodTable(ArrayRef fields, StringRef blobData) { base + sizeof(uint32_t), base)); } +/// Used to deserialize entries in the on-disk derivative function configuration +/// table. +class ModuleFile::DerivativeFunctionConfigTableInfo { +public: + using internal_key_type = StringRef; + using external_key_type = internal_key_type; + using data_type = SmallVector, 8>; + using hash_value_type = uint32_t; + using offset_type = unsigned; + + external_key_type GetExternalKey(internal_key_type ID) { return ID; } + + internal_key_type GetInternalKey(external_key_type ID) { return ID; } + + hash_value_type ComputeHash(internal_key_type key) { + return llvm::djbHash(key, SWIFTMODULE_HASH_SEED); + } + + static bool EqualKey(internal_key_type lhs, internal_key_type rhs) { + return lhs == rhs; + } + + static std::pair ReadKeyDataLength(const uint8_t *&data) { + unsigned keyLength = endian::readNext(data); + unsigned dataLength = endian::readNext(data); + return {keyLength, dataLength}; + } + + static internal_key_type ReadKey(const uint8_t *data, unsigned length) { + return StringRef(reinterpret_cast(data), length); + } + + static data_type ReadData(internal_key_type key, const uint8_t *data, + unsigned length) { + data_type result; + const uint8_t *limit = data + length; + while (data < limit) { + DeclID genSigId = endian::readNext(data); + int32_t nameLength = endian::readNext(data); + StringRef mangledName(reinterpret_cast(data), nameLength); + data += nameLength; + result.push_back({mangledName, genSigId}); + } + return result; + } +}; + +std::unique_ptr +ModuleFile::readDerivativeFunctionConfigTable(ArrayRef fields, + StringRef blobData) { + uint32_t tableOffset; + index_block::DerivativeFunctionConfigTableLayout::readRecord(fields, + tableOffset); + auto base = reinterpret_cast(blobData.data()); + + using OwnedTable = std::unique_ptr; + return OwnedTable(SerializedDerivativeFunctionConfigTable::Create( + base + tableOffset, base + sizeof(uint32_t), base)); +} + bool ModuleFile::readIndexBlock(llvm::BitstreamCursor &cursor) { if (llvm::Error Err = cursor.EnterSubBlock(INDEX_BLOCK_ID)) { // FIXME this drops the error on the floor. @@ -1015,6 +1075,10 @@ bool ModuleFile::readIndexBlock(llvm::BitstreamCursor &cursor) { case index_block::OBJC_METHODS: ObjCMethods = readObjCMethodTable(scratch, blobData); break; + case index_block::DERIVATIVE_FUNCTION_CONFIGURATIONS: + DerivativeFunctionConfigurations = + readDerivativeFunctionConfigTable(scratch, blobData); + break; case index_block::ENTRY_POINT: assert(blobData.empty()); setEntryPointClassID(scratch.front()); @@ -2405,6 +2469,34 @@ void ModuleFile::loadObjCMethods( } } +void ModuleFile::loadDerivativeFunctionConfigurations( + AbstractFunctionDecl *originalAFD, + llvm::SetVector &results) { + if (!DerivativeFunctionConfigurations) + return; + auto &ctx = originalAFD->getASTContext(); + Mangle::ASTMangler Mangler; + auto mangledName = Mangler.mangleDeclAsUSR(originalAFD, ""); + auto configs = DerivativeFunctionConfigurations->find(mangledName); + if (configs == DerivativeFunctionConfigurations->end()) + return; + for (auto entry : *configs) { + auto *parameterIndices = IndexSubset::getFromString(ctx, entry.first); + auto derivativeGenSigOrError = getGenericSignatureChecked(entry.second); + if (!derivativeGenSigOrError) { + if (!getContext().LangOpts.EnableDeserializationRecovery) + fatal(derivativeGenSigOrError.takeError()); + llvm::consumeError(derivativeGenSigOrError.takeError()); + } + auto derivativeGenSig = derivativeGenSigOrError.get(); + // NOTE(TF-1038): Result indices are currently unsupported in derivative + // registration attributes. In the meantime, always use `{0}` (wrt the + // first and only result). + auto resultIndices = IndexSubset::get(ctx, 1, {0}); + results.insert({parameterIndices, resultIndices, derivativeGenSig}); + } +} + TinyPtrVector ModuleFile::loadNamedMembers(const IterableDeclContext *IDC, DeclBaseName N, uint64_t contextData) { @@ -2602,6 +2694,17 @@ void ModuleFile::getTopLevelDecls( } } +void ModuleFile::getOperatorDecls(SmallVectorImpl &results) { + PrettyStackTraceModuleFile stackEntry(*this); + if (!OperatorDecls) + return; + + for (auto entry : OperatorDecls->data()) { + for (auto item : entry) + results.push_back(cast(getDecl(item.second))); + } +} + void ModuleFile::getPrecedenceGroups( SmallVectorImpl &results) { PrettyStackTraceModuleFile stackEntry(*this); diff --git a/lib/Serialization/ModuleFile.h b/lib/Serialization/ModuleFile.h index c52d8452ba428..be7c841c2eb76 100644 --- a/lib/Serialization/ModuleFile.h +++ b/lib/Serialization/ModuleFile.h @@ -417,6 +417,12 @@ class ModuleFile llvm::OnDiskIterableChainedHashTable; std::unique_ptr DeclUSRsTable; + class DerivativeFunctionConfigTableInfo; + using SerializedDerivativeFunctionConfigTable = + llvm::OnDiskIterableChainedHashTable; + std::unique_ptr + DerivativeFunctionConfigurations; + /// A blob of 0 terminated string segments referenced in \c SourceLocsTextData StringRef SourceLocsTextData; @@ -550,6 +556,12 @@ class ModuleFile std::unique_ptr readDeclMembersTable(ArrayRef fields, StringRef blobData); + /// Read an on-disk derivative function configuration table stored in + /// index_block::DerivativeFunctionConfigTableLayout format. + std::unique_ptr + readDerivativeFunctionConfigTable(ArrayRef fields, + StringRef blobData); + /// Reads the index block, which contains global tables. /// /// Returns false if there was an error. @@ -774,6 +786,12 @@ class ModuleFile bool isInstanceMethod, llvm::TinyPtrVector &methods); + /// Loads all derivative function configurations for the given + /// AbstractFunctionDecl. + void loadDerivativeFunctionConfigurations( + AbstractFunctionDecl *originalAFD, + llvm::SetVector &results); + /// Reports all class members in the module to the given consumer. /// /// This is intended for use with id-style lookup and code completion. @@ -811,6 +829,9 @@ class ModuleFile SmallVectorImpl &Results, llvm::function_ref matchAttributes = nullptr); + /// Adds all operators to the given vector. + void getOperatorDecls(SmallVectorImpl &Results); + /// Adds all precedence groups to the given vector. void getPrecedenceGroups(SmallVectorImpl &Results); diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index a26403ac9db14..14db3010597cc 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -55,7 +55,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 550; // linear_function, linear_function_extract +const uint16_t SWIFTMODULE_VERSION_MINOR = 551; // derivative function configurations /// A standard hash seed used for all string hashes in a serialized module. /// @@ -1934,6 +1934,10 @@ namespace index_block { /// produce Objective-C methods. OBJC_METHODS, + /// The derivative function configuration table, which maps original + /// function declaration names to derivative function configurations. + DERIVATIVE_FUNCTION_CONFIGURATIONS, + ENTRY_POINT, LOCAL_DECL_CONTEXT_OFFSETS, LOCAL_TYPE_DECLS, @@ -1998,6 +2002,12 @@ namespace index_block { BCBlob // map from member DeclBaseNames to offsets of DECL_MEMBERS records >; + using DerivativeFunctionConfigTableLayout = BCRecordLayout< + DERIVATIVE_FUNCTION_CONFIGURATIONS, // record ID + BCVBR<16>, // table offset within the blob (see below) + BCBlob // map from original declaration names to derivative configs + >; + using EntryPointLayout = BCRecordLayout< ENTRY_POINT, DeclIDField // the ID of the main class; 0 if there was a main source file diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index a091fafb0ea35..a24206eaa28df 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -770,6 +770,7 @@ void Serializer::writeBlockInfoBlock() { BLOCK_RECORD(index_block, CLASS_MEMBERS_FOR_DYNAMIC_LOOKUP); BLOCK_RECORD(index_block, OPERATOR_METHODS); BLOCK_RECORD(index_block, OBJC_METHODS); + BLOCK_RECORD(index_block, DERIVATIVE_FUNCTION_CONFIGURATIONS); BLOCK_RECORD(index_block, ENTRY_POINT); BLOCK_RECORD(index_block, LOCAL_DECL_CONTEXT_OFFSETS); BLOCK_RECORD(index_block, GENERIC_SIGNATURE_OFFSETS); @@ -4781,6 +4782,98 @@ static void writeObjCMethodTable(const index_block::ObjCMethodTableLayout &out, out.emit(scratch, tableOffset, hashTableBlob); } +namespace { + /// Used to serialize derivative function configurations. + class DerivativeFunctionConfigTableInfo { + public: + using key_type = std::string; + using key_type_ref = StringRef; + using data_type = Serializer::DerivativeFunctionConfigTableData; + using data_type_ref = const data_type &; + using hash_value_type = uint32_t; + using offset_type = unsigned; + + hash_value_type ComputeHash(key_type_ref key) { + assert(!key.empty()); + return llvm::djbHash(key, SWIFTMODULE_HASH_SEED); + } + + std::pair EmitKeyDataLength(raw_ostream &out, + key_type_ref key, + data_type_ref data) { + uint32_t keyLength = key.str().size(); + assert(keyLength == static_cast(keyLength)); + uint32_t dataLength = (sizeof(uint32_t) * 2) * data.size(); + for (auto entry : data) + dataLength += entry.first.size(); + assert(dataLength == static_cast(dataLength)); + endian::Writer writer(out, little); + writer.write(keyLength); + writer.write(dataLength); + return { keyLength, dataLength }; + } + + void EmitKey(raw_ostream &out, key_type_ref key, unsigned len) { + out << key; + } + + void EmitData(raw_ostream &out, key_type_ref key, data_type_ref data, + unsigned len) { + static_assert(declIDFitsIn32Bits(), "DeclID too large"); + endian::Writer writer(out, little); + for (auto &entry : data) { + // Write `GenericSignatureID`. + writer.write(entry.second); + // Write parameter indices string size, followed by data. + writer.write(entry.first.size()); + out << entry.first; + } + } + }; +} // end anonymous namespace + +static void writeDerivativeFunctionConfigs( + Serializer &S, const index_block::DerivativeFunctionConfigTableLayout &out, + Serializer::DerivativeFunctionConfigTable &derivativeConfigs) { + // Create the on-disk hash table. + llvm::OnDiskChainedHashTableGenerator + generator; + llvm::SmallString<32> hashTableBlob; + uint32_t tableOffset; + { + llvm::raw_svector_ostream blobStream(hashTableBlob); + for (auto &entry : derivativeConfigs) + generator.insert(entry.first.get(), entry.second); + // Make sure that no bucket is at offset 0. + endian::write(blobStream, 0, little); + tableOffset = generator.Emit(blobStream); + } + SmallVector scratch; + out.emit(scratch, tableOffset, hashTableBlob); +} + +// Records derivative function configurations for the given AbstractFunctionDecl +// by visiting `@differentiable` and `@derivative` attributes. +static void recordDerivativeFunctionConfig( + Serializer &S, const AbstractFunctionDecl *AFD, + Serializer::UniquedDerivativeFunctionConfigTable &derivativeConfigs) { + auto &ctx = AFD->getASTContext(); + Mangle::ASTMangler Mangler; + for (auto *attr : AFD->getAttrs().getAttributes()) { + auto mangledName = ctx.getIdentifier(Mangler.mangleDeclAsUSR(AFD, "")); + derivativeConfigs[mangledName].insert( + {ctx.getIdentifier(attr->getParameterIndices()->getString()), + attr->getDerivativeGenericSignature()}); + } + for (auto *attr : AFD->getAttrs().getAttributes()) { + auto *origAFD = attr->getOriginalFunction(); + auto mangledName = ctx.getIdentifier(Mangler.mangleDeclAsUSR(origAFD, "")); + derivativeConfigs[mangledName].insert( + {ctx.getIdentifier(attr->getParameterIndices()->getString()), + AFD->getGenericSignature()}); + } +}; + /// Recursively walks the members and derived global decls of any nominal types /// to build up global tables. template @@ -4790,6 +4883,7 @@ static void collectInterestingNestedDeclarations( Serializer::DeclTable &operatorMethodDecls, Serializer::ObjCMethodTable &objcMethods, Serializer::NestedTypeDeclsTable &nestedTypeDecls, + Serializer::UniquedDerivativeFunctionConfigTable &derivativeConfigs, bool isLocal = false) { const NominalTypeDecl *nominalParent = nullptr; @@ -4826,14 +4920,17 @@ static void collectInterestingNestedDeclarations( } } - // Record Objective-C methods. - if (auto *func = dyn_cast(member)) + // Record Objective-C methods and derivative function configurations. + if (auto *func = dyn_cast(member)) { recordObjCMethod(func); + recordDerivativeFunctionConfig(S, func, derivativeConfigs); + } // Handle accessors. if (auto storage = dyn_cast(member)) { for (auto *accessor : storage->getAllAccessors()) { recordObjCMethod(accessor); + recordDerivativeFunctionConfig(S, accessor, derivativeConfigs); } } @@ -4856,6 +4953,7 @@ static void collectInterestingNestedDeclarations( collectInterestingNestedDeclarations(S, iterable->getMembers(), operatorMethodDecls, objcMethods, nestedTypeDecls, + derivativeConfigs, isLocal); } } @@ -4868,6 +4966,7 @@ void Serializer::writeAST(ModuleOrSourceFile DC) { NestedTypeDeclsTable nestedTypeDecls; LocalTypeHashTableGenerator localTypeGenerator, opaqueReturnTypeGenerator; ExtensionTable extensionDecls; + UniquedDerivativeFunctionConfigTable uniquedDerivativeConfigs; bool hasLocalTypes = false; bool hasOpaqueReturnTypes = false; @@ -4916,6 +5015,8 @@ void Serializer::writeAST(ModuleOrSourceFile DC) { } else { llvm_unreachable("all top-level declaration kinds accounted for"); } + if (auto *AFD = dyn_cast(D)) + recordDerivativeFunctionConfig(*this, AFD, uniquedDerivativeConfigs); orderedTopLevelDecls.push_back(addDeclRef(D)); @@ -4925,7 +5026,8 @@ void Serializer::writeAST(ModuleOrSourceFile DC) { if (auto IDC = dyn_cast(D)) { collectInterestingNestedDeclarations(*this, IDC->getMembers(), operatorMethodDecls, objcMethods, - nestedTypeDecls); + nestedTypeDecls, + uniquedDerivativeConfigs); } } @@ -4954,7 +5056,9 @@ void Serializer::writeAST(ModuleOrSourceFile DC) { if (auto IDC = dyn_cast(TD)) { collectInterestingNestedDeclarations(*this, IDC->getMembers(), operatorMethodDecls, objcMethods, - nestedTypeDecls, /*isLocal=*/true); + nestedTypeDecls, + uniquedDerivativeConfigs, + /*isLocal=*/true); } } @@ -5017,6 +5121,20 @@ void Serializer::writeAST(ModuleOrSourceFile DC) { writeNestedTypeDeclsTable(NestedTypeDeclsTable, nestedTypeDecls); } + // Convert uniqued derivative function config table to serialization- + // ready format: turn `GenericSignature` to `GenericSignatureID`. + DerivativeFunctionConfigTable derivativeConfigs; + for (auto entry : uniquedDerivativeConfigs) { + for (auto config : entry.second) { + auto paramIndices = config.first.str(); + auto genSigID = addGenericSignatureRef(config.second); + derivativeConfigs[entry.first].push_back({paramIndices, genSigID}); + } + } + index_block::DerivativeFunctionConfigTableLayout DerivativeConfigTable(Out); + writeDerivativeFunctionConfigs(*this, DerivativeConfigTable, + derivativeConfigs); + if (entryPointClassID.hasValue()) { index_block::EntryPointLayout EntryPoint(Out); EntryPoint.emit(ScratchRecord, entryPointClassID.getValue()); diff --git a/lib/Serialization/Serialization.h b/lib/Serialization/Serialization.h index a570ca379895a..8529620ae9957 100644 --- a/lib/Serialization/Serialization.h +++ b/lib/Serialization/Serialization.h @@ -256,6 +256,23 @@ class Serializer : public SerializerBase { SmallVector, 4>; using ExtensionTable = llvm::MapVector; + using DerivativeFunctionConfigTableData = + llvm::SmallVector, 4>; + // In-memory representation of what will eventually be an on-disk hash table + // mapping original declaration USRs to derivative function configurations. + using DerivativeFunctionConfigTable = + llvm::MapVector; + // Uniqued mapping from original declarations USRs to derivative function + // configurations. + // Note: this exists because `GenericSignature` can be used as a `DenseMap` + // key, while `GenericSignatureID` cannot + // (`DenseMapInfo::getEmptyKey()` crashes). To work + // around this, a `UniquedDerivativeFunctionConfigTable` is first + // constructed, and then converted to a `DerivativeFunctionConfigTableData`. + using UniquedDerivativeFunctionConfigTable = llvm::MapVector< + Identifier, + llvm::SmallSetVector, 4>>; + private: /// A map from identifiers to methods and properties with the given name. /// diff --git a/lib/Serialization/SerializedModuleLoader.cpp b/lib/Serialization/SerializedModuleLoader.cpp index 64081f34d4edf..59e2d019faa1c 100644 --- a/lib/Serialization/SerializedModuleLoader.cpp +++ b/lib/Serialization/SerializedModuleLoader.cpp @@ -993,6 +993,17 @@ void SerializedModuleLoaderBase::loadObjCMethods( } } +void SerializedModuleLoaderBase::loadDerivativeFunctionConfigurations( + AbstractFunctionDecl *originalAFD, unsigned int previousGeneration, + llvm::SetVector &results) { + for (auto &modulePair : LoadedModuleFiles) { + if (modulePair.second <= previousGeneration) + continue; + modulePair.first->loadDerivativeFunctionConfigurations(originalAFD, + results); + } +} + std::error_code MemoryBufferSerializedModuleLoader::findModuleFilesInDirectory( AccessPathElem ModuleID, const SerializedModuleBaseName &BaseName, @@ -1173,6 +1184,11 @@ void SerializedASTFile::getTopLevelDeclsWhereAttributesMatch( File.getTopLevelDecls(results, matchAttributes); } +void SerializedASTFile::getOperatorDecls( + SmallVectorImpl &results) const { + File.getOperatorDecls(results); +} + void SerializedASTFile::getPrecedenceGroups( SmallVectorImpl &results) const { File.getPrecedenceGroups(results); diff --git a/lib/TBDGen/TBDGen.cpp b/lib/TBDGen/TBDGen.cpp index b9465e745a301..96063133eafa0 100644 --- a/lib/TBDGen/TBDGen.cpp +++ b/lib/TBDGen/TBDGen.cpp @@ -974,7 +974,7 @@ static bool hasLinkerDirective(Decl *D) { return !getAllMovedPlatformVersions(D).empty(); } -llvm::Expected +TBDFileAndSymbols GenerateTBDRequest::evaluate(Evaluator &evaluator, TBDGenDescriptor desc) const { auto *M = desc.getParentModule(); diff --git a/stdlib/private/OSLog/CMakeLists.txt b/stdlib/private/OSLog/CMakeLists.txt index 9228d5379bfd3..7241543470fe8 100644 --- a/stdlib/private/OSLog/CMakeLists.txt +++ b/stdlib/private/OSLog/CMakeLists.txt @@ -1,8 +1,8 @@ -add_swift_target_library(swiftOSLogPrototype +add_swift_target_library(swiftOSLogTestHelper IS_SDK_OVERLAY SHARED - OSLog.swift + OSLogTestHelper.swift OSLogMessage.swift OSLogIntegerFormatting.swift OSLogStringAlignment.swift @@ -11,10 +11,10 @@ add_swift_target_library(swiftOSLogPrototype OSLogNSObjectType.swift OSLogFloatingPointTypes.swift - SWIFT_MODULE_DEPENDS_IOS Darwin os ObjectiveC - SWIFT_MODULE_DEPENDS_OSX Darwin os ObjectiveC - SWIFT_MODULE_DEPENDS_TVOS Darwin os ObjectiveC - SWIFT_MODULE_DEPENDS_WATCHOS Darwin os ObjectiveC + SWIFT_MODULE_DEPENDS_IOS Darwin ObjectiveC + SWIFT_MODULE_DEPENDS_OSX Darwin ObjectiveC + SWIFT_MODULE_DEPENDS_TVOS Darwin ObjectiveC + SWIFT_MODULE_DEPENDS_WATCHOS Darwin ObjectiveC TARGET_SDKS ALL_APPLE_PLATFORMS SWIFT_COMPILE_FLAGS ${SWIFT_STANDARD_LIBRARY_SWIFT_FLAGS} INSTALL_IN_COMPONENT never_install diff --git a/stdlib/private/OSLog/OSLog.swift b/stdlib/private/OSLog/OSLog.swift deleted file mode 100644 index ce443a4820ecc..0000000000000 --- a/stdlib/private/OSLog/OSLog.swift +++ /dev/null @@ -1,198 +0,0 @@ -//===----------------- OSLog.swift ----------------------------------------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// - -// This file contains the new swift APIs for OS log that accept string -// interpolations. This is a prototype meant for experimentation and testing. -// Do not use it outside of tests. - -@_exported import os - -@available(macOS 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) -public struct Logger { - @usableFromInline - internal let logObject: OSLog - - /// Create a custom OSLog object for logging. - public init(subsystem: String, category: String) { - logObject = OSLog(subsystem: subsystem, category: category) - } - - /// Use the default OSLog object for logging. - public init() { - logObject = OSLog.default - } - - /// Create a Logger instance from an existing OSLog Object. - public init(_ logObj: OSLog) { - logObject = logObj - } - - // Functions defined below are marked @_optimize(none) to prevent inlining - // of string internals (such as String._StringGuts) which will interfere with - // constant evaluation and folding. Note that these functions will be inlined, - // constant evaluated/folded and optimized in the context of a caller. - - /// Log a string interpolation at a given level. The level is `default` if - /// it is not specified. - @_transparent - @_optimize(none) - public func log(level: OSLogType = .default, _ message: OSLogMessage) { - osLog(log: logObject, level: level, message) - } - - // The following overloads are for logging at specific levels. The levels that - // are supported are debug (also called trace), info, notice (also called - // default), error (also called warning), fault (also called critical). - - @_transparent - @_optimize(none) - public func trace(_ message: OSLogMessage) { - osLog(log: logObject, level: .debug, message) - } - - @_transparent - @_optimize(none) - public func debug(_ message: OSLogMessage) { - osLog(log: logObject, level: .debug, message) - } - - @_transparent - @_optimize(none) - public func info(_ message: OSLogMessage) { - osLog(log: logObject, level: .info, message) - } - - @_transparent - @_optimize(none) - public func notice(_ message: OSLogMessage) { - osLog(log: logObject, level: .default, message) - } - - @_transparent - @_optimize(none) - public func warning(_ message: OSLogMessage) { - osLog(log: logObject, level: .error, message) - } - - @_transparent - @_optimize(none) - public func error(_ message: OSLogMessage) { - osLog(log: logObject, level: .error, message) - } - - @_transparent - @_optimize(none) - public func critical(_ message: OSLogMessage) { - osLog(log: logObject, level: .fault, message) - } - - @_transparent - @_optimize(none) - public func fault(_ message: OSLogMessage) { - osLog(log: logObject, level: .fault, message) - } -} - -/// Given an instance of the custom string interpolation type: `OSLogMessage`, -/// extract the format string, serialize the arguments to a byte buffer, -/// and pass them to the OS logging system. -@available(macOS 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) -@_transparent -@_optimize(none) -public func osLog( - log logObject: OSLog, - level logLevel: OSLogType, - _ message: OSLogMessage -) { - // Compute static constants first so that they can be folded by - // OSLogOptimization pass. - let formatString = message.interpolation.formatString - let preamble = message.interpolation.preamble - let argumentCount = message.interpolation.argumentCount - let bufferSize = message.bufferSize - let uint32bufferSize = UInt32(bufferSize) - let argumentClosures = message.interpolation.arguments.argumentClosures - - let formatStringPointer = _getGlobalStringTablePointer(formatString) - - // Code that will execute at runtime. - guard logObject.isEnabled(type: logLevel) else { return } - - // Allocate a byte buffer to store the arguments. The buffer could be stack - // allocated as it is local to this function and also its size is a - // compile-time constant. - let bufferMemory = UnsafeMutablePointer.allocate(capacity: bufferSize) - // Array of references to auxiliary storage created during serialization of - // strings. This array can be stack allocated. - var stringStorageObjects: [AnyObject] = [] - - var currentBufferPosition = bufferMemory - serialize(preamble, at: ¤tBufferPosition) - serialize(argumentCount, at: ¤tBufferPosition) - argumentClosures.forEach { $0(¤tBufferPosition, &stringStorageObjects) } - - ___os_log_impl(UnsafeMutableRawPointer(mutating: #dsohandle), - logObject, - logLevel, - formatStringPointer, - bufferMemory, - uint32bufferSize) - - // The following operation extends the lifetime of argumentClosures, - // stringStorageObjects, and also of the objects stored in them till this - // point. This is necessary because __os_log_impl is passed internal pointers - // to the objects/strings stored in these arrays. - _fixLifetime(argumentClosures) - _fixLifetime(stringStorageObjects) - bufferMemory.deallocate() -} - -/// A test helper that constructs a byte buffer and a format string from an -/// instance of `OSLogMessage` using the same logic as the function `osLog`, -/// and applies a given `assertion` to the constructed format string and -/// byte buffer. This function should be used only in tests. -/// - Parameters: -/// - message: An instance of `OSLogMessage` created from string interpolation -/// - assertion: A closure that takes a format string and a pointer to a -/// byte buffer and asserts a condition. -@_transparent -@_optimize(none) -public // @testable -func _checkFormatStringAndBuffer( - _ message: OSLogMessage, - with assertion: (String, UnsafeBufferPointer) -> Void -) { - // Compute static constants first so that they can be folded by - // OSLogOptimization pass. - let formatString = message.interpolation.formatString - let preamble = message.interpolation.preamble - let argumentCount = message.interpolation.argumentCount - let bufferSize = message.bufferSize - let argumentClosures = message.interpolation.arguments.argumentClosures - - // Code that will execute at runtime. - let bufferMemory = UnsafeMutablePointer.allocate(capacity: bufferSize) - var stringStorageObjects: [AnyObject] = [] - - var currentBufferPosition = bufferMemory - serialize(preamble, at: ¤tBufferPosition) - serialize(argumentCount, at: ¤tBufferPosition) - argumentClosures.forEach { $0(¤tBufferPosition, &stringStorageObjects) } - - assertion( - formatString, - UnsafeBufferPointer(start: UnsafePointer(bufferMemory), count: bufferSize)) - - _fixLifetime(argumentClosures) - _fixLifetime(stringStorageObjects) - bufferMemory.deallocate() -} diff --git a/stdlib/private/OSLog/OSLogTestHelper.swift b/stdlib/private/OSLog/OSLogTestHelper.swift new file mode 100644 index 0000000000000..6b7d134c8115e --- /dev/null +++ b/stdlib/private/OSLog/OSLogTestHelper.swift @@ -0,0 +1,106 @@ +//===----------------- OSLogTestHelper.swift ----------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +// This file contains test helpers for testing the compiler diagnostics and optimizations +// of the new swift APIs for os log that accept string interpolations. + +// Some functions defined in this file are marked @_optimize(none) to prevent inlining +// of string internals (such as String._StringGuts) which will interfere with +// constant evaluation and folding. Note that these functions will be inlined, +// constant evaluated, folded and optimized in the context of a caller. TODO: +// @_optimize(none) can be removed if (non-mandatory) inlining optimizations can be moved +// after serialization. + +/// A function that acts like a check for whether logging is enabled in `_osLogTestHelper`. +@inline(never) +@usableFromInline +internal func isLoggingEnabled() -> Bool { true } + +/// A closure that does nothing. Meant to be used as the default assertion of +/// `_osLogTestHelper`. +public let _noopClosure = { (x : String, y : UnsafeBufferPointer) in return } + +/// A test helper that constructs a byte buffer and a format string from an +/// instance of `OSLogMessage` using the same logic as the new os log APIs, +/// and applies a given `assertion` to the constructed format string and +/// byte buffer. This function should be used only in tests. +/// - Parameters: +/// - message: An instance of `OSLogMessage` created from string interpolation +/// - assertion: A closure that takes a format string and a pointer to a +/// byte buffer and asserts a condition. +@_transparent +@_optimize(none) +public // @testable +func _osLogTestHelper( + _ message: OSLogMessage, + assertion: (String, UnsafeBufferPointer) -> Void = _noopClosure +) { + // Compute static constants first so that they can be folded by + // OSLogOptimization pass. + let formatString = message.interpolation.formatString + let preamble = message.interpolation.preamble + let argumentCount = message.interpolation.argumentCount + let bufferSize = message.bufferSize + let argumentClosures = message.interpolation.arguments.argumentClosures + let formatStringPointer = _getGlobalStringTablePointer(formatString) + + // Code that will execute at runtime. + if (!isLoggingEnabled()) { + return + } + + // Allocate a byte buffer to store the arguments. The buffer could be stack + // allocated as it is local to this function and also its size is a + // compile-time constant. + let bufferMemory = UnsafeMutablePointer.allocate(capacity: bufferSize) + // Array of references to auxiliary storage created during serialization of + // strings. This array can be stack allocated. + var stringStorageObjects: [AnyObject] = [] + + var currentBufferPosition = bufferMemory + serialize(preamble, at: ¤tBufferPosition) + serialize(argumentCount, at: ¤tBufferPosition) + argumentClosures.forEach { $0(¤tBufferPosition, &stringStorageObjects) } + + _os_log_impl_test( + assertion, + formatString, + formatStringPointer, + bufferMemory, + UInt32(bufferSize)) + + // The following operation extends the lifetime of argumentClosures, + // stringStorageObjects, and also of the objects stored in them, till this + // point. This is necessary because the assertion is passed internal pointers + // to the objects/strings stored in these arrays, as in the actual os log + // implementation. + _fixLifetime(argumentClosures) + _fixLifetime(stringStorageObjects) + bufferMemory.deallocate() +} + +/// A function that pretends to be _os_log_impl. +@inline(never) +@usableFromInline +internal func _os_log_impl_test( + _ assertion: (String, UnsafeBufferPointer) -> Void, + _ formatString: String, + _ formatStringPointer: UnsafePointer, + _ bufferMemory: UnsafeMutablePointer, + _ bufferSize: UInt32 +) { + assertion( + formatString, + UnsafeBufferPointer( + start: UnsafePointer(bufferMemory), + count: Int(bufferSize))) +} diff --git a/stdlib/public/Reflection/TypeRef.cpp b/stdlib/public/Reflection/TypeRef.cpp index 154f5837571b7..6fa789abe11a0 100644 --- a/stdlib/public/Reflection/TypeRef.cpp +++ b/stdlib/public/Reflection/TypeRef.cpp @@ -383,6 +383,16 @@ class DemanglingForTypeRef public: DemanglingForTypeRef(Demangle::Demangler &Dem) : Dem(Dem) {} + Demangle::NodePointer visit(const TypeRef *typeRef) { + auto node = TypeRefVisitor::visit(typeRef); + + // Wrap all nodes in a Type node, as consumers generally expect. + auto typeNode = Dem.createNode(Node::Kind::Type); + typeNode->addChild(node, Dem); + return typeNode; + } + Demangle::NodePointer visitBuiltinTypeRef(const BuiltinTypeRef *B) { return Dem.demangleType(B->getMangledName()); } @@ -423,9 +433,7 @@ class DemanglingForTypeRef if (auto parent = BG->getParent()) assert(false && "not implemented"); - auto top = Dem.createNode(Node::Kind::Type); - top->addChild(genericNode, Dem); - return top; + return genericNode; } Demangle::NodePointer visitTupleTypeRef(const TupleTypeRef *T) { @@ -576,18 +584,14 @@ class DemanglingForTypeRef node = Dem.createNode(Node::Kind::ProtocolListWithAnyObject); node->addChild(proto_list, Dem); } - auto typeNode = Dem.createNode(Node::Kind::Type); - typeNode->addChild(node, Dem); - return typeNode; + return node; } Demangle::NodePointer visitMetatypeTypeRef(const MetatypeTypeRef *M) { auto node = Dem.createNode(Node::Kind::Metatype); assert(!M->wasAbstract() && "not implemented"); node->addChild(visit(M->getInstanceType()), Dem); - auto typeNode = Dem.createNode(Node::Kind::Type); - typeNode->addChild(node, Dem); - return typeNode; + return node; } Demangle::NodePointer @@ -618,8 +622,7 @@ class DemanglingForTypeRef } Demangle::NodePointer visitForeignClassTypeRef(const ForeignClassTypeRef *F) { - assert(false && "not implemented"); - return nullptr; + return Dem.demangleType(F->getName()); } Demangle::NodePointer visitObjCClassTypeRef(const ObjCClassTypeRef *OC) { @@ -636,9 +639,7 @@ class DemanglingForTypeRef auto node = Dem.createNode(Node::Kind::Protocol); node->addChild(module, Dem); node->addChild(Dem.createNode(Node::Kind::Identifier, OC->getName()), Dem); - auto typeNode = Dem.createNode(Node::Kind::Type); - typeNode->addChild(node, Dem); - return typeNode; + return node; } #define REF_STORAGE(Name, name, ...) \ diff --git a/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp b/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp index 649a6f09816ff..0265069b78283 100644 --- a/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp +++ b/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp @@ -270,6 +270,16 @@ swift_reflection_typeRefForMangledTypeName(SwiftReflectionContextRef ContextRef, return reinterpret_cast(TR); } +char * +swift_reflection_copyDemangledNameForTypeRef( + SwiftReflectionContextRef ContextRef, swift_typeref_t OpaqueTypeRef) { + auto TR = reinterpret_cast(OpaqueTypeRef); + + Demangle::Demangler Dem; + auto Name = nodeToString(TR->getDemangling(Dem)); + return strdup(Name.c_str()); +} + swift_typeref_t swift_reflection_genericArgumentOfTypeRef(swift_typeref_t OpaqueTypeRef, unsigned Index) { @@ -517,6 +527,12 @@ void swift_reflection_dumpInfoForTypeRef(SwiftReflectionContextRef ContextRef, std::string MangledName = mangleNode(TR->getDemangling(Dem)); fprintf(stdout, "Mangled name: %s%s\n", MANGLING_PREFIX_STR, MangledName.c_str()); + + char *DemangledName = + swift_reflection_copyDemangledNameForTypeRef(ContextRef, OpaqueTypeRef); + fprintf(stdout, "Demangled name: %s\n", DemangledName); + free(DemangledName); + #ifndef NDEBUG assert(mangleNode(TR->getDemangling(Dem)) == MangledName && "round-trip diff"); diff --git a/stdlib/public/core/StaticString.swift b/stdlib/public/core/StaticString.swift index fc3c0f287a033..e264e6e635fac 100644 --- a/stdlib/public/core/StaticString.swift +++ b/stdlib/public/core/StaticString.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -19,11 +19,53 @@ /// A string type designed to represent text that is known at compile time. /// -/// Instances of the `StaticString` type are immutable. `StaticString` provides -/// limited, pointer-based access to its contents, unlike Swift's more -/// commonly used `String` type. A static string can store its value as a -/// pointer to an ASCII code unit sequence, as a pointer to a UTF-8 code unit -/// sequence, or as a single Unicode scalar value. +/// Instances of the `StaticString` type are immutable. +/// +/// `StaticString` provides only low-level access to its contents, unlike +/// Swift's more commonly used `String` type. A static string can use +/// either of the following as its storage: +/// +/// * a pointer to a null-terminated sequence of UTF-8 code units: +/// +/// let emoji: StaticString = "\u{1F600}" +/// emoji.hasPointerRepresentation //-> true +/// emoji.isASCII //-> false +/// emoji.unicodeScalar //-> Fatal error! +/// emoji.utf8CodeUnitCount //-> 4 +/// emoji.utf8Start[0] //-> 0xF0 +/// emoji.utf8Start[1] //-> 0x9F +/// emoji.utf8Start[2] //-> 0x98 +/// emoji.utf8Start[3] //-> 0x80 +/// emoji.utf8Start[4] //-> 0x00 +/// +/// * a single Unicode scalar value, under very limited circumstances: +/// +/// struct MyStaticScalar: ExpressibleByUnicodeScalarLiteral { +/// typealias UnicodeScalarLiteralType = StaticString +/// let value: StaticString +/// init(unicodeScalarLiteral value: StaticString) { +/// self.value = value +/// } +/// } +/// +/// let emoji: StaticString = MyStaticScalar("\u{1F600}").value +/// emoji.hasPointerRepresentation //-> false +/// emoji.isASCII //-> false +/// emoji.unicodeScalar.value //-> 0x1F600 +/// emoji.utf8CodeUnitCount //-> Fatal error! +/// emoji.utf8Start //-> Fatal error! +/// +/// You can use the `withUTF8Buffer(_:)` method to access a static string's +/// contents, regardless of which representation the static string uses. +/// +/// emoji.withUTF8Buffer { utf8 in +/// utf8.count //-> 4 +/// utf8[0] //-> 0xF0 +/// utf8[1] //-> 0x9F +/// utf8[2] //-> 0x98 +/// utf8[3] //-> 0x80 +/// utf8[4] //-> Fatal error! +/// } @frozen public struct StaticString : _ExpressibleByBuiltinUnicodeScalarLiteral, @@ -42,7 +84,7 @@ public struct StaticString internal var _startPtrOrData: Builtin.Word /// If `_startPtrOrData` is a pointer, contains the length of the UTF-8 data - /// in bytes. + /// in bytes (excluding the null terminator). @usableFromInline internal var _utf8CodeUnitCount: Builtin.Word @@ -51,16 +93,15 @@ public struct StaticString /// - bit 0: set to 0 if `_startPtrOrData` is a pointer, or to 1 if it is a /// Unicode scalar. /// - /// - bit 1: set to 1 if `_startPtrOrData` is a pointer and string data is - /// ASCII. + /// - bit 1: set to 1 if `_startPtrOrData` either points to an ASCII code unit + /// sequence, or stores an ASCII scalar value. @usableFromInline internal var _flags: Builtin.Int8 - /// A pointer to the beginning of the string's UTF-8 encoded representation. + /// A pointer to a null-terminated sequence of UTF-8 code units. /// - /// The static string must store a pointer to either ASCII or UTF-8 code - /// units. Accessing this property when `hasPointerRepresentation` is - /// `false` triggers a runtime error. + /// - Important: Accessing this property when `hasPointerRepresentation` is + /// `false` triggers a runtime error. @_transparent public var utf8Start: UnsafePointer { _precondition( @@ -69,11 +110,10 @@ public struct StaticString return UnsafePointer(bitPattern: UInt(_startPtrOrData))! } - /// The stored Unicode scalar value. + /// A single Unicode scalar value. /// - /// The static string must store a single Unicode scalar value. Accessing - /// this property when `hasPointerRepresentation` is `true` triggers a - /// runtime error. + /// - Important: Accessing this property when `hasPointerRepresentation` is + /// `true` triggers a runtime error. @_transparent public var unicodeScalar: Unicode.Scalar { _precondition( @@ -82,10 +122,10 @@ public struct StaticString return Unicode.Scalar(UInt32(UInt(_startPtrOrData)))! } - /// The length in bytes of the static string's ASCII or UTF-8 representation. + /// The number of UTF-8 code units (excluding the null terminator). /// - /// - Warning: If the static string stores a single Unicode scalar value, the - /// value of `utf8CodeUnitCount` is unspecified. + /// - Important: Accessing this property when `hasPointerRepresentation` is + /// `false` triggers a runtime error. @_transparent public var utf8CodeUnitCount: Int { _precondition( @@ -99,29 +139,25 @@ public struct StaticString return Builtin.inttoptr_Word(_startPtrOrData) } - /// A Boolean value indicating whether the static string stores a pointer to - /// ASCII or UTF-8 code units. + /// A Boolean value that indicates whether the static string stores a + /// pointer to a null-terminated sequence of UTF-8 code units. + /// + /// If `hasPointerRepresentation` is `false`, the static string stores a + /// single Unicode scalar value. @_transparent public var hasPointerRepresentation: Bool { return (UInt8(_flags) & 0x1) == 0 } - /// A Boolean value that is `true` if the static string stores a pointer to - /// ASCII code units. - /// - /// Use this property in conjunction with `hasPointerRepresentation` to - /// determine whether a static string with pointer representation stores an - /// ASCII or UTF-8 code unit sequence. - /// - /// - Warning: If the static string stores a single Unicode scalar value, the - /// value of `isASCII` is unspecified. + /// A Boolean value that indicates whether the static string represents only + /// ASCII code units (or an ASCII scalar value). @_transparent public var isASCII: Bool { return (UInt8(_flags) & 0x2) != 0 } /// Invokes the given closure with a buffer containing the static string's - /// UTF-8 code unit sequence. + /// UTF-8 code unit sequence (excluding the null terminator). /// /// This method works regardless of whether the static string stores a /// pointer or a single Unicode scalar value. @@ -132,12 +168,13 @@ public struct StaticString /// - Parameter body: A closure that takes a buffer pointer to the static /// string's UTF-8 code unit sequence as its sole argument. If the closure /// has a return value, that value is also used as the return value of the - /// `withUTF8Buffer(invoke:)` method. The pointer argument is valid only - /// for the duration of the method's execution. + /// `withUTF8Buffer(_:)` method. The pointer argument is valid only for the + /// duration of the method's execution. /// - Returns: The return value, if any, of the `body` closure. @_transparent public func withUTF8Buffer( - _ body: (UnsafeBufferPointer) -> R) -> R { + _ body: (UnsafeBufferPointer) -> R + ) -> R { if hasPointerRepresentation { return body(UnsafeBufferPointer( start: utf8Start, count: utf8CodeUnitCount)) @@ -256,7 +293,7 @@ public struct StaticString self = value } - /// A string representation of the static string. + /// A textual representation of the static string. public var description: String { return withUTF8Buffer { String._uncheckedFromUTF8($0) } } diff --git a/test/AutoDiff/SILGen/Inputs/noderivative_attr_other_file.swift b/test/AutoDiff/SILGen/Inputs/noderivative_attr_other_file.swift new file mode 100644 index 0000000000000..b5842532aebf0 --- /dev/null +++ b/test/AutoDiff/SILGen/Inputs/noderivative_attr_other_file.swift @@ -0,0 +1,5 @@ +@noDerivative +@_silgen_name("float_to_int_noderivative") +func floatToIntNoDerivative(_ x: Float) -> Int { + Int(x) +} diff --git a/test/AutoDiff/SILGen/mangling.swift b/test/AutoDiff/SILGen/mangling.swift new file mode 100644 index 0000000000000..f324b78b7c387 --- /dev/null +++ b/test/AutoDiff/SILGen/mangling.swift @@ -0,0 +1,23 @@ +// RUN: %target-swift-frontend -enable-experimental-differentiable-programming -module-name mangling -Xllvm -sil-full-demangle %s -emit-silgen | %FileCheck %s + +// Note: adapted from test/SILGen/mangling.swift. + +import _Differentiation + +// CHECK-LABEL: sil hidden [ossa] @$s8mangling15nonescapingFunc2fnyS2fXE_tF : $@convention(thin) (@noescape @callee_guaranteed (Float) -> Float) -> () { +func nonescapingFunc(fn: (Float) -> Float) {} + +// CHECK-LABEL: sil hidden [ossa] @$s8mangling8diffFunc2fnyS2fXF_tF : $@convention(thin) (@differentiable @noescape @callee_guaranteed (Float) -> Float) -> () { +func diffFunc(fn: @differentiable (Float) -> Float) {} + +// CHECK-LABEL: sil hidden [ossa] @$s8mangling10linearFunc2fnyS2fXF_tF : $@convention(thin) (@differentiable @noescape @callee_guaranteed (Float) -> Float) -> () { +func linearFunc(fn: @differentiable (Float) -> Float) {} + +// CHECK-LABEL: sil hidden [ossa] @$s8mangling12escapingFunc2fnS2fcS2fc_tF : $@convention(thin) (@guaranteed @callee_guaranteed (Float) -> Float) -> @owned @callee_guaranteed (Float) -> Float { +func escapingFunc(fn: @escaping (Float) -> Float) -> (Float) -> Float { fn } + +// CHECK-LABEL: sil hidden [ossa] @$s8mangling16diffEscapingFunc2fnS2fXGS2fXG_tF : $@convention(thin) (@guaranteed @differentiable @callee_guaranteed (Float) -> Float) -> @owned @differentiable @callee_guaranteed (Float) -> Float { +func diffEscapingFunc(fn: @escaping @differentiable (Float) -> Float) -> @differentiable (Float) -> Float { fn } + +// CHECK-LABEL: sil hidden [ossa] @$s8mangling18linearEscapingFunc2fnS2fXIS2fXI_tF : $@convention(thin) (@guaranteed @differentiable(linear) @callee_guaranteed (Float) -> Float) -> @owned @differentiable(linear) @callee_guaranteed (Float) -> Float { +func linearEscapingFunc(fn: @escaping @differentiable(linear) (Float) -> Float) -> @differentiable(linear) (Float) -> Float { fn } diff --git a/test/AutoDiff/SILGen/noderivative_attr.swift b/test/AutoDiff/SILGen/noderivative_attr.swift new file mode 100644 index 0000000000000..6a1ac9ce35315 --- /dev/null +++ b/test/AutoDiff/SILGen/noderivative_attr.swift @@ -0,0 +1,77 @@ +// RUN: %target-swift-frontend -enable-experimental-differentiable-programming -emit-silgen -verify %s | %FileCheck %s +// REQUIRES: asserts + +import _Differentiation + +@noDerivative var flag: Bool + +struct NotDifferentiable { + @noDerivative var stored: Float + + @noDerivative + var computedProperty: Float { + get { 1 } + set {} + _modify { yield &stored } + } + + @noDerivative + func instanceMethod(_ x: Float) -> Float { x } + + @noDerivative + static func staticMethod(_ x: Float) -> Float { x } + + @noDerivative + subscript(_ x: Float) -> Float { + get { 1 } + set {} + _modify { yield &stored } + } +} + +// CHECK-LABEL: struct NotDifferentiable { +// CHECK: @noDerivative @_hasStorage var stored: Float { get set } +// CHECK: @noDerivative var computedProperty: Float { get set _modify } +// CHECK: @noDerivative func instanceMethod(_ x: Float) -> Float +// CHECK: @noDerivative static func staticMethod(_ x: Float) -> Float +// CHECK: @noDerivative subscript(x: Float) -> Float { get set _modify } +// CHECK: } + +// CHECK-LABEL: // NotDifferentiable.computedProperty.getter +// CHECK: sil hidden [_semantics "autodiff.nonvarying"] [ossa] @$s17noderivative_attr17NotDifferentiableV16computedPropertySfvg : $@convention(method) (NotDifferentiable) -> Float + +// CHECK-LABEL: // NotDifferentiable.computedProperty.setter +// CHECK: sil hidden [_semantics "autodiff.nonvarying"] [ossa] @$s17noderivative_attr17NotDifferentiableV16computedPropertySfvs : $@convention(method) (Float, @inout NotDifferentiable) -> () + +// CHECK-LABEL: // NotDifferentiable.computedProperty.modify +// CHECK: sil hidden [_semantics "autodiff.nonvarying"] [ossa] @$s17noderivative_attr17NotDifferentiableV16computedPropertySfvM : $@yield_once @convention(method) (@inout NotDifferentiable) -> @yields @inout Float + +// CHECK-LABEL: // NotDifferentiable.instanceMethod(_:) +// CHECK: sil hidden [_semantics "autodiff.nonvarying"] [ossa] @$s17noderivative_attr17NotDifferentiableV14instanceMethodyS2fF : $@convention(method) (Float, NotDifferentiable) -> Float + +// CHECK-LABEL: // static NotDifferentiable.staticMethod(_:) +// CHECK: sil hidden [_semantics "autodiff.nonvarying"] [ossa] @$s17noderivative_attr17NotDifferentiableV12staticMethodyS2fFZ : $@convention(method) (Float, @thin NotDifferentiable.Type) -> Float + +// CHECK-LABEL: // NotDifferentiable.subscript.getter +// CHECK: sil hidden [_semantics "autodiff.nonvarying"] [ossa] @$s17noderivative_attr17NotDifferentiableVyS2fcig : $@convention(method) (Float, NotDifferentiable) -> Float + +// CHECK-LABEL: // NotDifferentiable.subscript.setter +// CHECK: sil hidden [_semantics "autodiff.nonvarying"] [ossa] @$s17noderivative_attr17NotDifferentiableVyS2fcis : $@convention(method) (Float, Float, @inout NotDifferentiable) -> () + +// CHECK-LABEL: // NotDifferentiable.subscript.modify +// CHECK: sil hidden [_semantics "autodiff.nonvarying"] [ossa] @$s17noderivative_attr17NotDifferentiableVyS2fciM : $@yield_once @convention(method) (Float, @inout NotDifferentiable) -> @yields @inout Float + +struct Bar: Differentiable { + @noDerivative var stored: Float +} + +// Test TF-152: derived conformances "no interface type set" crasher. +struct TF_152: Differentiable { + @differentiable(wrt: bar) + func applied(to input: Float, bar: TF_152_Bar) -> Float { + return input + } +} +struct TF_152_Bar: Differentiable { + @noDerivative let dense: Float +} diff --git a/test/AutoDiff/SILGen/noderivative_attr_cross_file.swift b/test/AutoDiff/SILGen/noderivative_attr_cross_file.swift new file mode 100644 index 0000000000000..7e4d2a08db69d --- /dev/null +++ b/test/AutoDiff/SILGen/noderivative_attr_cross_file.swift @@ -0,0 +1,10 @@ +// RUN: %target-swift-frontend -enable-experimental-differentiable-programming -emit-silgen %S/Inputs/noderivative_attr_other_file.swift %s | %FileCheck %s + +import _Differentiation + +@differentiable +func bar(_ x: Float) -> Float { + return Float(floatToIntNoDerivative(x)) +} + +// CHECK: sil hidden [_semantics "autodiff.nonvarying"] [ossa] @float_to_int_noderivative : $@convention(thin) (Float) -> Int diff --git a/test/AutoDiff/Sema/DerivedConformances/Inputs/class_differentiable_other_module.swift b/test/AutoDiff/Sema/DerivedConformances/Inputs/class_differentiable_other_module.swift new file mode 100644 index 0000000000000..99435939c4df1 --- /dev/null +++ b/test/AutoDiff/Sema/DerivedConformances/Inputs/class_differentiable_other_module.swift @@ -0,0 +1,9 @@ +import _Differentiation + +// expected-note @+1 {{type declared here}} +class OtherFileNonconforming {} + +// expected-note @+1 {{type declared here}} +class GenericOtherFileNonconforming { + var x: T +} diff --git a/test/AutoDiff/Sema/DerivedConformances/Inputs/struct_additive_arithmetic_other_module.swift b/test/AutoDiff/Sema/DerivedConformances/Inputs/struct_additive_arithmetic_other_module.swift index 92f45c786c4e5..4b9efbc951f04 100644 --- a/test/AutoDiff/Sema/DerivedConformances/Inputs/struct_additive_arithmetic_other_module.swift +++ b/test/AutoDiff/Sema/DerivedConformances/Inputs/struct_additive_arithmetic_other_module.swift @@ -1,11 +1,11 @@ // expected-note @+1 3 {{type declared here}} -struct OtherFileNonconforming : Equatable { +struct OtherFileNonconforming: Equatable { var int: Int var float: Float } // expected-note @+1 3 {{type declared here}} -struct GenericOtherFileNonconforming : Equatable { +struct GenericOtherFileNonconforming: Equatable { var x: T var int: Int var float: Float diff --git a/test/AutoDiff/Sema/DerivedConformances/Inputs/struct_differentiable_other_module.swift b/test/AutoDiff/Sema/DerivedConformances/Inputs/struct_differentiable_other_module.swift new file mode 100644 index 0000000000000..c3699349d3404 --- /dev/null +++ b/test/AutoDiff/Sema/DerivedConformances/Inputs/struct_differentiable_other_module.swift @@ -0,0 +1,9 @@ +import _Differentiation + +// expected-note @+1 {{type declared here}} +struct OtherFileNonconforming {} + +// expected-note @+1 {{type declared here}} +struct GenericOtherFileNonconforming { + var x: T +} diff --git a/test/AutoDiff/Sema/DerivedConformances/class_differentiable.swift b/test/AutoDiff/Sema/DerivedConformances/class_differentiable.swift new file mode 100644 index 0000000000000..4ee49828540c5 --- /dev/null +++ b/test/AutoDiff/Sema/DerivedConformances/class_differentiable.swift @@ -0,0 +1,539 @@ +// RUN: %target-swift-frontend -enable-experimental-differentiable-programming -typecheck -verify -primary-file %s %S/Inputs/class_differentiable_other_module.swift + +import _Differentiation + +// Verify that a type `T` conforms to `AdditiveArithmetic`. +func assertConformsToAdditiveArithmetic(_: T.Type) +where T: AdditiveArithmetic {} + +// Dummy protocol with default implementations for `AdditiveArithmetic` requirements. +// Used to test `Self : AdditiveArithmetic` requirements. +protocol DummyAdditiveArithmetic: AdditiveArithmetic {} +extension DummyAdditiveArithmetic { + static func == (lhs: Self, rhs: Self) -> Bool { + fatalError() + } + static var zero: Self { + fatalError() + } + static func + (lhs: Self, rhs: Self) -> Self { + fatalError() + } + static func - (lhs: Self, rhs: Self) -> Self { + fatalError() + } +} + +class Empty: Differentiable {} +func testEmpty() { + assertConformsToAdditiveArithmetic(Empty.TangentVector.self) +} + +// Test structs with `let` stored properties. +// Derived conformances fail because `mutating func move` requires all stored +// properties to be mutable. +class ImmutableStoredProperties: Differentiable { + var okay: Float + + // expected-warning @+1 {{stored property 'nondiff' has no derivative because 'Int' does not conform to 'Differentiable'; add an explicit '@noDerivative' attribute}} {{3-3=@noDerivative }} + let nondiff: Int + + // expected-warning @+1 {{synthesis of the 'Differentiable.move(along:)' requirement for 'ImmutableStoredProperties' requires all stored properties to be mutable; use 'var' instead, or add an explicit '@noDerivative' attribute}} {{3-3=@noDerivative }} + let diff: Float + + init() { + okay = 0 + nondiff = 0 + diff = 0 + } +} +func testImmutableStoredProperties() { + _ = ImmutableStoredProperties.TangentVector(okay: 1) +} +class MutableStoredPropertiesWithInitialValue: Differentiable { + var x = Float(1) + var y = Double(1) +} +// Test class with both an empty constructor and memberwise initializer. +class AllMixedStoredPropertiesHaveInitialValue: Differentiable { + let x = Float(1) // expected-warning {{synthesis of the 'Differentiable.move(along:)' requirement for 'AllMixedStoredPropertiesHaveInitialValue' requires all stored properties to be mutable; use 'var' instead, or add an explicit '@noDerivative' attribute}} {{3-3=@noDerivative }} + var y = Float(1) + // Memberwise initializer should be `init(y:)` since `x` is immutable. + static func testMemberwiseInitializer() { + _ = AllMixedStoredPropertiesHaveInitialValue() + } +} +/* +class HasCustomConstructor: Differentiable { + var x = Float(1) + var y = Float(1) + // Custom constructor should not affect synthesis. + init(x: Float, y: Float, z: Bool) {} +} +*/ + +class Simple: Differentiable { + var w: Float + var b: Float + + init(w: Float, b: Float) { + self.w = w + self.b = b + } +} +func testSimple() { + let simple = Simple(w: 1, b: 1) + let tangent = Simple.TangentVector(w: 1, b: 1) + simple.move(along: tangent) +} + +// Test type with mixed members. +class Mixed: Differentiable { + var simple: Simple + var float: Float + + init(simple: Simple, float: Float) { + self.simple = simple + self.float = float + } +} +func testMixed(_ simple: Simple, _ simpleTangent: Simple.TangentVector) { + let mixed = Mixed(simple: simple, float: 1) + let tangent = Mixed.TangentVector(simple: simpleTangent, float: 1) + mixed.move(along: tangent) +} + +// Test type with manual definition of vector space types to `Self`. +final class VectorSpacesEqualSelf: Differentiable & DummyAdditiveArithmetic { + var w: Float + var b: Float + typealias TangentVector = VectorSpacesEqualSelf + + init(w: Float, b: Float) { + self.w = w + self.b = b + } +} +/* +extension VectorSpacesEqualSelf : Equatable, AdditiveArithmetic { + static func == (lhs: VectorSpacesEqualSelf, rhs: VectorSpacesEqualSelf) -> Bool { + fatalError() + } + static var zero: VectorSpacesEqualSelf { + fatalError() + } + static func + (lhs: VectorSpacesEqualSelf, rhs: VectorSpacesEqualSelf) -> VectorSpacesEqualSelf { + fatalError() + } + static func - (lhs: VectorSpacesEqualSelf, rhs: VectorSpacesEqualSelf) -> VectorSpacesEqualSelf { + fatalError() + } +} +*/ + +// Test generic type with vector space types to `Self`. +class GenericVectorSpacesEqualSelf: Differentiable +where T: Differentiable, T == T.TangentVector { + var w: T + var b: T + + init(w: T, b: T) { + self.w = w + self.b = b + } +} +func testGenericVectorSpacesEqualSelf() { + let genericSame = GenericVectorSpacesEqualSelf(w: 1, b: 1) + let tangent = GenericVectorSpacesEqualSelf.TangentVector(w: 1, b: 1) + genericSame.move(along: tangent) +} + +// Test nested type. +class Nested: Differentiable { + var simple: Simple + var mixed: Mixed + var generic: GenericVectorSpacesEqualSelf + + init( + simple: Simple, mixed: Mixed, generic: GenericVectorSpacesEqualSelf + ) { + self.simple = simple + self.mixed = mixed + self.generic = generic + } +} +func testNested( + _ simple: Simple, _ mixed: Mixed, + _ genericSame: GenericVectorSpacesEqualSelf +) { + _ = Nested(simple: simple, mixed: mixed, generic: genericSame) +} + +// Test type that does not conform to `AdditiveArithmetic` but whose members do. +// Thus, `Self` cannot be used as `TangentVector` or `TangentVector`. +// Vector space structs types must be synthesized. +// Note: it would be nice to emit a warning if conforming `Self` to +// `AdditiveArithmetic` is possible. +class AllMembersAdditiveArithmetic: Differentiable { + var w: Float + var b: Float + + init(w: Float, b: Float) { + self.w = w + self.b = b + } +} + +// Test type whose properties are not all differentiable. +class DifferentiableSubset: Differentiable { + var w: Float + var b: Float + @noDerivative var flag: Bool + @noDerivative let technicallyDifferentiable: Float = .pi + + init(w: Float, b: Float, flag: Bool) { + self.w = w + self.b = b + self.flag = flag + } +} +func testDifferentiableSubset() { + _ = DifferentiableSubset.TangentVector(w: 1, b: 1) + _ = DifferentiableSubset.TangentVector(w: 1, b: 1) +} + +// Test nested type whose properties are not all differentiable. +class NestedDifferentiableSubset: Differentiable { + var x: DifferentiableSubset + var mixed: Mixed + @noDerivative var technicallyDifferentiable: Float + + init(x: DifferentiableSubset, mixed: Mixed) { + self.x = x + self.mixed = mixed + technicallyDifferentiable = 0 + } +} + +// Test type that uses synthesized vector space types but provides custom +// method. +class HasCustomMethod: Differentiable { + var simple: Simple + var mixed: Mixed + var generic: GenericVectorSpacesEqualSelf + + init( + simple: Simple, mixed: Mixed, generic: GenericVectorSpacesEqualSelf + ) { + self.simple = simple + self.mixed = mixed + self.generic = generic + } + + func move(along direction: TangentVector) { + print("Hello world") + simple.move(along: direction.simple) + mixed.move(along: direction.mixed) + generic.move(along: direction.generic) + } +} + +// Test type with user-defined memberwise initializer. +class TF_25: Differentiable { + public var bar: Float + public init(bar: Float) { + self.bar = bar + } +} +// Test user-defined memberwise initializer. +class TF_25_Generic: Differentiable { + public var bar: T + public init(bar: T) { + self.bar = bar + } +} + +// Test initializer that is not a memberwise initializer because of stored property name vs parameter label mismatch. +class HasCustomNonMemberwiseInitializer: Differentiable { + var value: T + init(randomLabel value: T) { self.value = value } +} + +// Test type with generic environment. +class HasGenericEnvironment: Differentiable +{ + var x: Float = 0 +} + +// Test type with generic members that conform to `Differentiable`. +class GenericSynthesizeAllStructs: Differentiable { + var w: T + var b: T + + init(w: T, b: T) { + self.w = w + self.b = b + } +} + +// Test type in generic context. +class A { + class B: Differentiable { + class InGenericContext: Differentiable { + @noDerivative var a: A + var b: B + var t: T + var u: U + + init(a: A, b: B, t: T, u: U) { + self.a = a + self.b = b + self.t = t + self.u = u + } + } + } +} + +// Test extension. +class Extended { + var x: Float + + init(x: Float) { + self.x = x + } +} +extension Extended: Differentiable {} + +// Test extension of generic type. +class GenericExtended { + var x: T + + init(x: T) { + self.x = x + } +} +extension GenericExtended: Differentiable where T: Differentiable {} + +// Test constrained extension of generic type. +class GenericConstrained { + var x: T + + init(x: T) { + self.x = x + } +} +extension GenericConstrained: Differentiable +where T: Differentiable {} + +final class TF_260: Differentiable & DummyAdditiveArithmetic +{ + var x: T.TangentVector + + init(x: T.TangentVector) { + self.x = x + } +} + +// TF-269: Test crash when differentiation properties have no getter. +// Related to access levels and associated type inference. + +// TODO(TF-631): Blocked by class type differentiation support. +// [AD] Unhandled instruction in adjoint emitter: %2 = ref_element_addr %0 : $TF_269, #TF_269.filter // user: %3 +// [AD] Diagnosing non-differentiability. +// [AD] For instruction: +// %2 = ref_element_addr %0 : $TF_269, #TF_269.filter // user: %3 +/* +public protocol TF_269_Layer: Differentiable & KeyPathIterable + where TangentVector: KeyPathIterable { + + associatedtype Input: Differentiable + associatedtype Output: Differentiable + func applied(to input: Input) -> Output +} + +public class TF_269 : TF_269_Layer { + public var filter: Float + public typealias Activation = @differentiable (Output) -> Output + @noDerivative public let activation: @differentiable (Output) -> Output + + init(filter: Float, activation: @escaping Activation) { + self.filter = filter + self.activation = activation + } + + // NOTE: `KeyPathIterable` derived conformances do not yet support class + // types. + public var allKeyPaths: [PartialKeyPath] { + [] + } + + public func applied(to input: Float) -> Float { + return input + } +} +*/ + +// Test errors. + +// expected-error @+1 {{class 'MissingInitializer' has no initializers}} +class MissingInitializer: Differentiable { + // expected-note @+1 {{stored property 'w' without initial value prevents synthesized initializers}} + var w: Float + // expected-note @+1 {{stored property 'b' without initial value prevents synthesized initializers}} + var b: Float +} + +// Test manually customizing vector space types. +// These should fail. Synthesis is semantically unsupported if vector space +// types are customized. +final class TangentVectorWB: DummyAdditiveArithmetic, Differentiable { + var w: Float + var b: Float + + init(w: Float, b: Float) { + self.w = w + self.b = b + } +} +// expected-error @+3 {{'Differentiable' requires the types 'VectorSpaceTypeAlias.TangentVector' (aka 'TangentVectorWB') and 'TangentVectorWB.TangentVector' be equivalent}} +// expected-note @+2 {{requirement specified as 'Self.TangentVector' == 'Self.TangentVector.TangentVector' [with Self = VectorSpaceTypeAlias]}} +// expected-error @+1 {{type 'VectorSpaceTypeAlias' does not conform to protocol 'Differentiable'}} +final class VectorSpaceTypeAlias: DummyAdditiveArithmetic, Differentiable { + var w: Float + var b: Float + typealias TangentVector = TangentVectorWB + + init(w: Float, b: Float) { + self.w = w + self.b = b + } +} +// expected-error @+1 {{type 'VectorSpaceCustomStruct' does not conform to protocol 'Differentiable'}} +final class VectorSpaceCustomStruct: DummyAdditiveArithmetic, Differentiable { + var w: Float + var b: Float + struct TangentVector: AdditiveArithmetic, Differentiable { + var w: Float.TangentVector + var b: Float.TangentVector + typealias TangentVector = VectorSpaceCustomStruct.TangentVector + } + + init(w: Float, b: Float) { + self.w = w + self.b = b + } +} + +class StaticNoDerivative: Differentiable { + @noDerivative static var s: Bool = true +} + +final class StaticMembersShouldNotAffectAnything: DummyAdditiveArithmetic, + Differentiable +{ + static var x: Bool = true + static var y: Bool = false +} + +class ImplicitNoDerivative: Differentiable { + var a: Float = 0 + var b: Bool = true // expected-warning {{stored property 'b' has no derivative because 'Bool' does not conform to 'Differentiable'; add an explicit '@noDerivative' attribute}} +} + +class ImplicitNoDerivativeWithSeparateTangent: Differentiable { + var x: DifferentiableSubset + var b: Bool = true // expected-warning {{stored property 'b' has no derivative because 'Bool' does not conform to 'Differentiable'; add an explicit '@noDerivative' attribute}} {{3-3=@noDerivative }} + + init(x: DifferentiableSubset) { + self.x = x + } +} + +// TF-1018: verify that `@noDerivative` warnings are always silenceable, even +// when the `Differentiable` conformance context is not the nominal type +// declaration. + +class ExtensionDifferentiableNoDerivative { + // expected-warning @+2 {{stored property 'x' has no derivative because 'T' does not conform to 'Differentiable'; add an explicit '@noDerivative' attribute}} + // expected-warning @+1 {{stored property 'y' has no derivative because 'T' does not conform to 'Differentiable'; add an explicit '@noDerivative' attribute}} + var x, y: T + // expected-warning @+1 {{stored property 'nondiff' has no derivative because 'Bool' does not conform to 'Differentiable'; add an explicit '@noDerivative' attribute}} + var nondiff: Bool + init() { fatalError() } +} +extension ExtensionDifferentiableNoDerivative: Differentiable {} + +class ExtensionDifferentiableNoDerivativeFixed { + @noDerivative var x, y: T + @noDerivative var nondiff: Bool + init() { fatalError() } +} +extension ExtensionDifferentiableNoDerivativeFixed: Differentiable {} + +class ConditionalDifferentiableNoDerivative { + var x, y: T + // expected-warning @+1 {{stored property 'nondiff' has no derivative because 'Bool' does not conform to 'Differentiable'; add an explicit '@noDerivative' attribute}} + var nondiff: Bool + init() { fatalError() } +} +extension ConditionalDifferentiableNoDerivative: Differentiable +where T: Differentiable {} + +class ConditionalDifferentiableNoDerivativeFixed { + var x, y: T + @noDerivative var nondiff: Bool + init() { fatalError() } +} +extension ConditionalDifferentiableNoDerivativeFixed: Differentiable +where T: Differentiable {} + +// TF-265: Test invalid initializer (that uses a non-existent type). +class InvalidInitializer: Differentiable { + init(filterShape: (Int, Int, Int, Int), blah: NonExistentType) {} // expected-error {{use of undeclared type 'NonExistentType'}} +} + +// Test memberwise initializer synthesis. +final class NoMemberwiseInitializerExtended { + var value: T + init(_ value: T) { + self.value = value + } +} +extension NoMemberwiseInitializerExtended: Equatable, AdditiveArithmetic, + DummyAdditiveArithmetic +where T: AdditiveArithmetic {} +extension NoMemberwiseInitializerExtended: Differentiable +where T: Differentiable & AdditiveArithmetic {} + +// TF-1190: Test `@noDerivative` warning for property wrapper backing storage properties. + +@propertyWrapper +struct Wrapper { + private var value: Value + var wrappedValue: Value { + get { value } + set { value = newValue } + } +} +struct TF_1190 {} +class TF_1190_Outer: Differentiable { + // expected-warning @+1 {{stored property '_x' has no derivative because 'Wrapper>' does not conform to 'Differentiable'; add an explicit '@noDerivative' attribute}} + @Wrapper var x: TF_1190 + @noDerivative @Wrapper var y: TF_1190 + + init(x: TF_1190, y: TF_1190) { + self.x = x + self.y = y + } +} + +// Test derived conformances in disallowed contexts. + +// expected-error @+2 {{type 'OtherFileNonconforming' does not conform to protocol 'Differentiable'}} +// expected-error @+1 {{implementation of 'Differentiable' cannot be automatically synthesized in an extension in a different file to the type}} +extension OtherFileNonconforming: Differentiable {} + +// expected-error @+2 {{type 'GenericOtherFileNonconforming' does not conform to protocol 'Differentiable'}} +// expected-error @+1 {{implementation of 'Differentiable' cannot be automatically synthesized in an extension in a different file to the type}} +extension GenericOtherFileNonconforming: Differentiable {} diff --git a/test/AutoDiff/Sema/DerivedConformances/derived_differentiable.swift b/test/AutoDiff/Sema/DerivedConformances/derived_differentiable.swift new file mode 100644 index 0000000000000..a5bed880a7a39 --- /dev/null +++ b/test/AutoDiff/Sema/DerivedConformances/derived_differentiable.swift @@ -0,0 +1,82 @@ +// RUN: %target-swift-frontend -enable-experimental-differentiable-programming -print-ast %s | %FileCheck %s --check-prefix=CHECK-AST + +import _Differentiation + +struct GenericTangentVectorMember: Differentiable, + AdditiveArithmetic +{ + var x: T.TangentVector +} + +// CHECK-AST-LABEL: internal struct GenericTangentVectorMember : Differentiable, AdditiveArithmetic where T : Differentiable +// CHECK-AST: internal var x: T.TangentVector +// CHECK-AST: internal init(x: T.TangentVector) +// CHECK-AST: internal typealias TangentVector = GenericTangentVectorMember +// CHECK-AST: internal static var zero: GenericTangentVectorMember { get } +// CHECK-AST: internal static func + (lhs: GenericTangentVectorMember, rhs: GenericTangentVectorMember) -> GenericTangentVectorMember +// CHECK-AST: internal static func - (lhs: GenericTangentVectorMember, rhs: GenericTangentVectorMember) -> GenericTangentVectorMember +// CHECK-AST: @_implements(Equatable, ==(_:_:)) internal static func __derived_struct_equals(_ a: GenericTangentVectorMember, _ b: GenericTangentVectorMember) -> Bool + +public struct ConditionallyDifferentiable { + public var x: T +} +extension ConditionallyDifferentiable: Differentiable where T: Differentiable {} + +// CHECK-AST-LABEL: public struct ConditionallyDifferentiable { +// CHECK-AST: @differentiable(wrt: self where T : Differentiable) +// CHECK-AST: public var x: T +// CHECK-AST: internal init(x: T) +// CHECK-AST: } + +// Verify that `TangentVector` is not synthesized to be `Self` for +// `AdditiveArithmetic`-conforming classes. +final class AdditiveArithmeticClass: AdditiveArithmetic, + Differentiable +{ + var x, y: T + init(x: T, y: T) { + self.x = x + self.y = y + } + + // Dummy `AdditiveArithmetic` requirements. + static func == (lhs: AdditiveArithmeticClass, rhs: AdditiveArithmeticClass) + -> Bool + { + fatalError() + } + static var zero: AdditiveArithmeticClass { + fatalError() + } + static func + (lhs: AdditiveArithmeticClass, rhs: AdditiveArithmeticClass) + -> Self + { + fatalError() + } + static func - (lhs: AdditiveArithmeticClass, rhs: AdditiveArithmeticClass) + -> Self + { + fatalError() + } +} + +// CHECK-AST-LABEL: final internal class AdditiveArithmeticClass : AdditiveArithmetic, Differentiable where T : AdditiveArithmetic, T : Differentiable { +// CHECK-AST: final internal var x: T, y: T +// CHECK-AST: internal struct TangentVector : Differentiable, AdditiveArithmetic +// CHECK-AST: } + +@frozen +public struct FrozenStruct: Differentiable {} + +// CHECK-AST-LABEL: @frozen public struct FrozenStruct : Differentiable { +// CHECK-AST: internal init() +// CHECK-AST: @frozen public struct TangentVector : Differentiable, AdditiveArithmetic { + +@usableFromInline +struct UsableFromInlineStruct: Differentiable {} + +// CHECK-AST-LABEL: @usableFromInline +// CHECK-AST: struct UsableFromInlineStruct : Differentiable { +// CHECK-AST: internal init() +// CHECK-AST: @usableFromInline +// CHECK-AST: struct TangentVector : Differentiable, AdditiveArithmetic { diff --git a/test/AutoDiff/Sema/DerivedConformances/struct_additive_arithmetic.swift b/test/AutoDiff/Sema/DerivedConformances/struct_additive_arithmetic.swift index 4c0048b2de8ad..4d7dffcefade3 100644 --- a/test/AutoDiff/Sema/DerivedConformances/struct_additive_arithmetic.swift +++ b/test/AutoDiff/Sema/DerivedConformances/struct_additive_arithmetic.swift @@ -2,7 +2,7 @@ import _Differentiation -func testAdditiveArithmetic( +func testAdditiveArithmetic( _ x: inout T ) { // Test `AdditiveArithmetic` requirements: `zero`, `+`, `-`. @@ -11,7 +11,7 @@ func testAdditiveArithmetic( x -= x - zero } -struct Empty : AdditiveArithmetic {} +struct Empty: AdditiveArithmetic {} func testEmpty() { var empty = Empty() testAdditiveArithmetic(&empty) @@ -27,7 +27,7 @@ func testInt2() { } // Test generic type. -struct Vector2: AdditiveArithmetic { +struct Vector2: AdditiveArithmetic { var x: T var y: T } @@ -61,14 +61,16 @@ func testMixed(nested: Nested) { // Test type in generic context. struct A { struct B { - struct GenericContextNested : AdditiveArithmetic { + struct GenericContextNested: AdditiveArithmetic { var nested: Nested var float: Float var uint8: UInt8 } } } -func testGenericContext(nested: Nested) -> A.B.GenericContextNested { +func testGenericContext(nested: Nested) + -> A.B.GenericContextNested +{ var genericNested = A.B.GenericContextNested(nested: nested, float: 1, uint8: 1) testAdditiveArithmetic(&genericNested) @@ -79,16 +81,17 @@ func testGenericContext(nested: Nested) -> A.B.GenericContextN struct Extended { var x: Int } -extension Extended : Equatable, AdditiveArithmetic {} +extension Extended: Equatable, AdditiveArithmetic {} // Test extension of generic type. struct GenericExtended { var x: T } -extension GenericExtended : Equatable, AdditiveArithmetic where T : AdditiveArithmetic {} +extension GenericExtended: Equatable, AdditiveArithmetic +where T: AdditiveArithmetic {} // Test memberwise initializer synthesis. -struct NoMemberwiseInitializer : AdditiveArithmetic { +struct NoMemberwiseInitializer: AdditiveArithmetic { var value: T init(randomLabel value: T) { self.value = value } } @@ -106,12 +109,12 @@ struct NoMemberwiseInitializerExtended { } } extension NoMemberwiseInitializerExtended: Equatable, AdditiveArithmetic - where T : AdditiveArithmetic {} +where T: AdditiveArithmetic {} // Test derived conformances in disallowed contexts. // expected-error @+1 3 {{implementation of 'AdditiveArithmetic' cannot be automatically synthesized in an extension in a different file to the type}} -extension OtherFileNonconforming : AdditiveArithmetic {} +extension OtherFileNonconforming: AdditiveArithmetic {} // expected-error @+1 3 {{implementation of 'AdditiveArithmetic' cannot be automatically synthesized in an extension in a different file to the type}} -extension GenericOtherFileNonconforming : AdditiveArithmetic {} +extension GenericOtherFileNonconforming: AdditiveArithmetic {} diff --git a/test/AutoDiff/Sema/DerivedConformances/struct_differentiable.swift b/test/AutoDiff/Sema/DerivedConformances/struct_differentiable.swift new file mode 100644 index 0000000000000..722c13e4f26e9 --- /dev/null +++ b/test/AutoDiff/Sema/DerivedConformances/struct_differentiable.swift @@ -0,0 +1,350 @@ +// RUN: %target-swift-frontend -enable-experimental-differentiable-programming -typecheck -verify -primary-file %s %S/Inputs/struct_differentiable_other_module.swift + +import _Differentiation + +// Verify that a type `T` conforms to `AdditiveArithmetic`. +func assertConformsToAdditiveArithmetic(_: T.Type) +where T: AdditiveArithmetic {} + +struct Empty: Differentiable {} +func testEmpty() { + assertConformsToAdditiveArithmetic(Empty.TangentVector.self) +} + +// Test interaction with `AdditiveArithmetic` derived conformances. +// Previously, this crashed due to duplicate memberwise initializer synthesis. +struct EmptyAdditiveArithmetic: AdditiveArithmetic, Differentiable {} + +// Test structs with `let` stored properties. +// Derived conformances fail because `mutating func move` requires all stored +// properties to be mutable. +struct ImmutableStoredProperties: Differentiable { + var okay: Float + + // expected-warning @+1 {{stored property 'nondiff' has no derivative because 'Int' does not conform to 'Differentiable'; add an explicit '@noDerivative' attribute, or conform 'ImmutableStoredProperties' to 'AdditiveArithmetic'}} {{3-3=@noDerivative }} + let nondiff: Int + + // expected-warning @+1 {{synthesis of the 'Differentiable.move(along:)' requirement for 'ImmutableStoredProperties' requires all stored properties to be mutable; use 'var' instead, or add an explicit '@noDerivative' attribute, or conform 'ImmutableStoredProperties' to 'AdditiveArithmetic'}} {{3-3=@noDerivative }} + let diff: Float +} +func testImmutableStoredProperties() { + _ = ImmutableStoredProperties.TangentVector(okay: 1) +} +struct MutableStoredPropertiesWithInitialValue: Differentiable { + var x = Float(1) + var y = Double(1) +} +// Test struct with both an empty constructor and memberwise initializer. +struct AllMixedStoredPropertiesHaveInitialValue: Differentiable { + let x = Float(1) // expected-warning {{synthesis of the 'Differentiable.move(along:)' requirement for 'AllMixedStoredPropertiesHaveInitialValue' requires all stored properties to be mutable; use 'var' instead, or add an explicit '@noDerivative' attribute}} {{3-3=@noDerivative }} + var y = Float(1) + // Memberwise initializer should be `init(y:)` since `x` is immutable. + static func testMemberwiseInitializer() { + _ = AllMixedStoredPropertiesHaveInitialValue(y: 1) + } +} +struct HasCustomConstructor: Differentiable { + var x = Float(1) + var y = Float(1) + // Custom constructor should not affect synthesis. + init(x: Float, y: Float, z: Bool) {} +} + +struct Simple: AdditiveArithmetic, Differentiable { + var w: Float + var b: Float +} +func testSimple() { + var simple = Simple(w: 1, b: 1) + simple.move(along: simple) +} + +// Test type with mixed members. +struct Mixed: AdditiveArithmetic, Differentiable { + var simple: Simple + var float: Float +} +func testMixed(_ simple: Simple) { + var mixed = Mixed(simple: simple, float: 1) + mixed.move(along: mixed) +} + +// Test type with manual definition of vector space types to `Self`. +struct VectorSpacesEqualSelf: AdditiveArithmetic, Differentiable { + var w: Float + var b: Float + typealias TangentVector = VectorSpacesEqualSelf +} + +// Test generic type with vector space types to `Self`. +struct GenericVectorSpacesEqualSelf: AdditiveArithmetic, Differentiable +where T: Differentiable, T == T.TangentVector { + var w: T + var b: T +} +func testGenericVectorSpacesEqualSelf() { + var genericSame = GenericVectorSpacesEqualSelf(w: 1, b: 1) + genericSame.move(along: genericSame) +} + +// Test nested type. +struct Nested: AdditiveArithmetic, Differentiable { + var simple: Simple + var mixed: Mixed + var generic: GenericVectorSpacesEqualSelf +} +func testNested( + _ simple: Simple, _ mixed: Mixed, + _ genericSame: GenericVectorSpacesEqualSelf +) { + var nested = Nested(simple: simple, mixed: mixed, generic: genericSame) + nested.move(along: nested) +} + +// Test type that does not conform to `AdditiveArithmetic` but whose members do. +// Thus, `Self` cannot be used as `TangentVector` or `TangentVector`. +// Vector space structs types must be synthesized. +// Note: it would be nice to emit a warning if conforming `Self` to +// `AdditiveArithmetic` is possible. +struct AllMembersAdditiveArithmetic: Differentiable { + var w: Float + var b: Float +} + +// Test type whose properties are not all differentiable. +struct DifferentiableSubset: Differentiable { + var w: Float + var b: Float + @noDerivative var flag: Bool + @noDerivative let technicallyDifferentiable: Float = .pi +} +func testDifferentiableSubset() { + _ = DifferentiableSubset.TangentVector(w: 1, b: 1) + _ = DifferentiableSubset.TangentVector(w: 1, b: 1) +} + +// Test nested type whose properties are not all differentiable. +struct NestedDifferentiableSubset: Differentiable { + var x: DifferentiableSubset + var mixed: Mixed + @noDerivative var technicallyDifferentiable: Float +} + +// Test type that uses synthesized vector space types but provides custom +// method. +struct HasCustomMethod: Differentiable { + var simple: Simple + var mixed: Mixed + var generic: GenericVectorSpacesEqualSelf + mutating func move(along direction: TangentVector) { + print("Hello world") + simple.move(along: direction.simple) + mixed.move(along: direction.mixed) + generic.move(along: direction.generic) + } +} + +// Test type with user-defined memberwise initializer. +struct TF_25: Differentiable { + public var bar: Float + public init(bar: Float) { + self.bar = bar + } +} +// Test user-defined memberwise initializer. +struct TF_25_Generic: Differentiable { + public var bar: T + public init(bar: T) { + self.bar = bar + } +} + +// Test initializer that is not a memberwise initializer because of stored property name vs parameter label mismatch. +struct HasCustomNonMemberwiseInitializer: Differentiable { + var value: T + init(randomLabel value: T) { self.value = value } +} + +// Test type with generic environment. +struct HasGenericEnvironment: Differentiable +{ + var x: Float +} + +// Test type with generic members that conform to `Differentiable`. +struct GenericSynthesizeAllStructs: Differentiable { + var w: T + var b: T +} + +// Test type in generic context. +struct A { + struct B: Differentiable { + struct InGenericContext: Differentiable { + @noDerivative var a: A + var b: B + var t: T + var u: U + } + } +} + +// Test extension. +struct Extended { + var x: Float +} +extension Extended: Differentiable {} + +// Test extension of generic type. +struct GenericExtended { + var x: T +} +extension GenericExtended: Differentiable where T: Differentiable {} + +// Test constrained extension of generic type. +struct GenericConstrained { + var x: T +} +extension GenericConstrained: Differentiable +where T: Differentiable {} + +struct TF_260: Differentiable, AdditiveArithmetic { + var x: T.TangentVector +} + +// TF-269: Test crash when differentiation properties have no getter. +// Related to access levels and associated type inference. +public protocol TF_269_Layer: Differentiable { + associatedtype Input: Differentiable + associatedtype Output: Differentiable + func applied(to input: Input) -> Output +} + +public struct TF_269: TF_269_Layer { + public var filter: Float + public typealias Activation = @differentiable (Output) -> Output + @noDerivative public let activation: Activation + + public func applied(to input: Float) -> Float { + return input + } +} + +// Test errors. + +// Test manually customizing vector space types. +// Thees should fail. Synthesis is semantically unsupported if vector space +// types are customized. +// expected-error @+1 {{type 'VectorSpaceTypeAlias' does not conform to protocol 'Differentiable'}} +struct VectorSpaceTypeAlias: AdditiveArithmetic, Differentiable { + var w: Float + var b: Float + typealias TangentVector = Simple +} +// expected-error @+1 {{type 'VectorSpaceCustomStruct' does not conform to protocol 'Differentiable'}} +struct VectorSpaceCustomStruct: AdditiveArithmetic, Differentiable { + var w: Float + var b: Float + struct TangentVector: AdditiveArithmetic, Differentiable { + var w: Float.TangentVector + var b: Float.TangentVector + typealias TangentVector = VectorSpaceCustomStruct.TangentVector + } +} + +struct StaticNoDerivative: Differentiable { + @noDerivative static var s: Bool = true +} + +struct StaticMembersShouldNotAffectAnything: AdditiveArithmetic, Differentiable +{ + static var x: Bool = true + static var y: Bool = false +} + +struct ImplicitNoDerivative: Differentiable { + var a: Float + var b: Bool // expected-warning {{stored property 'b' has no derivative because 'Bool' does not conform to 'Differentiable'; add an explicit '@noDerivative' attribute}} +} + +struct ImplicitNoDerivativeWithSeparateTangent: Differentiable { + var x: DifferentiableSubset + var b: Bool // expected-warning {{stored property 'b' has no derivative because 'Bool' does not conform to 'Differentiable'; add an explicit '@noDerivative' attribute}} {{3-3=@noDerivative }} +} + +// TF-1018: verify that `@noDerivative` warnings are always silenceable, even +// when the `Differentiable` conformance context is not the nominal type +// declaration. + +struct ExtensionDifferentiableNoDerivative { + // expected-warning @+2 {{stored property 'x' has no derivative because 'T' does not conform to 'Differentiable'; add an explicit '@noDerivative' attribute}} + // expected-warning @+1 {{stored property 'y' has no derivative because 'T' does not conform to 'Differentiable'; add an explicit '@noDerivative' attribute}} + var x, y: T + // expected-warning @+1 {{stored property 'nondiff' has no derivative because 'Bool' does not conform to 'Differentiable'; add an explicit '@noDerivative' attribute}} + var nondiff: Bool +} +extension ExtensionDifferentiableNoDerivative: Differentiable {} + +struct ExtensionDifferentiableNoDerivativeFixed { + @noDerivative var x, y: T + @noDerivative var nondiff: Bool +} +extension ExtensionDifferentiableNoDerivativeFixed: Differentiable {} + +struct ConditionalDifferentiableNoDerivative { + var x, y: T + // expected-warning @+1 {{stored property 'nondiff' has no derivative because 'Bool' does not conform to 'Differentiable'; add an explicit '@noDerivative' attribute}} + var nondiff: Bool +} +extension ConditionalDifferentiableNoDerivative: Differentiable +where T: Differentiable {} + +struct ConditionalDifferentiableNoDerivativeFixed { + var x, y: T + @noDerivative var nondiff: Bool +} +extension ConditionalDifferentiableNoDerivativeFixed: Differentiable +where T: Differentiable {} + +// TF-265: Test invalid initializer (that uses a non-existent type). +struct InvalidInitializer: Differentiable { + init(filterShape: (Int, Int, Int, Int), blah: NonExistentType) {} // expected-error {{use of undeclared type 'NonExistentType'}} +} + +// Test memberwise initializer synthesis. +struct NoMemberwiseInitializerExtended { + var value: T + init(_ value: T) { + self.value = value + } +} +extension NoMemberwiseInitializerExtended: Equatable, AdditiveArithmetic +where T: AdditiveArithmetic {} +extension NoMemberwiseInitializerExtended: Differentiable +where T: Differentiable & AdditiveArithmetic {} + +// TF-1190: Test `@noDerivative` warning for property wrapper backing storage properties. + +@propertyWrapper +struct Wrapper { + private var value: Value + var wrappedValue: Value { + value + } +} +struct TF_1190 {} +struct TF_1190_Outer: Differentiable { + // expected-warning @+1 {{stored property '_x' has no derivative because 'Wrapper>' does not conform to 'Differentiable'; add an explicit '@noDerivative' attribute}} + @Wrapper var x: TF_1190 + @noDerivative @Wrapper var y: TF_1190 +} + +// Verify that cross-file derived conformances are disallowed. + +// expected-error @+2 {{type 'OtherFileNonconforming' does not conform to protocol 'Differentiable'}} +// expected-error @+1 {{implementation of 'Differentiable' cannot be automatically synthesized in an extension in a different file to the type}} +extension OtherFileNonconforming: Differentiable {} + +// expected-error @+2 {{type 'GenericOtherFileNonconforming' does not conform to protocol 'Differentiable'}} +// expected-error @+1 {{implementation of 'Differentiable' cannot be automatically synthesized in an extension in a different file to the type}} +extension GenericOtherFileNonconforming: Differentiable {} diff --git a/test/AutoDiff/Sema/DerivedConformances/struct_differentiable_member_types.swift b/test/AutoDiff/Sema/DerivedConformances/struct_differentiable_member_types.swift new file mode 100644 index 0000000000000..4a602c301edc8 --- /dev/null +++ b/test/AutoDiff/Sema/DerivedConformances/struct_differentiable_member_types.swift @@ -0,0 +1,15 @@ +// RUN: %target-typecheck-verify-swift -enable-experimental-differentiable-programming + +import _Differentiation + +// Test usages of synthesized `Differentiable` member struct types. + +// TF-466: Test conforming a synthesized member type to a protocol with +// property requirements. +protocol Protocol { + var weight: Float { get } +} +struct Struct: Differentiable { + var weight: Float +} +extension Struct.TangentVector: Protocol {} diff --git a/test/AutoDiff/Sema/transpose_attr_type_checking.swift b/test/AutoDiff/Sema/transpose_attr_type_checking.swift new file mode 100644 index 0000000000000..2eeb9737fc90a --- /dev/null +++ b/test/AutoDiff/Sema/transpose_attr_type_checking.swift @@ -0,0 +1,595 @@ +// RUN: %target-swift-frontend-typecheck -enable-experimental-differentiable-programming -verify %s + +import _Differentiation + +// ~~~~~~~~~~~~~ Test top-level functions. ~~~~~~~~~~~~~ + +func linearFunc(_ x: Float) -> Float { + return x +} + +@transpose(of: linearFunc, wrt: 0) +func linearFuncTranspose(x: Float) -> Float { + return x +} + +func twoParams(_ x: Float, _ y: Double) -> Double { + return Double(x) + y +} + +@transpose(of: twoParams, wrt: 0) +func twoParamsT1(_ y: Double, _ t: Double) -> Float { + return Float(t + y) +} + +@transpose(of: twoParams, wrt: 1) +func twoParamsT2(_ x: Float, _ t: Double) -> Double { + return Double(x) + t +} + +@transpose(of: twoParams, wrt: (0, 1)) +func twoParamsT3(_ t: Double) -> (Float, Double) { + return (Float(t), t) +} + +func threeParams(_ x: Float, _ y: Double, _ z: Float) -> Double { + return Double(x) + y +} + +@transpose(of: threeParams, wrt: 0) +func threeParamsT1(_ y: Double, _ z: Float, _ t: Double) -> Float { + return Float(t + y) + z +} + +@transpose(of: threeParams, wrt: 1) +func threeParamsT2(_ x: Float, _ z: Float, _ t: Double) -> Double { + return Double(x + z) + t +} + +@transpose(of: threeParams, wrt: 2) +func threeParamsT3(_ x: Float, _ y: Double, _ t: Double) -> Float { + return Float(y + t) + x +} + +@transpose(of: threeParams, wrt: (0, 1)) +func threeParamsT4(_ z: Float, _ t: Double) -> (Float, Double) { + return (z + Float(t), Double(z) + t) +} + +@transpose(of: threeParams, wrt: (0, 2)) +func threeParamsT5(_ y: Double, _ t: Double) -> (Float, Float) { + let ret = Float(y + t) + return (ret, ret) +} + +@transpose(of: threeParams, wrt: (0, 1, 2)) +func threeParamsT5(_ t: Double) -> (Float, Double, Float) { + let ret = Float(t) + return (ret, t, ret) +} + +// Generics +func generic(x: T) -> T where T == T.TangentVector { + return x +} + +@transpose(of: generic, wrt: 0) +func genericT(x: T) -> T where T == T.TangentVector { + return x +} + +func genericThreeParam< + T: Differentiable & BinaryFloatingPoint, + U: Differentiable & BinaryFloatingPoint, + V: Differentiable & BinaryFloatingPoint>( + t: T, u: U, v: V +) -> T where T == T.TangentVector, + U == U.TangentVector, + V == V.TangentVector { + return t +} + +@transpose(of: genericThreeParam, wrt: 1) +func genericThreeParamT2< + T: Differentiable & BinaryFloatingPoint, + U: Differentiable & BinaryFloatingPoint, + V: Differentiable & BinaryFloatingPoint>( + t: T, v: V, s: T +) -> U where T == T.TangentVector, + U == U.TangentVector, + V == V.TangentVector { + return U(1) +} + +@transpose(of: genericThreeParam, wrt: (0, 1, 2)) +func genericThreeParamT2< + T: Differentiable & BinaryFloatingPoint, + U: Differentiable & BinaryFloatingPoint, + V: Differentiable & BinaryFloatingPoint>( + t: T +) -> (T, U, V) where T == T.TangentVector, + U == U.TangentVector, + V == V.TangentVector { + return (T(1), U(1), V(1)) +} + +func genericOneParamFloatOneParam( + t: T, f: Float +) -> T where T == T.TangentVector { + return T(f) +} + +@transpose(of: genericOneParamFloatOneParam, wrt: 0) +func genericOneParamFloatOneParamT1( + f: Float, t: T +) -> T where T == T.TangentVector { + return t +} + +@transpose(of: genericOneParamFloatOneParam, wrt: 1) +func genericOneParamFloatOneParamT1( + t1: T, t2: T +) -> Float where T == T.TangentVector { + return 1 +} + +@transpose(of: genericOneParamFloatOneParam, wrt: (0, 1)) +func genericOneParamFloatOneParamT1( + t: T +) -> (T, Float) where T == T.TangentVector { + return (T(1), 1) +} + +func withInt(x: Float, y: Int) -> Float { + if y >= 0 { + return x + } else { + return x + } +} + +@transpose(of: withInt, wrt: 0) +func withIntT(x: Int, t: Float) -> Float { + return t +} + +func missingDiffSelfRequirement(x: T) -> T { + return x +} + +// expected-error @+1 {{cannot transpose with respect to original result 'T' that does not conform to 'Differentiable' and satisfy 'T == T.TangentVector'}} +@transpose(of: missingDiffSelfRequirement, wrt: 0) +func missingDiffSelfRequirementT(x: T) -> T { + return x +} + +func missingSelfRequirement(x: T) + -> T where T.TangentVector == T { + return x +} + +// expected-error @+1 {{cannot transpose with respect to original result 'T' that does not conform to 'Differentiable' and satisfy 'T == T.TangentVector'}} +@transpose(of: missingSelfRequirement, wrt: 0) +func missingSelfRequirementT(x: T) -> T { + return x +} + +func differentGenericConstraint(x: T) +-> T where T == T.TangentVector { + return x +} + +// expected-error @+1 {{could not find function 'differentGenericConstraint' with expected type ' (T) -> T'}} +@transpose(of: differentGenericConstraint, wrt: 0) +func differentGenericConstraintT(x: T) +-> T where T == T.TangentVector { + return x +} + +func transposingInt(x: Float, y: Int) -> Float { + if y >= 0 { + return x + } else { + return x + } +} + +// expected-error @+1 {{cannot transpose with respect to original parameter 'Int' that does not conform to 'Differentiable' and satisfy 'Int == Int.TangentVector'}} +@transpose(of: transposingInt, wrt: 1) +func transposingIntT1(x: Float, t: Float) -> Int { + return Int(x) +} + +@transpose(of: transposingInt, wrt: 0) +func tangentNotLast(y: Int, t: Float) -> Float { + return t +} + +// ~~~~~~~~~~~~~ Test methods. ~~~~~~~~~~~~~ + +// // Method no parameters. +extension Float { + func getDouble() -> Double { + return Double(self) + } + + @transpose(of: Float.getDouble, wrt: self) + static func structTranspose(v: Double) -> Float { + return Float(v) + } +} + +// Method with one parameter. +extension Float { + func adding(_ double: Double) -> Float { + return self + Float(double) + } + + @transpose(of: Float.adding, wrt: 0) + func addingT1(t: Float) -> Double { + return Double(self + t) + } + + @transpose(of: Float.adding, wrt: self) + static func addingT2(_ double: Double, t: Float) -> Float { + return Float(double) + t + } + + @transpose(of: Float.adding, wrt: (self, 0)) + static func addingT3(t: Float) -> (Float, Double) { + return (t, Double(t)) + } +} + +// Different self type/result type. +extension Int { + func myAdding(_ double: Double) -> Float { + return Float(double) + } + + @transpose(of: Int.myAdding, wrt: 0) + func addingT3(t: Float) -> Double { + return Double(t) + } + + // expected-error @+1 {{cannot transpose with respect to original parameter 'Int' that does not conform to 'Differentiable' and satisfy 'Int == Int.TangentVector'}} + @transpose(of: Int.myAdding, wrt: (self, 0)) + static func addingT3(v: Float) -> (Int, Double) { + return (Int(v), Double(v)) + } +} + +// Static methods. +struct A : Differentiable & AdditiveArithmetic { + typealias TangentVector = A + var x: Double + + static prefix func -(a: A) -> A { + return A(x: -a.x) + } + + @transpose(of: -, wrt: 0) + static func transposeNegate(t: A) -> A { + return A(x: -t.x) + } + + static prefix func +(a: A) -> A { + return a + } + + // TODO(TF-1065): Consider disallowing qualified operator names. + @transpose(of: A.+, wrt: 0) + static func transposeIdQualified(t: A) -> A { + return t + } +} + +extension Float { + static func myMultiply(lhs: Float, rhs: Float) -> Float { + return lhs * rhs + } + + @transpose(of: Float.myMultiply, wrt: 0) + @transpose(of: Float.myMultiply, wrt: 1) + static func myMultiplyT(param: Float, v: Float) -> Float { + return param + v + } + + static func threeParamsStatic(_ x: Float, _ y: Double, _ z: Float) -> Double { + return Double(x + z) + y + } + + @transpose(of: Float.threeParamsStatic, wrt: (0, 1, 2)) + static func threeParamsT12(v: Double) -> (x: Float, y: Double, z: Float) { + return (Float(v), v, Float(v)) + } + + @transpose(of: Float.threeParamsStatic, wrt: (0, 2)) + static func threeParamsT12(_ y: Double, v: Double) -> (x: Float, z: Float) { + let ret = Float(y + v) + return (ret, ret) + } + + @transpose(of: Float.threeParamsStatic, wrt: 1) + static func threeParamsT12(_ x: Float, _ z: Float, v: Double) -> Double { + return v + Double(x + z) + } +} + +// Method with 3 parameters. +extension Float { + func threeParams(_ x: Float, _ y: Double, _ z: Float) -> Double { + return Double(self + x + z) + y + } + + @transpose(of: Float.threeParams, wrt: 0) + func threeParamsT1(_ y: Double, _ z: Float, t: Double) -> Float { + return self + Float(t + y) + z + } + + @transpose(of: Float.threeParams, wrt: 1) + func threeParamsT2(_ x: Float, _ z: Float, t: Double) -> Double { + return t + Double(x + z + self) + } + + @transpose(of: Float.threeParams, wrt: 2) + func threeParamsT3(_ x: Float, _ y: Double, t: Double) -> Float { + return x + Float(y + t) + self + } + + @transpose(of: Float.threeParams, wrt: (0, 1)) + func threeParamsT4(_ z: Float, t: Double) -> (x: Float, y: Double) { + return (Float(t) + z + self, t + Double(z + self)) + } + + @transpose(of: Float.threeParams, wrt: (0, 2)) + func threeParamsT5(_ y: Double, t: Double) -> (x: Float, z: Float) { + let ret = Float(y + t) + self + return (ret, ret) + } + + @transpose(of: Float.threeParams, wrt: (0, 1, 2)) + func threeParamsT6(t: Double) -> (x: Float, y: Double, z: Float) { + return (Float(t) + self, t + Double(self), Float(t) + self) + } + + @transpose(of: Float.threeParams, wrt: self) + static func threeParamsT6(_ x: Float, _ y: Double, _ z: Float, t: Double) -> Float { + return x + z + Float(y + t) + } + + @transpose(of: Float.threeParams, wrt: (self, 0)) + static func threeParamsT7(_ y: Double, _ z: Float, t: Double) -> (self: Float, x: Float) { + let ret = Float(y + t) + z + return (ret, ret) + } + + @transpose(of: Float.threeParams, wrt: (self, 1)) + static func threeParamsT7(_ x: Float, _ z: Float, t: Double) -> (self: Float, y: Double) { + return (x + z + Float(t), t + Double(x + z)) + } + + @transpose(of: Float.threeParams, wrt: (self, 2)) + static func threeParamsT9(_ x: Float, _ y: Double, t: Double) -> (self: Float, z: Float) { + let ret = Float(y + t) + x + return (ret, ret) + } + + @transpose(of: Float.threeParams, wrt: (self, 0, 1)) + static func threeParamsT10(_ z: Float, t: Double) -> (self: Float, x: Float, y: Double) { + let ret = Float(t) + z + return (ret, ret, Double(ret)) + } + + @transpose(of: Float.threeParams, wrt: (self, 0, 2)) + static func threeParamsT11(_ y: Double, t: Double) -> (self: Float, x: Float, z: Float) { + let ret = Float(t + y) + return (ret, ret, ret) + } + + @transpose(of: Float.threeParams, wrt: (self, 0, 1, 2)) + static func threeParamsT12(t: Double) -> (self: Float, x: Float, y: Double, z: Float) { + return (Float(t), Float(t), t, Float(t)) + } +} + +// Nested struct +struct level1 { + struct level2: Differentiable & AdditiveArithmetic { + static var zero: Self { Self() } + static func + (_: Self, _: Self) -> Self { Self() } + static func - (_: Self, _: Self) -> Self { Self() } + typealias TangentVector = Self + mutating func move(along: TangentVector) {} + func foo(x: Float) -> Float { + return x + } + } + struct level2_nondiff { + func foo(x: Float) -> Float { + return x + } + } +} + +extension level1.level2 { + @transpose(of: foo, wrt: 0) + func trans(t: Float) -> Float { + return t + } + + @transpose(of: foo, wrt: (self, 0)) + static func trans(t: Float) -> (self: level1.level2, x: Float) { + return (level1.level2(), t) + } +} + +extension level1.level2_nondiff { + // expected-error @+1 {{cannot transpose with respect to original parameter 'level1.level2_nondiff' that does not conform to 'Differentiable' and satisfy 'level1.level2_nondiff == level1.level2_nondiff.TangentVector'}} + @transpose(of: level1.level2_nondiff.foo, wrt: (self, 0)) + static func trans(t: Float) -> (self: level1.level2_nondiff, x: Float) { + return (level1.level2_nondiff(), t) + } +} + +// Generics +extension Float { + func genericOneParamFloatOneParam( + x: T, y: Float + ) -> Float where T == T.TangentVector { + return y + Float(x) + } + + @transpose(of: Float.genericOneParamFloatOneParam, wrt: 0) + func genericOneParamFloatOneParamT1( + y: Float, t: Float + ) -> T where T == T.TangentVector { + return T(y + t) + } + + @transpose(of: Float.genericOneParamFloatOneParam, wrt: (0, 1)) + func genericOneParamFloatOneParamT2( + t: Float + ) -> (x: T, y: Float) where T == T.TangentVector { + return (T(t), t) + } + + @transpose(of: Float.genericOneParamFloatOneParam, wrt: (self, 1)) + static func genericOneParamFloatOneParamT1( + x: T, + t: Float + ) -> (self: Float, y: Float) where T == T.TangentVector { + return (Float(x) + t, Float(x) + t) + } + + @transpose(of: Float.genericOneParamFloatOneParam, wrt: (self, 0, 1)) + static func genericOneParamFloatOneParamT1( + t: Float + ) -> (self: Float, x: T, y: Float) where T == T.TangentVector { + return (t, T(t), t) + } +} + +// Test non-`func` original declarations. + +struct Struct {} +extension Struct: Equatable where T: Equatable {} +extension Struct: Differentiable & AdditiveArithmetic +where T: Differentiable & AdditiveArithmetic { + static var zero: Self { Self() } + static func + (_: Self, _: Self) -> Self { Self() } + static func - (_: Self, _: Self) -> Self { Self() } + typealias TangentVector = Self + mutating func move(along: TangentVector) {} +} + +// Test computed properties. +extension Struct { + var computedProperty: Struct { self } +} +extension Struct where T: Differentiable & AdditiveArithmetic { + @transpose(of: computedProperty, wrt: self) + static func transposeProperty(t: Self) -> Self { + t + } +} + +// Test initializers. +extension Struct { + init(_ x: Float) {} + init(_ x: T, y: Float) {} +} + +extension Struct where T: Differentiable, T == T.TangentVector { + @transpose(of: init, wrt: 0) + static func vjpInitX(_ x: Self) -> Float { + fatalError() + } + + @transpose(of: init(_:y:), wrt: (0, 1)) + static func vjpInitXY(_ x: Self) -> (T, Float) { + fatalError() + } + + // Test instance transpose for static original intializer. + // TODO(TF-1015): Add improved instance/static member mismatch error. + // expected-error @+1 {{could not find function 'init' with expected type ' (Struct) -> (Float) -> Struct'}} + @transpose(of: init, wrt: 0) + func vjpInitStaticMismatch(_ x: Self) -> Float { + fatalError() + } +} + +// Test subscripts. +extension Struct { + subscript() -> Self { + get { self } + set {} + } + subscript(float float: Float) -> Self { self } + subscript(x: U) -> Self { self } +} + +extension Struct where T: Differentiable & AdditiveArithmetic { + @transpose(of: subscript, wrt: self) + static func vjpSubscript(t: Struct) -> Struct { + t + } + + @transpose(of: subscript(float:), wrt: self) + static func vjpSubscriptLabelled(float: Float, t: Struct) -> Struct { + t + } + + @transpose(of: subscript(_:), wrt: self) + static func vjpSubscriptGeneric(x: U, t: Struct) -> Struct { + t + } +} + +// Check that `@transpose` attribute rejects stored property original declarations. + +struct StoredProperty: Differentiable & AdditiveArithmetic { + var stored: Float + typealias TangentVector = StoredProperty + static var zero: StoredProperty { StoredProperty(stored: 0) } + static func + (_: StoredProperty, _: StoredProperty) -> StoredProperty { + StoredProperty(stored: 0) + } + static func - (_: StoredProperty, _: StoredProperty) -> StoredProperty { + StoredProperty(stored: 0) + } + + // Note: `@transpose` support for instance members is currently too limited + // to properly register a transpose for a non-`Self`-typed member. + + // expected-error @+1 {{could not find function 'stored' with expected type '(StoredProperty) -> () -> StoredProperty'}} + @transpose(of: stored, wrt: self) + static func vjpStored(v: Self) -> Self { + fatalError() + } +} + +// Check that the self type of the method and the result type are the same when +// transposing WRT self. Needed to make sure they are defined within the same +// context. + +extension Float { + func convertToDouble() -> Double { + Double(self) + } + + // Ok + @transpose(of: convertToDouble, wrt: self) + static func t1(t: Double) -> Float { + Float(t) + } +} +extension Double { + // expected-error @+2 {{the transpose of an instance method must be a 'static' method in the same type when 'self' is a linearity parameter}} + // expected-note @+1 {{the transpose is declared in 'Double' but the original function is declared in 'Float'}} + @transpose(of: Float.convertToDouble, wrt: self) + static func t1(t: Double) -> Float { + Float(t) + } +} diff --git a/test/AutoDiff/Serialization/transpose_attr.swift b/test/AutoDiff/Serialization/transpose_attr.swift index a5c5c9255a87e..4c9372e046631 100644 --- a/test/AutoDiff/Serialization/transpose_attr.swift +++ b/test/AutoDiff/Serialization/transpose_attr.swift @@ -5,10 +5,6 @@ // BCANALYZER-NOT: UnknownCode -// TODO(TF-838): Enable this test. -// Blocked by TF-830: `@transpose` attribute type-checking. -// XFAIL: * - import _Differentiation // Dummy `Differentiable`-conforming type. @@ -50,14 +46,14 @@ extension S { // CHECK: @transpose(of: instanceMethod, wrt: 0) @transpose(of: instanceMethod, wrt: 0) - func transposeInstanceMethod(v: S) -> (S, S) { - (v, v) + func transposeInstanceMethod(t: S) -> S { + self + t } // CHECK: @transpose(of: instanceMethod, wrt: self) @transpose(of: instanceMethod, wrt: self) - func transposeInstanceMethodWrtSelf(v: S) -> (S, S) { - (v, v) + static func transposeInstanceMethodWrtSelf(_ other: S, t: S) -> S { + other + t } } @@ -70,8 +66,8 @@ extension S { // CHECK: @transpose(of: staticMethod, wrt: 0) @transpose(of: staticMethod, wrt: 0) - func transposeStaticMethod(_: S.Type) -> S { - self + static func transposeStaticMethod(t: S) -> S { + t } } @@ -81,8 +77,8 @@ extension S { // CHECK: @transpose(of: computedProperty, wrt: self) @transpose(of: computedProperty, wrt: self) - func transposeProperty() -> Self { - self + static func transposeProperty(t: Self) -> Self { + t } } @@ -92,7 +88,7 @@ extension S { // CHECK: @transpose(of: subscript, wrt: self) @transpose(of: subscript(_:), wrt: self) - func transposeSubscript(x: T) -> Self { - self + static func transposeSubscript(x: T, t: Self) -> Self { + t } } diff --git a/test/Constraints/closures.swift b/test/Constraints/closures.swift index 9c4283b69db7c..26ff6d475194c 100644 --- a/test/Constraints/closures.swift +++ b/test/Constraints/closures.swift @@ -1004,3 +1004,15 @@ func rdar52204414() { let _ = { () -> Void in return 42 } // expected-error@-1 {{declared closure result 'Int' is incompatible with contextual type 'Void'}} } + +// SR-12291 - trailing closure is used as an argument to the last (positionally) parameter +func overloaded_with_default(a: () -> Int, b: Int = 0, c: Int = 0) {} +func overloaded_with_default(b: Int = 0, c: Int = 0, a: () -> Int) {} + +overloaded_with_default { 0 } // Ok (could be ambiguous if trailing was allowed to match `a:` in first overload) + +func overloaded_with_default_and_autoclosure(_ a: @autoclosure () -> T, b: Int = 0) {} +func overloaded_with_default_and_autoclosure(b: Int = 0, c: @escaping () -> T?) {} + +overloaded_with_default_and_autoclosure { 42 } // Ok +overloaded_with_default_and_autoclosure(42) // Ok diff --git a/test/Constraints/rdar60898369.swift b/test/Constraints/rdar60898369.swift new file mode 100644 index 0000000000000..001dff45a45b8 --- /dev/null +++ b/test/Constraints/rdar60898369.swift @@ -0,0 +1,11 @@ +// RUN: %target-typecheck-verify-swift -disable-availability-checking -swift-version 5 + +struct S { + @available(swift, obsoleted: 4.2) + init(foo: Int) throws {} + + @available(swift, introduced: 4.2) + init?(foo: Int) throws {} +} + +_ = try S(foo: 42) diff --git a/test/Demangle/Inputs/manglings.txt b/test/Demangle/Inputs/manglings.txt index d541c4fea727e..c987ab733d537 100644 --- a/test/Demangle/Inputs/manglings.txt +++ b/test/Demangle/Inputs/manglings.txt @@ -355,4 +355,5 @@ $s3red4testyAA3ResOyxSayq_GAEs5ErrorAAq_sAFHD1__HCg_GADyxq_GsAFR_r0_lF --> red.t $s3red4testyAA7OurTypeOy4them05TheirD0Vy5AssocQzGAjE0F8ProtocolAAxAA0c7DerivedH0HD1_AA0c4BaseH0HI1_AieKHA2__HCg_GxmAaLRzlF ---> red.test(A.Type) -> red.OurType> $s17property_wrappers10WithTuplesV9fractionsSd_S2dtvpfP --> property wrapper backing initializer of property_wrappers.WithTuples.fractions : (Swift.Double, Swift.Double, Swift.Double) $sSo17OS_dispatch_queueC4sync7executeyyyXE_tFTOTA ---> {T:$sSo17OS_dispatch_queueC4sync7executeyyyXE_tFTO} partial apply forwarder for @nonobjc __C.OS_dispatch_queue.sync(execute: () -> ()) -> () - +$sxq_Idgnr_D ---> @differentiable @callee_guaranteed (@in_guaranteed A) -> (@out B) +$sxq_Ilgnr_D ---> @differentiable(linear) @callee_guaranteed (@in_guaranteed A) -> (@out B) diff --git a/test/IDE/complete_decl_attribute.swift b/test/IDE/complete_decl_attribute.swift index 9ab5063a1707b..77e1cb166a598 100644 --- a/test/IDE/complete_decl_attribute.swift +++ b/test/IDE/complete_decl_attribute.swift @@ -68,6 +68,7 @@ struct MyStruct {} // KEYWORD2-NEXT: Keyword/None: IBSegueAction[#Func Attribute#]; name=IBSegueAction{{$}} // KEYWORD2-NEXT: Keyword/None: derivative[#Func Attribute#]; name=derivative // KEYWORD2-NEXT: Keyword/None: transpose[#Func Attribute#]; name=transpose +// KEYWORD2-NEXT: Keyword/None: noDerivative[#Func Attribute#]; name=noDerivative // KEYWORD2-NOT: Keyword // KEYWORD2: Decl[Struct]/CurrModule: MyStruct[#MyStruct#]; name=MyStruct // KEYWORD2: End completions @@ -130,6 +131,7 @@ struct MyStruct {} // ON_GLOBALVAR-DAG: Keyword/None: usableFromInline[#Var Attribute#]; name=usableFromInline // ON_GLOBALVAR-DAG: Keyword/None: GKInspectable[#Var Attribute#]; name=GKInspectable // ON_GLOBALVAR-DAG: Keyword/None: differentiable[#Var Attribute#]; name=differentiable +// ON_GLOBALVAR-DAG: Keyword/None: noDerivative[#Var Attribute#]; name=noDerivative // ON_GLOBALVAR-NOT: Keyword // ON_GLOBALVAR: Decl[Struct]/CurrModule: MyStruct[#MyStruct#]; name=MyStruct // ON_GLOBALVAR: End completions @@ -160,6 +162,7 @@ struct _S { // ON_PROPERTY-DAG: Keyword/None: usableFromInline[#Var Attribute#]; name=usableFromInline // ON_PROPERTY-DAG: Keyword/None: GKInspectable[#Var Attribute#]; name=GKInspectable // ON_PROPERTY-DAG: Keyword/None: differentiable[#Var Attribute#]; name=differentiable +// ON_PROPERTY-DAG: Keyword/None: noDerivative[#Var Attribute#]; name=noDerivative // ON_PROPERTY-NOT: Keyword // ON_PROPERTY: Decl[Struct]/CurrModule: MyStruct[#MyStruct#]; name=MyStruct // ON_PROPERTY-NOT: Decl[PrecedenceGroup] @@ -182,6 +185,7 @@ struct _S { // ON_METHOD-DAG: Keyword/None: differentiable[#Func Attribute#]; name=differentiable // ON_METHOD-DAG: Keyword/None: derivative[#Func Attribute#]; name=derivative // ON_METHOD-DAG: Keyword/None: transpose[#Func Attribute#]; name=transpose +// ON_METHOD-DAG: Keyword/None: noDerivative[#Func Attribute#]; name=noDerivative // ON_METHOD-NOT: Keyword // ON_METHOD: Decl[Struct]/CurrModule: MyStruct[#MyStruct#]; name=MyStruct // ON_METHOD: End completions @@ -239,6 +243,7 @@ struct _S { // ON_MEMBER_LAST-DAG: Keyword/None: differentiable[#Declaration Attribute#]; name=differentiable // ON_MEMBER_LAST-DAG: Keyword/None: derivative[#Declaration Attribute#]; name=derivative // ON_MEMBER_LAST-DAG: Keyword/None: transpose[#Declaration Attribute#]; name=transpose +// ON_MEMBER_LAST-DAG: Keyword/None: noDerivative[#Declaration Attribute#]; name=noDerivative // ON_MEMBER_LAST-NOT: Keyword // ON_MEMBER_LAST: Decl[Struct]/CurrModule: MyStruct[#MyStruct#]; name=MyStruct // ON_MEMBER_LAST-NOT: Decl[PrecedenceGroup] @@ -285,6 +290,7 @@ func dummy2() {} // KEYWORD_LAST-NEXT: Keyword/None: IBSegueAction[#Declaration Attribute#]; name=IBSegueAction{{$}} // KEYWORD_LAST-NEXT: Keyword/None: derivative[#Declaration Attribute#]; name=derivative // KEYWORD_LAST-NEXT: Keyword/None: transpose[#Declaration Attribute#]; name=transpose +// KEYWORD_LAST-NEXT: Keyword/None: noDerivative[#Declaration Attribute#]; name=noDerivative // KEYWORD_LAST-NOT: Keyword // KEYWORD_LAST: Decl[Struct]/CurrModule: MyStruct[#MyStruct#]; name=MyStruct // KEYWORD_LAST: End completions diff --git a/test/IDE/complete_dynamic_lookup.swift b/test/IDE/complete_dynamic_lookup.swift index 3ca5008ff632c..14c4fcb1895fe 100644 --- a/test/IDE/complete_dynamic_lookup.swift +++ b/test/IDE/complete_dynamic_lookup.swift @@ -232,8 +232,8 @@ protocol Bar { func bar() } // TLOC_MEMBERS_NO_DOT-NEXT: Decl[InstanceMethod]/CurrNominal: .topLevelObjcClass_InstanceFunc1()[#Void#]{{; name=.+$}} // TLOC_MEMBERS_NO_DOT-NEXT: Decl[Subscript]/CurrNominal: [{#(i): Int8#}][#Int#]{{; name=.+$}} // TLOC_MEMBERS_NO_DOT-NEXT: Decl[InstanceVar]/CurrNominal: .topLevelObjcClass_Property1[#Int#]{{; name=.+$}} -// TLOC_MEMBERS_NO_DOT-NEXT: Decl[InfixOperatorFunction]/OtherModule[Swift]: === {#AnyObject?#}[#Bool#]; -// TLOC_MEMBERS_NO_DOT-NEXT: Decl[InfixOperatorFunction]/OtherModule[Swift]: !== {#AnyObject?#}[#Bool#]; +// TLOC_MEMBERS_NO_DOT-DAG: Decl[InfixOperatorFunction]/OtherModule[Swift]: === {#AnyObject?#}[#Bool#]; +// TLOC_MEMBERS_NO_DOT-DAG: Decl[InfixOperatorFunction]/OtherModule[Swift]: !== {#AnyObject?#}[#Bool#]; // TLOC_MEMBERS_NO_DOT-NEXT: Keyword[self]/CurrNominal: .self[#TopLevelObjcClass#]; name=self // TLOC_MEMBERS_NO_DOT-NEXT: End completions diff --git a/test/IDE/complete_stdlib_optional_objc.swift b/test/IDE/complete_stdlib_optional_objc.swift index 46c5692796d70..ee2825f0df122 100644 --- a/test/IDE/complete_stdlib_optional_objc.swift +++ b/test/IDE/complete_stdlib_optional_objc.swift @@ -73,8 +73,8 @@ func testAnyObject8(a: AnyObject) { // OBJCCLASS_MEMBERS_NO_DOT: Begin completions // OBJCCLASS_MEMBERS_NO_DOT-NEXT: Decl[InstanceVar]/CurrNominal: .instanceVar[#Int#] // OBJCCLASS_MEMBERS_NO_DOT-NEXT: Decl[InstanceMethod]/CurrNominal: .instanceFunc()[#ObjcClass#] -// OBJCCLASS_MEMBERS_NO_DOT-NEXT: Decl[InfixOperatorFunction]/OtherModule[Swift]: === {#AnyObject?#}[#Bool#] -// OBJCCLASS_MEMBERS_NO_DOT-NEXT: Decl[InfixOperatorFunction]/OtherModule[Swift]: !== {#AnyObject?#}[#Bool#] +// OBJCCLASS_MEMBERS_NO_DOT-DAG: Decl[InfixOperatorFunction]/OtherModule[Swift]: === {#AnyObject?#}[#Bool#] +// OBJCCLASS_MEMBERS_NO_DOT-DAG: Decl[InfixOperatorFunction]/OtherModule[Swift]: !== {#AnyObject?#}[#Bool#] // OBJCCLASS_MEMBERS_NO_DOT-NEXT: Keyword[self]/CurrNominal: .self[#ObjcClass#]; name=self // OBJCCLASS_MEMBERS_NO_DOT-NEXT: End completions diff --git a/test/IRGen/Inputs/usr/include/Gizmo.h b/test/IRGen/Inputs/usr/include/Gizmo.h index b359a526b39d6..474f15047b0ce 100644 --- a/test/IRGen/Inputs/usr/include/Gizmo.h +++ b/test/IRGen/Inputs/usr/include/Gizmo.h @@ -159,7 +159,3 @@ struct StructOfNSStrings useStructOfNSStringsInObjC(struct StructOfNSStrings); __attribute__((swift_name("OuterType.InnerType"))) @interface OuterTypeInnerType : NSObject @end - -@protocol P -- (oneway void)stuff; -@end diff --git a/test/IRGen/objc_protocol_instance_methods.swift b/test/IRGen/objc_protocol_instance_methods.swift deleted file mode 100644 index d67484867b6c9..0000000000000 --- a/test/IRGen/objc_protocol_instance_methods.swift +++ /dev/null @@ -1,16 +0,0 @@ -// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-ir %s | %FileCheck %s - -// REQUIRES: OS=macosx - - -// Make sure we don't emit duplicate method descriptors - -// CHECK-NOT: _PROTOCOL_INSTANCE_METHODS_NSObject{{.*}}"\01L_selector_data(conformsToProtocol:)"{{.*}}"\01L_selector_data(conformsToProtocol:)" - -// Make sure that extended method types are in sync with entries in method list. -// CHECK: @_PROTOCOL_INSTANCE_METHODS_NSObject = private constant { i32, i32, [5 x -// CHECK: @_PROTOCOL_METHOD_TYPES_NSObject = private constant [5 -import Foundation - -@objc protocol P: NSObjectProtocol {} -class C: NSObject, P {} diff --git a/test/IRGen/objc_type_encoding.swift b/test/IRGen/objc_type_encoding.swift index be86229249fba..29f00d6b0c42a 100644 --- a/test/IRGen/objc_type_encoding.swift +++ b/test/IRGen/objc_type_encoding.swift @@ -166,7 +166,6 @@ import gizmo func subclassComposition(_: MyCustomObject & NSRuncing & NSFunging) } - // CHECK-macosx: [[ENC1:@.*]] = private unnamed_addr constant [35 x i8] c"v24@0:8@\22\2216\00" // CHECK-macosx: [[ENC2:@.*]] = private unnamed_addr constant [46 x i8] c"v32@0:8@\22Gizmo\2216@?24\00" // CHECK-macosx: [[ENC3:@.*]] = private unnamed_addr constant [53 x i8] c"v24@0:8@\22_TtC18objc_type_encoding14MyCustomObject\2216\00" @@ -182,10 +181,3 @@ import gizmo // CHECK-tvos: [[ENC3:@.*]] = private unnamed_addr constant [53 x i8] c"v24@0:8@\22_TtC18objc_type_encoding14MyCustomObject\2216\00" // CHECK-tvos: [[ENC4:@.*]] = private unnamed_addr constant [75 x i8] c"v24@0:8@\22_TtC18objc_type_encoding14MyCustomObject\2216\00" // CHECK-tvos: @_PROTOCOL_METHOD_TYPES__TtP18objc_type_encoding10MyProtocol_ = private constant [4 x i8*] [i8* getelementptr inbounds ([35 x i8], [35 x i8]* [[ENC1]], i64 0, i64 0), i8* getelementptr inbounds ([46 x i8], [46 x i8]* [[ENC2]], i64 0, i64 0), i8* getelementptr inbounds ([53 x i8], [53 x i8]* [[ENC3]], i64 0, i64 0), i8* getelementptr inbounds ([75 x i8], [75 x i8]* [[ENC4]], i64 0, i64 0)] - -class C: P { - func stuff() {} -} - -// CHECK-macosx: [[ENC5:@.*]] = private unnamed_addr constant [9 x i8] c"Vv16@0:8\00" -// CHECK-macosx: @_PROTOCOL_INSTANCE_METHODS_P = {{.*}}@"\01L_selector_data(stuff)"{{.*}}[[ENC5]]{{.*}}, section "__DATA, __objc_const", align 8 diff --git a/test/SILOptimizer/OSLogCompilerDiagnosticsTest.swift b/test/SILOptimizer/OSLogCompilerDiagnosticsTest.swift new file mode 100644 index 0000000000000..00936f957f80e --- /dev/null +++ b/test/SILOptimizer/OSLogCompilerDiagnosticsTest.swift @@ -0,0 +1,121 @@ +// RUN: %target-swift-frontend -swift-version 5 -emit-sil -primary-file %s -o /dev/null -verify +// +// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos + +// Tests for the diagnostics produced by the OSLogOptimization pass that +// performs compile-time analysis and optimization of the new os log prototype +// APIs. The tests here check whether bad user inputs are diagnosed correctly. +// The tests here model the possible invalid inputs to the os log methods. +// TODO: diagnostics will be improved. globalStringTablePointer builtin error +// must be suppressed. + +import OSLogTestHelper + +func testDynamicLogMessage(message: OSLogMessage) { + _osLogTestHelper(message) + // expected-error @-1 {{globalStringTablePointer builtin must used only on string literals}} +} + +func testNonconstantFormatOption(formatOpt: OSLogIntegerFormatting) { + _osLogTestHelper("Minimum integer value: \(Int.min, format: formatOpt)") + // expected-error @-1 {{interpolation arguments like format and privacy options must be constants}} + // expected-error @-2 {{globalStringTablePointer builtin must used only on string literals}} +} + +func testNonconstantPrivacyOption( privacyOpt: OSLogPrivacy) { + _osLogTestHelper("Minimum integer value: \(Int.min, privacy: privacyOpt)") + // expected-error @-1 {{interpolation arguments like format and privacy options must be constants}} + // expected-error @-2 {{globalStringTablePointer builtin must used only on string literals}} +} + +func testNoninlinedOSLogMessage() { + let logMessage: OSLogMessage = "Minimum integer value: \(Int.min)" + // expected-error @-1 {{OSLogMessage instance must not be explicitly created and must be deletable}} + _osLogTestHelper(logMessage) +} + +func testNoninlinedOSLogMessageComplex(b: Bool) { + let logMessage: OSLogMessage = "Maximum integer value: \(Int.max)" + // expected-error @-1 {{OSLogMessage instance must not be explicitly created and must be deletable}} + if !b { + return + } + _osLogTestHelper(logMessage) + // expected-error @-1 {{globalStringTablePointer builtin must used only on string literals}} +} + +func testNoninlinedFormatOptions() { + let formatOption: OSLogIntegerFormatting = .hex(includePrefix: true) + _osLogTestHelper("Minimum integer value: \(Int.min, format: formatOption)") + // expected-error @-1 {{interpolation arguments like format and privacy options must be constants}} + // expected-error @-2 {{globalStringTablePointer builtin must used only on string literals}} +} + +func testNoninlinedFormatOptionsComplex(b: Bool) { + let formatOption: OSLogIntegerFormatting = .hex(includePrefix: true) + if !b { + return + } + _osLogTestHelper("Minimum integer value: \(Int.min, format: formatOption)") + // expected-error @-1 {{interpolation arguments like format and privacy options must be constants}} + // expected-error @-2 {{globalStringTablePointer builtin must used only on string literals}} +} + +internal enum Color { + case red + case blue +} + +// Invoking the log calls in unreachable code should not crash the compiler. +func testUnreachableLogCall(c: Color) { + let arg = 10 + switch c { + case .red: + return + case .blue: + return + default: // expected-warning {{default will never be executed}} + _osLogTestHelper("Unreachable log call") + _osLogTestHelper("Unreachable log call with argument \(arg)") + _osLogTestHelper( + """ + Unreachable log call with argument and formatting \ + \(arg, align: .right(columns: 10)) + """) + } +} + +// Passing InOut values to the logger should not crash the compiler. +func foo(_ mutableValue: inout String) { + _osLogTestHelper("FMFLabelledLocation: initialized with coder \(mutableValue)") + // expected-error@-1 {{escaping closure captures 'inout' parameter 'mutableValue'}} + // expected-note@-3 {{parameter 'mutableValue' is declared 'inout'}} + // expected-note@-3 {{captured here}} +} + +// This is an extension used only for testing a diagnostic that doesn't arise +// normally but may be triggered by changes to the library. +extension OSLogInterpolation { + @_transparent + mutating func appendInterpolation(_ c: Color) { + switch c { + case .red: + appendInterpolation(1) + case .blue: + appendInterpolation(0) + } + } +} + +func testUnreachableLogCallComplex(c: Color) { + switch c { + case .red: + return + case .blue: + return + default: // expected-warning {{default will never be executed}} + _osLogTestHelper("Some call \(c)") + // expected-warning@-1 {{os log call will never be executed and may have undiagnosed errors}} + // expected-error@-2 {{globalStringTablePointer builtin must used only on string literals}} + } +} diff --git a/test/SILOptimizer/OSLogConstantEvaluableTest.swift b/test/SILOptimizer/OSLogConstantEvaluableTest.swift index 90fe201249217..47bff6dcb7a56 100644 --- a/test/SILOptimizer/OSLogConstantEvaluableTest.swift +++ b/test/SILOptimizer/OSLogConstantEvaluableTest.swift @@ -15,7 +15,7 @@ // This test is meant to catch regressions in the OSLog overlay implementation // affecting the constant evaluability of functions that are expected to be so. -import OSLogPrototype +import OSLogTestHelper // CHECK-LABEL: @init(stringLiteral: String) -> OSLogMessage // CHECK-NOT: error: diff --git a/test/SILOptimizer/OSLogPrototypeFullOptTest.swift b/test/SILOptimizer/OSLogFullOptTest.swift similarity index 67% rename from test/SILOptimizer/OSLogPrototypeFullOptTest.swift rename to test/SILOptimizer/OSLogFullOptTest.swift index 3a4eedbcb9832..aa08ba8bd6b8d 100644 --- a/test/SILOptimizer/OSLogPrototypeFullOptTest.swift +++ b/test/SILOptimizer/OSLogFullOptTest.swift @@ -1,4 +1,5 @@ // RUN: %target-swift-frontend -emit-ir -swift-version 5 -O -primary-file %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize +// // REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos // This tests the optimality of the IR generated for the new os log APIs. This @@ -8,26 +9,24 @@ // os log APIs. TODO: eventually these optimization should also happen in Onone // mode. -import OSLogPrototype +import OSLogTestHelper import Foundation // CHECK-LABEL: define hidden swiftcc void @"${{.*}}testSimpleInterpolation -@available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) -func testSimpleInterpolation(h: Logger) { - h.log(level: .debug, "Minimum integer value: \(Int.min)") +func testSimpleInterpolation() { + _osLogTestHelper("Minimum integer value: \(Int.min)") // CHECK: entry: - // CHECK-NEXT: [[LOGLEVEL:%.+]] = tail call swiftcc i8 @"$sSo13os_log_type_ta0A0E5debugABvgZ"() - // CHECK-NEXT: tail call swiftcc %TSo9OS_os_logC* @"$s14OSLogPrototype6LoggerV9logObjectSo06OS_os_D0Cvg" - // CHECK-NEXT: [[LOGOBJ:%.+]] = bitcast %TSo9OS_os_logC* - // CHECK-NEXT: tail call zeroext i1 @os_log_type_enabled + // Ignore some code related to the default argument and string literal invariant + // checks. + // CHECK: tail call swiftcc i1 @"${{.*}}isLoggingEnabled{{.*}}"() // CHECK-NEXT: br i1 {{%.*}}, label %[[ENABLED:[0-9]+]], label %[[NOT_ENABLED:[0-9]+]] // CHECK: [[ENABLED]]: // // Header bytes. // - // CHECK-64-NEXT: [[BUFFER:%.+]] = tail call noalias i8* @swift_slowAlloc(i64 12 - // CHECK-32-NEXT: [[BUFFER:%.+]] = tail call noalias i8* @swift_slowAlloc(i32 8 + // CHECK-64: [[BUFFER:%.+]] = tail call noalias i8* @swift_slowAlloc(i64 12 + // CHECK-32: [[BUFFER:%.+]] = tail call noalias i8* @swift_slowAlloc(i32 8 // CHECK-NEXT: store i8 0, i8* [[BUFFER]], align 1 // CHECK-NEXT: [[OFFSET1:%.+]] = getelementptr inbounds i8, i8* [[BUFFER]], i{{.*}} 1 // CHECK-NEXT: store i8 1, i8* [[OFFSET1]], align 1 @@ -39,46 +38,41 @@ func testSimpleInterpolation(h: Logger) { // CHECK-NEXT: [[OFFSET3:%.+]] = getelementptr inbounds i8, i8* [[BUFFER]], i{{.*}} 3 // CHECK-64-NEXT: store i8 8, i8* [[OFFSET3]], align 1 // CHECK-32-NEXT: store i8 4, i8* [[OFFSET3]], align 1 + // CHECK-NEXT: bitcast %swift.refcounted* %{{.*}} to %swift.opaque* // CHECK-NEXT: [[OFFSET4:%.+]] = getelementptr inbounds i8, i8* [[BUFFER]], i{{.*}} 4 // CHECK-NEXT: [[BITCASTED:%.+]] = bitcast i8* [[OFFSET4]] to i{{.*}}* // CHECK-64-NEXT: store i64 -9223372036854775808, i64* [[BITCASTED]], align 1 // CHECK-32-NEXT: store i32 -2147483648, i32* [[BITCASTED]], align 1 - // CHECK-64-NEXT: tail call void @_os_log_impl({{.*}}, {{.*}} [[LOGOBJ]], i8 zeroext [[LOGLEVEL]], i8* getelementptr inbounds ([27 x i8], [27 x i8]* @{{.*}}, i64 0, i64 0), i8* {{(nonnull )?}}[[BUFFER]], i32 12) - // CHECK-32-NEXT: tail call void @_os_log_impl({{.*}}, {{.*}} [[LOGOBJ]], i8 zeroext [[LOGLEVEL]], i8* getelementptr inbounds ([27 x i8], [27 x i8]* @{{.*}}, i32 0, i32 0), i8* {{(nonnull )?}}[[BUFFER]], i32 8) + // CHECK-64-NEXT: tail call swiftcc void @"${{.*}}_os_log_impl_test{{.*}}"({{.*}}, {{.*}}, {{.*}}, {{.*}}, i8* getelementptr inbounds ([27 x i8], [27 x i8]* @{{.*}}, i64 0, i64 0), i8* {{(nonnull )?}}[[BUFFER]], i32 12) + // CHECK-32-NEXT: tail call swiftcc void @"${{.*}}_os_log_impl_test{{.*}}"({{.*}}, {{.*}}, {{.*}}, {{.*}}, i8* getelementptr inbounds ([27 x i8], [27 x i8]* @{{.*}}, i32 0, i32 0), i8* {{(nonnull )?}}[[BUFFER]], i32 8) // CHECK-NEXT: tail call void @swift_slowDealloc(i8* {{(nonnull )?}}[[BUFFER]] // CHECK-NEXT: br label %[[NOT_ENABLED]] // CHECK: [[NOT_ENABLED]]: - // CHECK-NEXT: bitcast - // CHECK-NEXT: tail call void @llvm.objc.release + // CHECK-NEXT: tail call void @swift_release // CHECK-NEXT: ret void } // CHECK-LABEL: define hidden swiftcc void @"${{.*}}testInterpolationWithMultipleArguments -@available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) -func testInterpolationWithMultipleArguments(h: Logger) { +func testInterpolationWithMultipleArguments() { let privateID: Int32 = 0x79abcdef let filePermissions: Int32 = 0o777 let pid: Int32 = 122225 - h.log( - level: .error, + _osLogTestHelper( """ Access prevented: process \(pid, privacy: .public) initiated by \ user: \(privateID, privacy: .private) attempted resetting \ permissions to \(filePermissions) """) // CHECK: entry: - // CHECK-NEXT: [[LOGLEVEL:%.+]] = tail call swiftcc i8 @"$sSo13os_log_type_ta0A0E5errorABvgZ"() - // CHECK-NEXT: tail call swiftcc %TSo9OS_os_logC* @"$s14OSLogPrototype6LoggerV9logObjectSo06OS_os_D0Cvg" - // CHECK-NEXT: [[LOGOBJ:%.+]] = bitcast %TSo9OS_os_logC* - // CHECK-NEXT: tail call zeroext i1 @os_log_type_enabled + // CHECK: tail call swiftcc i1 @"${{.*}}isLoggingEnabled{{.*}}"() // CHECK-NEXT: br i1 {{%.*}}, label %[[ENABLED:[0-9]+]], label %[[NOT_ENABLED:[0-9]+]] // CHECK: [[ENABLED]]: // // Header bytes. // - // CHECK-NEXT: [[BUFFER:%.+]] = tail call noalias i8* @swift_slowAlloc(i{{.*}} 20 + // CHECK: [[BUFFER:%.+]] = tail call noalias i8* @swift_slowAlloc(i{{.*}} 20 // CHECK-NEXT: store i8 1, i8* [[BUFFER]], align 1 // CHECK-NEXT: [[OFFSET1:%.+]] = getelementptr inbounds i8, i8* [[BUFFER]], i{{.*}} 1 // CHECK-NEXT: store i8 3, i8* [[OFFSET1]], align 1 @@ -109,42 +103,43 @@ func testInterpolationWithMultipleArguments(h: Logger) { // CHECK-NEXT: store i8 0, i8* [[OFFSET22]], align 1 // CHECK-NEXT: [[OFFSET23:%.+]] = getelementptr inbounds i8, i8* [[BUFFER]], i{{.*}} 15 // CHECK-NEXT: store i8 4, i8* [[OFFSET23]], align 1 + // CHECK-NEXT: bitcast %swift.refcounted* %{{.*}} to %swift.opaque* // CHECK-NEXT: [[OFFSET24:%.+]] = getelementptr inbounds i8, i8* [[BUFFER]], i{{.*}} 16 // CHECK-NEXT: [[BITCASTED3:%.+]] = bitcast i8* [[OFFSET24]] to i32* // CHECK-NEXT: store i32 511, i32* [[BITCASTED3]], align 1 // // os_log_impl call. - // CHECK-NEXT: tail call void @_os_log_impl({{.*}}, {{.*}} [[LOGOBJ]], i8 zeroext [[LOGLEVEL]], i8* getelementptr inbounds ([106 x i8], [106 x i8]* @{{.*}}, i{{.*}} 0, i{{.*}} 0), i8* {{(nonnull )?}}[[BUFFER]], i32 20) + // CHECK-NEXT: tail call swiftcc void @"${{.*}}_os_log_impl_test{{.*}}"({{.*}}, {{.*}}, {{.*}}, {{.*}}, i8* getelementptr inbounds ([106 x i8], [106 x i8]* @{{.*}}, i{{.*}} 0, i{{.*}} 0), i8* {{(nonnull )?}}[[BUFFER]], i32 20) // CHECK-NEXT: tail call void @swift_slowDealloc(i8* {{(nonnull )?}}[[BUFFER]] // CHECK-NEXT: br label %[[NOT_ENABLED]] // CHECK: [[NOT_ENABLED]]: - // CHECK-NEXT: bitcast - // CHECK-NEXT: tail call void @llvm.objc.release + // CHECK-NEXT: tail call void @swift_release // CHECK-NEXT: ret void } // CHECK-LABEL: define hidden swiftcc void @"${{.*}}testNSObjectInterpolation -@available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) -func testNSObjectInterpolation(h: Logger, nsArray: NSArray) { - h.log("NSArray: \(nsArray, privacy: .public)") +func testNSObjectInterpolation(nsArray: NSArray) { + _osLogTestHelper("NSArray: \(nsArray, privacy: .public)") // TODO: check why the ARC optimizer cannot eliminate the many retain/release pairs here. // CHECK: entry: - // CHECK-NEXT: bitcast %TSo7NSArrayC* %1 to i8* + // CHECK-NEXT: bitcast %TSo7NSArrayC* %0 to i8* // CHECK-NEXT: tail call i8* @llvm.objc.retain // CHECK-NEXT: [[NSARRAY_ARG:%.+]] = tail call i8* @llvm.objc.retain - // CHECK-NEXT: [[LOGLEVEL:%.+]] = tail call swiftcc i8 @"$sSo13os_log_type_ta0A0E7defaultABvgZ"() - // CHECK-NEXT: tail call swiftcc %TSo9OS_os_logC* @"$s14OSLogPrototype6LoggerV9logObjectSo06OS_os_D0Cvg" - // CHECK-NEXT: [[LOGOBJ:%.+]] = bitcast %TSo9OS_os_logC* - // CHECK-NEXT: tail call zeroext i1 @os_log_type_enabled + // CHECK: tail call swiftcc i1 @"${{.*}}isLoggingEnabled{{.*}}"() // CHECK-NEXT: br i1 {{%.*}}, label %[[ENABLED:[0-9]+]], label %[[NOT_ENABLED:[0-9]+]] + // CHECK: [[NOT_ENABLED]]: + // CHECK-NEXT: tail call void @swift_release + // CHECK-NEXT: tail call void @llvm.objc.release + // CHECK-NEXT: br label %[[EXIT:[0-9]+]] + // CHECK: [[ENABLED]]: // // Header bytes. // - // CHECK-64-NEXT: [[BUFFER:%.+]] = tail call noalias i8* @swift_slowAlloc(i64 12 - // CHECK-32-NEXT: [[BUFFER:%.+]] = tail call noalias i8* @swift_slowAlloc(i32 8 + // CHECK-64: [[BUFFER:%.+]] = tail call noalias i8* @swift_slowAlloc(i64 12 + // CHECK-32: [[BUFFER:%.+]] = tail call noalias i8* @swift_slowAlloc(i32 8 // CHECK-NEXT: store i8 2, i8* [[BUFFER]], align 1 // CHECK-NEXT: [[OFFSET1:%.+]] = getelementptr inbounds i8, i8* [[BUFFER]], i{{.*}} 1 // CHECK-NEXT: store i8 1, i8* [[OFFSET1]], align 1 @@ -157,43 +152,35 @@ func testNSObjectInterpolation(h: Logger, nsArray: NSArray) { // CHECK-64-NEXT: store i8 8, i8* [[OFFSET3]], align 1 // CHECK-32-NEXT: store i8 4, i8* [[OFFSET3]], align 1 // CHECK-NEXT: tail call void @llvm.objc.release + // CHECK-NEXT: bitcast %swift.refcounted* %{{.*}} to %swift.opaque* // CHECK-NEXT: [[OFFSET4:%.+]] = getelementptr inbounds i8, i8* [[BUFFER]], i{{.*}} 4 // CHECK-NEXT: [[BITCASTED_DEST:%.+]] = bitcast i8* [[OFFSET4]] to %TSo7NSArrayC** // CHECK-NEXT: [[BITCASTED_SRC:%.+]] = bitcast i8* [[NSARRAY_ARG]] to %TSo7NSArrayC* // CHECK-NEXT: store %TSo7NSArrayC* [[BITCASTED_SRC]], %TSo7NSArrayC** [[BITCASTED_DEST]], align 1 - // CHECK-64-NEXT: tail call void @_os_log_impl({{.*}}, {{.*}} [[LOGOBJ]], i8 zeroext [[LOGLEVEL]], i8* getelementptr inbounds ([20 x i8], [20 x i8]* @{{.*}}, i64 0, i64 0), i8* {{(nonnull )?}}[[BUFFER]], i32 12) - // CHECK-32-NEXT: tail call void @_os_log_impl({{.*}}, {{.*}} [[LOGOBJ]], i8 zeroext [[LOGLEVEL]], i8* getelementptr inbounds ([20 x i8], [20 x i8]* @{{.*}}, i32 0, i32 0), i8* {{(nonnull )?}}[[BUFFER]], i32 8) + // CHECK-64-NEXT: tail call swiftcc void @"${{.*}}_os_log_impl_test{{.*}}"({{.*}}, {{.*}}, {{.*}}, {{.*}}, i8* getelementptr inbounds ([20 x i8], [20 x i8]* @{{.*}}, i64 0, i64 0), i8* {{(nonnull )?}}[[BUFFER]], i32 12) + // CHECK-32-NEXT: tail call swiftcc void @"${{.*}}_os_log_impl_test{{.*}}"({{.*}}, {{.*}}, {{.*}}, {{.*}}, i8* getelementptr inbounds ([20 x i8], [20 x i8]* @{{.*}}, i32 0, i32 0), i8* {{(nonnull )?}}[[BUFFER]], i32 8) // CHECK-NEXT: tail call void @swift_slowDealloc(i8* {{(nonnull )?}}[[BUFFER]] - // CHECK-NEXT: br label %[[EXIT:[0-9]+]] - - // CHECK: [[NOT_ENABLED]]: - // CHECK-NEXT: tail call void @llvm.objc.release + // CHECK-NEXT: tail call void @swift_release // CHECK-NEXT: br label %[[EXIT]] // CHECK: [[EXIT]]: // CHECK-NEXT: tail call void @llvm.objc.release(i8* [[NSARRAY_ARG]]) - // CHECK-NEXT: bitcast - // CHECK-NEXT: tail call void @llvm.objc.release // CHECK-NEXT: ret void } // CHECK-LABEL: define hidden swiftcc void @"${{.*}}testFloatInterpolation -@available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) -func testFloatInterpolation(h: Logger, doubleValue: Double) { - h.info("Double value: \(doubleValue)") +func testFloatInterpolation(doubleValue: Double) { + _osLogTestHelper("Double value: \(doubleValue)") // CHECK: entry: - // CHECK-NEXT: tail call swiftcc %TSo9OS_os_logC* @"$s14OSLogPrototype6LoggerV9logObjectSo06OS_os_D0Cvg" - // CHECK-NEXT: [[LOGLEVEL:%.+]] = tail call swiftcc i8 @"$sSo13os_log_type_ta0A0E4infoABvgZ"() - // CHECK-NEXT: [[LOGOBJ:%.+]] = bitcast %TSo9OS_os_logC* - // CHECK-NEXT: tail call zeroext i1 @os_log_type_enabled + // CHECK: tail call swiftcc i1 @"${{.*}}isLoggingEnabled{{.*}}"() // CHECK-NEXT: br i1 {{%.*}}, label %[[ENABLED:[0-9]+]], label %[[NOT_ENABLED:[0-9]+]] // CHECK: [[ENABLED]]: // // Header bytes. // - // CHECK-NEXT: [[BUFFER:%.+]] = tail call noalias i8* @swift_slowAlloc(i{{.*}} 12 + // CHECK: [[BUFFER:%.+]] = tail call noalias i8* @swift_slowAlloc(i{{.*}} 12 // CHECK-NEXT: store i8 0, i8* [[BUFFER]], align 1 // CHECK-NEXT: [[OFFSET1:%.+]] = getelementptr inbounds i8, i8* [[BUFFER]], i{{.*}} 1 // CHECK-NEXT: store i8 1, i8* [[OFFSET1]], align 1 @@ -204,41 +191,37 @@ func testFloatInterpolation(h: Logger, doubleValue: Double) { // CHECK-NEXT: store i8 0, i8* [[OFFSET2]], align 1 // CHECK-NEXT: [[OFFSET3:%.+]] = getelementptr inbounds i8, i8* [[BUFFER]], i{{.*}} 3 // CHECK-NEXT: store i8 8, i8* [[OFFSET3]], align 1 + // CHECK-NEXT: bitcast %swift.refcounted* %{{.*}} to %swift.opaque* // CHECK-NEXT: [[OFFSET4:%.+]] = getelementptr inbounds i8, i8* [[BUFFER]], i{{.*}} 4 // CHECK-NEXT: [[BITCASTED:%.+]] = bitcast i8* [[OFFSET4]] to double* - // CHECK-NEXT: store double %1, double* [[BITCASTED]], align 1 - // CHECK-NEXT: tail call void @_os_log_impl({{.*}}, {{.*}} [[LOGOBJ]], i8 zeroext [[LOGLEVEL]], i8* getelementptr inbounds ([17 x i8], [17 x i8]* @{{.*}}, i{{.*}} 0, i{{.*}} 0), i8* {{(nonnull )?}}[[BUFFER]], i32 12) + // CHECK-NEXT: store double %0, double* [[BITCASTED]], align 1 + // CHECK-NEXT: tail call swiftcc void @"${{.*}}_os_log_impl_test{{.*}}"({{.*}}, {{.*}}, {{.*}}, {{.*}}, i8* getelementptr inbounds ([17 x i8], [17 x i8]* @{{.*}}, i{{.*}} 0, i{{.*}} 0), i8* {{(nonnull )?}}[[BUFFER]], i32 12) // CHECK-NEXT: tail call void @swift_slowDealloc(i8* {{(nonnull )?}}[[BUFFER]] // CHECK-NEXT: br label %[[NOT_ENABLED]] // CHECK: [[NOT_ENABLED]]: - // CHECK-NEXT: bitcast - // CHECK-NEXT: tail call void @llvm.objc.release + // CHECK-NEXT: tail call void @swift_release // CHECK-NEXT: ret void } // This test checks that the precision and alignment are optimally "stored" into the // byte buffer at the right positions. // CHECK-LABEL: define hidden swiftcc void @"${{.*}}testDynamicPrecisionAndAlignment -@available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) -func testDynamicPrecisionAndAlignment(h: Logger) { - h.debug( +func testDynamicPrecisionAndAlignment() { + _osLogTestHelper( """ Maximum Int64 value: \ \(Int32.max, format: .decimal(minDigits: 10), align: .left(columns: 5)) """) // CHECK: entry: - // CHECK-NEXT: tail call swiftcc %TSo9OS_os_logC* @"$s14OSLogPrototype6LoggerV9logObjectSo06OS_os_D0Cvg" - // CHECK-NEXT: [[LOGLEVEL:%.+]] = tail call swiftcc i8 @"$sSo13os_log_type_ta0A0E5debugABvgZ"() - // CHECK-NEXT: [[LOGOBJ:%.+]] = bitcast %TSo9OS_os_logC* - // CHECK-NEXT: tail call zeroext i1 @os_log_type_enabled + // CHECK: tail call swiftcc i1 @"${{.*}}isLoggingEnabled{{.*}}"() // CHECK-NEXT: br i1 {{%.*}}, label %[[ENABLED:[0-9]+]], label %[[NOT_ENABLED:[0-9]+]] // CHECK: [[ENABLED]]: // // Header bytes. // - // CHECK-NEXT: [[BUFFER:%.+]] = tail call noalias i8* @swift_slowAlloc(i{{.*}} 20 + // CHECK: [[BUFFER:%.+]] = tail call noalias i8* @swift_slowAlloc(i{{.*}} 20 // CHECK-NEXT: store i8 0, i8* [[BUFFER]], align 1 // CHECK-NEXT: [[OFFSET1:%.+]] = getelementptr inbounds i8, i8* [[BUFFER]], i{{.*}} 1 // CHECK-NEXT: store i8 3, i8* [[OFFSET1]], align 1 @@ -269,18 +252,18 @@ func testDynamicPrecisionAndAlignment(h: Logger) { // CHECK-NEXT: store i8 0, i8* [[OFFSET22]], align 1 // CHECK-NEXT: [[OFFSET23:%.+]] = getelementptr inbounds i8, i8* [[BUFFER]], i{{.*}} 15 // CHECK-NEXT: store i8 4, i8* [[OFFSET23]], align 1 + // CHECK-NEXT: bitcast %swift.refcounted* %{{.*}} to %swift.opaque* // CHECK-NEXT: [[OFFSET24:%.+]] = getelementptr inbounds i8, i8* [[BUFFER]], i{{.*}} 16 // CHECK-NEXT: [[BITCASTED3:%.+]] = bitcast i8* [[OFFSET24]] to i32* // CHECK-NEXT: store i32 2147483647, i32* [[BITCASTED3]], align 1 // // os_log_impl call. - // CHECK-NEXT: tail call void @_os_log_impl({{.*}}, {{.*}} [[LOGOBJ]], i8 zeroext [[LOGLEVEL]], i8* getelementptr inbounds ([28 x i8], [28 x i8]* @{{.*}}, i{{.*}} 0, i{{.*}} 0), i8* {{(nonnull )?}}[[BUFFER]], i32 20) + // CHECK-NEXT: tail call swiftcc void @"${{.*}}_os_log_impl_test{{.*}}"({{.*}}, {{.*}}, {{.*}}, {{.*}}, i8* getelementptr inbounds ([28 x i8], [28 x i8]* @{{.*}}, i{{.*}} 0, i{{.*}} 0), i8* {{(nonnull )?}}[[BUFFER]], i32 20) // CHECK-NEXT: tail call void @swift_slowDealloc(i8* {{(nonnull )?}}[[BUFFER]] // CHECK-NEXT: br label %[[NOT_ENABLED]] // CHECK: [[NOT_ENABLED]]: - // CHECK-NEXT: bitcast - // CHECK-NEXT: tail call void @llvm.objc.release + // CHECK-NEXT: tail call void @swift_release // CHECK-NEXT: ret void } diff --git a/test/SILOptimizer/OSLogPrototypeCompileTest.sil b/test/SILOptimizer/OSLogMandatoryOptTest.sil similarity index 99% rename from test/SILOptimizer/OSLogPrototypeCompileTest.sil rename to test/SILOptimizer/OSLogMandatoryOptTest.sil index 943f0436d872e..470958372f323 100644 --- a/test/SILOptimizer/OSLogPrototypeCompileTest.sil +++ b/test/SILOptimizer/OSLogMandatoryOptTest.sil @@ -3,7 +3,7 @@ // SIL tests for the OSLogOptimization pass which performs compile-time analysis // and optimization of os log APIs. This test checks specific aspects of the // OSLogOptimization pass on hand-crafted SIL code. The tests here do not depend -// on the os log overlay. +// on any library. import Swift import Builtin diff --git a/test/SILOptimizer/OSLogMandatoryOptTest.swift b/test/SILOptimizer/OSLogMandatoryOptTest.swift new file mode 100644 index 0000000000000..7d46f43689c4d --- /dev/null +++ b/test/SILOptimizer/OSLogMandatoryOptTest.swift @@ -0,0 +1,611 @@ +// RUN: %target-swift-frontend -swift-version 5 -emit-sil -primary-file %s -Xllvm -sil-print-after=OSLogOptimization -o /dev/null 2>&1 | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize +// +// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos + +// Tests for the OSLogOptimization pass that performs compile-time analysis +// and optimization of the new os log APIs. The tests here check whether specific +// compile-time constants such as the format string, the size of the byte buffer etc. are +// literals after the mandatory pipeline. + +import OSLogTestHelper +import Foundation + +// CHECK-LABEL: @${{.*}}testSimpleInterpolationyy +func testSimpleInterpolation() { + _osLogTestHelper("Minimum integer value: \(Int.min)") + + // Check if there is a call to _os_log_impl with a literal format string. + // CHECK-DAG is used here as it is easier to perform the checks backwards + // from uses to the definitions. + + // CHECK-DAG: builtin "globalStringTablePointer"([[STRING:%[0-9]+]] : $String) + // We need to wade through some borrows and copy values here. + // CHECK-DAG: [[STRING]] = begin_borrow [[STRING2:%[0-9]+]] + // CHECK-DAG: [[STRING2]] = copy_value [[STRING3:%[0-9]+]] + // CHECK-DAG: [[STRING3]] = begin_borrow [[STRING4:%[0-9]+]] + // CHECK-DAG: [[STRING4]] = apply [[STRING_INIT:%[0-9]+]]([[LIT:%[0-9]+]], + // CHECK-DAG: [[STRING_INIT]] = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC + // CHECK-DAG: [[LIT]] = string_literal utf8 "Minimum integer value: %ld" + + // Check if the size of the argument buffer is a constant. + + // CHECK-DAG: [[ALLOCATE:%[0-9]+]] = function_ref @$sSp8allocate8capacitySpyxGSi_tFZ + // CHECK-DAG: apply [[ALLOCATE]]([[BUFFERSIZE:%[0-9]+]], {{%.*}}) + // CHECK-DAG: [[BUFFERSIZE]] = struct $Int ([[BUFFERSIZELIT:%[0-9]+]] + // CHECK-64-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int64, 12 + // CHECK-32-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int32, 8 + + // Check whether the header bytes: premable and argument count are constants. + + // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s15OSLogTestHelper9serialize_2atys5UInt8V_SpyAEGztF + // CHECK-DAG: apply [[SERIALIZE]]([[PREAMBLE:%[0-9]+]], {{%.*}}) + // CHECK-DAG: [[PREAMBLE]] = struct $UInt8 ([[PREAMBLELIT:%[0-9]+]] : $Builtin.Int8) + // CHECK-DAG: [[PREAMBLELIT]] = integer_literal $Builtin.Int8, 0 + + // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s15OSLogTestHelper9serialize_2atys5UInt8V_SpyAEGztF + // CHECK-DAG: apply [[SERIALIZE]]([[ARGCOUNT:%[0-9]+]], {{%.*}}) + // CHECK-DAG: [[ARGCOUNT]] = struct $UInt8 ([[ARGCOUNTLIT:%[0-9]+]] : $Builtin.Int8) + // CHECK-DAG: [[ARGCOUNTLIT]] = integer_literal $Builtin.Int8, 1 + + // Check whether argument array is folded. We need not check the contents of + // the array which is checked by a different test suite. + + // CHECK-DAG: [[FOREACH:%[0-9]+]] = function_ref @$sSTsE7forEachyyy7ElementQzKXEKF + // CHECK-DAG: try_apply [[FOREACH]], inout Array) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) + // CHECK-DAG: store_borrow [[ARGSARRAY2:%[0-9]+]] to [[ARGSARRAYADDR]] + // We need to wade through some borrows and copy values here. + // CHECK-DAG: [[ARGSARRAY2]] = begin_borrow [[ARGSARRAY3:%[0-9]+]] + // CHECK-DAG: [[ARGSARRAY3]] = copy_value [[ARGSARRAY4:%[0-9]+]] + // CHECK-DAG: [[ARGSARRAY4]] = begin_borrow [[ARGSARRAY:%[0-9]+]] + // CHECK-DAG: ([[ARGSARRAY]], {{%.*}}) = destructure_tuple [[ARRAYINITRES:%[0-9]+]] + // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARRAYSIZE:%[0-9]+]]) + // CHECK-DAG: [[ARRAYINIT]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF + // CHECK-DAG: [[ARRAYSIZE]] = integer_literal $Builtin.Word, 3 +} + +// CHECK-LABEL: @${{.*}}testInterpolationWithFormatOptionsyy +func testInterpolationWithFormatOptions() { + _osLogTestHelper("Maximum unsigned integer value: \(UInt.max, format: .hex)") + + // Check if there is a call to _os_log_impl with a literal format string. + + // CHECK-DAG: builtin "globalStringTablePointer"([[STRING:%[0-9]+]] : $String) + // CHECK-DAG: [[STRING]] = begin_borrow [[STRING2:%[0-9]+]] + // CHECK-DAG: [[STRING2]] = copy_value [[STRING3:%[0-9]+]] + // CHECK-DAG: [[STRING3]] = begin_borrow [[STRING4:%[0-9]+]] + // CHECK-DAG: [[STRING4]] = apply [[STRING_INIT:%[0-9]+]]([[LIT:%[0-9]+]], + // CHECK-DAG: [[STRING_INIT]] = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC + // CHECK-DAG: [[LIT]] = string_literal utf8 "Maximum unsigned integer value: %lx" + + // Check if the size of the argument buffer is a constant. + + // CHECK-DAG: [[ALLOCATE:%[0-9]+]] = function_ref @$sSp8allocate8capacitySpyxGSi_tFZ + // CHECK-DAG: apply [[ALLOCATE]]([[BUFFERSIZE:%[0-9]+]], {{%.*}}) + // CHECK-DAG: [[BUFFERSIZE]] = struct $Int ([[BUFFERSIZELIT:%[0-9]+]] + // CHECK-64-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int64, 12 + // CHECK-32-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int32, 8 + + // Check whether the header bytes: premable and argument count are constants. + + // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s15OSLogTestHelper9serialize_2atys5UInt8V_SpyAEGztF + // CHECK-DAG: apply [[SERIALIZE]]([[PREAMBLE:%[0-9]+]], {{%.*}}) + // CHECK-DAG: [[PREAMBLE]] = struct $UInt8 ([[PREAMBLELIT:%[0-9]+]] : $Builtin.Int8) + // CHECK-DAG: [[PREAMBLELIT]] = integer_literal $Builtin.Int8, 0 + + // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s15OSLogTestHelper9serialize_2atys5UInt8V_SpyAEGztF + // CHECK-DAG: apply [[SERIALIZE]]([[ARGCOUNT:%[0-9]+]], {{%.*}}) + // CHECK-DAG: [[ARGCOUNT]] = struct $UInt8 ([[ARGCOUNTLIT:%[0-9]+]] : $Builtin.Int8) + // CHECK-DAG: [[ARGCOUNTLIT]] = integer_literal $Builtin.Int8, 1 + + // Check whether argument array is folded. We need not check the contents of + // the array which is checked by a different test suite. + + // CHECK-DAG: [[FOREACH:%[0-9]+]] = function_ref @$sSTsE7forEachyyy7ElementQzKXEKF + // CHECK-DAG: try_apply [[FOREACH]], inout Array) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) + // CHECK-DAG: store_borrow [[ARGSARRAY2:%[0-9]+]] to [[ARGSARRAYADDR]] + // CHECK-DAG: [[ARGSARRAY2]] = begin_borrow [[ARGSARRAY3:%[0-9]+]] + // CHECK-DAG: [[ARGSARRAY3]] = copy_value [[ARGSARRAY4:%[0-9]+]] + // CHECK-DAG: [[ARGSARRAY4]] = begin_borrow [[ARGSARRAY:%[0-9]+]] + // CHECK-DAG: ([[ARGSARRAY]], {{%.*}}) = destructure_tuple [[ARRAYINITRES:%[0-9]+]] + // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARRAYSIZE:%[0-9]+]]) + // CHECK-DAG: [[ARRAYINIT]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF + // CHECK-DAG: [[ARRAYSIZE]] = integer_literal $Builtin.Word, 3 +} + +// CHECK-LABEL: @${{.*}}testInterpolationWithFormatOptionsAndPrivacyyy +func testInterpolationWithFormatOptionsAndPrivacy() { + let privateID: UInt = 0x79abcdef + _osLogTestHelper( + "Private Identifier: \(privateID, format: .hex, privacy: .private)") + + // Check if there is a call to _os_log_impl with a literal format string. + + // CHECK-DAG: builtin "globalStringTablePointer"([[STRING:%[0-9]+]] : $String) + // CHECK-DAG: [[STRING]] = begin_borrow [[STRING2:%[0-9]+]] + // CHECK-DAG: [[STRING2]] = copy_value [[STRING3:%[0-9]+]] + // CHECK-DAG: [[STRING3]] = begin_borrow [[STRING4:%[0-9]+]] + // CHECK-DAG: [[STRING4]] = apply [[STRING_INIT:%[0-9]+]]([[LIT:%[0-9]+]], + // CHECK-DAG: [[STRING_INIT]] = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC + // CHECK-DAG: [[LIT]] = string_literal utf8 "Private Identifier: %{private}lx" + + // Check if the size of the argument buffer is a constant. + + // CHECK-DAG: [[ALLOCATE:%[0-9]+]] = function_ref @$sSp8allocate8capacitySpyxGSi_tFZ + // CHECK-DAG: apply [[ALLOCATE]]([[BUFFERSIZE:%[0-9]+]], {{%.*}}) + // CHECK-DAG: [[BUFFERSIZE]] = struct $Int ([[BUFFERSIZELIT:%[0-9]+]] + // CHECK-64-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int64, 12 + // CHECK-32-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int32, 8 + + // Check whether the header bytes: premable and argument count are constants. + + // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s15OSLogTestHelper9serialize_2atys5UInt8V_SpyAEGztF + // CHECK-DAG: apply [[SERIALIZE]]([[PREAMBLE:%[0-9]+]], {{%.*}}) + // CHECK-DAG: [[PREAMBLE]] = struct $UInt8 ([[PREAMBLELIT:%[0-9]+]] : $Builtin.Int8) + // CHECK-DAG: [[PREAMBLELIT]] = integer_literal $Builtin.Int8, 1 + + // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s15OSLogTestHelper9serialize_2atys5UInt8V_SpyAEGztF + // CHECK-DAG: apply [[SERIALIZE]]([[ARGCOUNT:%[0-9]+]], {{%.*}}) + // CHECK-DAG: [[ARGCOUNT]] = struct $UInt8 ([[ARGCOUNTLIT:%[0-9]+]] : $Builtin.Int8) + // CHECK-DAG: [[ARGCOUNTLIT]] = integer_literal $Builtin.Int8, 1 + + // Check whether argument array is folded. We need not check the contents of + // the array which is checked by a different test suite. + + // CHECK-DAG: [[FOREACH:%[0-9]+]] = function_ref @$sSTsE7forEachyyy7ElementQzKXEKF + // CHECK-DAG: try_apply [[FOREACH]], inout Array) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) + // CHECK-DAG: store_borrow [[ARGSARRAY2:%[0-9]+]] to [[ARGSARRAYADDR]] + // CHECK-DAG: [[ARGSARRAY2]] = begin_borrow [[ARGSARRAY3:%[0-9]+]] + // CHECK-DAG: [[ARGSARRAY3]] = copy_value [[ARGSARRAY4:%[0-9]+]] + // CHECK-DAG: [[ARGSARRAY4]] = begin_borrow [[ARGSARRAY:%[0-9]+]] + // CHECK-DAG: ([[ARGSARRAY]], {{%.*}}) = destructure_tuple [[ARRAYINITRES:%[0-9]+]] + // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARRAYSIZE:%[0-9]+]]) + // CHECK-DAG: [[ARRAYINIT]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF + // CHECK-DAG: [[ARRAYSIZE]] = integer_literal $Builtin.Word, 3 +} + +// CHECK-LABEL: @${{.*}}testInterpolationWithMultipleArgumentsyy +func testInterpolationWithMultipleArguments() { + let privateID = 0x79abcdef + let filePermissions: UInt = 0o777 + let pid = 122225 + _osLogTestHelper( + """ + Access prevented: process \(pid, privacy: .public) initiated by \ + user: \(privateID, privacy: .private) attempted resetting \ + permissions to \(filePermissions, format: .octal) + """) + + // Check if there is a call to _os_log_impl with a literal format string. + + // CHECK-DAG: builtin "globalStringTablePointer"([[STRING:%[0-9]+]] : $String) + // CHECK-DAG: [[STRING]] = begin_borrow [[STRING2:%[0-9]+]] + // CHECK-DAG: [[STRING2]] = copy_value [[STRING3:%[0-9]+]] + // CHECK-DAG: [[STRING3]] = begin_borrow [[STRING4:%[0-9]+]] + // CHECK-DAG: [[STRING4]] = apply [[STRING_INIT:%[0-9]+]]([[LIT:%[0-9]+]], + // CHECK-DAG: [[STRING_INIT]] = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC + // CHECK-DAG: [[LIT]] = string_literal utf8 "Access prevented: process %{public}ld initiated by user: %{private}ld attempted resetting permissions to %lo" + + // Check if the size of the argument buffer is a constant. + + // CHECK-DAG: [[ALLOCATE:%[0-9]+]] = function_ref @$sSp8allocate8capacitySpyxGSi_tFZ + // CHECK-DAG: apply [[ALLOCATE]]([[BUFFERSIZE:%[0-9]+]], {{%.*}}) + // CHECK-DAG: [[BUFFERSIZE]] = struct $Int ([[BUFFERSIZELIT:%[0-9]+]] + // CHECK-64-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int64, 32 + // CHECK-32-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int32, 20 + + // Check whether the header bytes: premable and argument count are constants. + + // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s15OSLogTestHelper9serialize_2atys5UInt8V_SpyAEGztF + // CHECK-DAG: apply [[SERIALIZE]]([[PREAMBLE:%[0-9]+]], {{%.*}}) + // CHECK-DAG: [[PREAMBLE]] = struct $UInt8 ([[PREAMBLELIT:%[0-9]+]] : $Builtin.Int8) + // CHECK-DAG: [[PREAMBLELIT]] = integer_literal $Builtin.Int8, 1 + + // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s15OSLogTestHelper9serialize_2atys5UInt8V_SpyAEGztF + // CHECK-DAG: apply [[SERIALIZE]]([[ARGCOUNT:%[0-9]+]], {{%.*}}) + // CHECK-DAG: [[ARGCOUNT]] = struct $UInt8 ([[ARGCOUNTLIT:%[0-9]+]] : $Builtin.Int8) + // CHECK-DAG: [[ARGCOUNTLIT]] = integer_literal $Builtin.Int8, 3 + + // Check whether argument array is folded. We need not check the contents of + // the array which is checked by a different test suite. + + // CHECK-DAG: [[FOREACH:%[0-9]+]] = function_ref @$sSTsE7forEachyyy7ElementQzKXEKF + // CHECK-DAG: try_apply [[FOREACH]], inout Array) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) + // CHECK-DAG: store_borrow [[ARGSARRAY2:%[0-9]+]] to [[ARGSARRAYADDR]] + // CHECK-DAG: [[ARGSARRAY2]] = begin_borrow [[ARGSARRAY3:%[0-9]+]] + // CHECK-DAG: [[ARGSARRAY3]] = copy_value [[ARGSARRAY4:%[0-9]+]] + // CHECK-DAG: [[ARGSARRAY4]] = begin_borrow [[ARGSARRAY:%[0-9]+]] + // CHECK-DAG: ([[ARGSARRAY]], {{%.*}}) = destructure_tuple [[ARRAYINITRES:%[0-9]+]] + // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARRAYSIZE:%[0-9]+]]) + // CHECK-DAG: [[ARRAYINIT]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF + // CHECK-DAG: [[ARRAYSIZE]] = integer_literal $Builtin.Word, 9 +} + +// CHECK-LABEL: @${{.*}}testLogMessageWithoutDatayy +func testLogMessageWithoutData() { + // FIXME: here `ExpressibleByStringLiteral` conformance of OSLogMessage + // is used. In this case, the constant evaluation begins from the apply of + // the "string.makeUTF8: initializer. The constant evaluator ends up using + // the backward mode to identify the string_literal inst passed to the + // initializer. Eliminate reliance on this backward mode by starting from + // the string_literal inst, instead of initialization instruction. + _osLogTestHelper("A message with no data") + + // Check if there is a call to _os_log_impl with a literal format string. + + // CHECK-DAG: builtin "globalStringTablePointer"([[STRING:%[0-9]+]] : $String) + // CHECK-DAG: [[STRING]] = begin_borrow [[STRING2:%[0-9]+]] + // CHECK-DAG: [[STRING2]] = copy_value [[STRING3:%[0-9]+]] + // CHECK-DAG: [[STRING3]] = begin_borrow [[STRING4:%[0-9]+]] + // CHECK-DAG: [[STRING4]] = apply [[STRING_INIT:%[0-9]+]]([[LIT:%[0-9]+]], + // CHECK-DAG: [[STRING_INIT]] = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC + // CHECK-DAG: [[LIT]] = string_literal utf8 "A message with no data" + + // Check if the size of the argument buffer is a constant. + + // CHECK-DAG: [[ALLOCATE:%[0-9]+]] = function_ref @$sSp8allocate8capacitySpyxGSi_tFZ + // CHECK-DAG: apply [[ALLOCATE]]([[BUFFERSIZE:%[0-9]+]], {{%.*}}) + // CHECK-DAG: [[BUFFERSIZE]] = struct $Int ([[BUFFERSIZELIT:%[0-9]+]] + // CHECK-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int{{[0-9]+}}, 2 + + // Check whether the header bytes: premable and argument count are constants. + + // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s15OSLogTestHelper9serialize_2atys5UInt8V_SpyAEGztF + // CHECK-DAG: apply [[SERIALIZE]]([[PREAMBLE:%[0-9]+]], {{%.*}}) + // CHECK-DAG: [[PREAMBLE]] = struct $UInt8 ([[PREAMBLELIT:%[0-9]+]] : $Builtin.Int8) + // CHECK-DAG: [[PREAMBLELIT]] = integer_literal $Builtin.Int8, 0 + + // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s15OSLogTestHelper9serialize_2atys5UInt8V_SpyAEGztF + // CHECK-DAG: apply [[SERIALIZE]]([[ARGCOUNT:%[0-9]+]], {{%.*}}) + // CHECK-DAG: [[ARGCOUNT]] = struct $UInt8 ([[ARGCOUNTLIT:%[0-9]+]] : $Builtin.Int8) + // CHECK-DAG: [[ARGCOUNTLIT]] = integer_literal $Builtin.Int8, 0 + + // Check whether argument array is folded. + + // CHECK-DAG: [[FOREACH:%[0-9]+]] = function_ref @$sSTsE7forEachyyy7ElementQzKXEKF + // CHECK-DAG: try_apply [[FOREACH]], inout Array) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) + // CHECK-DAG: store_borrow [[ARGSARRAY2:%[0-9]+]] to [[ARGSARRAYADDR]] + // CHECK-DAG: [[ARGSARRAY2]] = begin_borrow [[ARGSARRAY3:%[0-9]+]] + // CHECK-DAG: [[ARGSARRAY3]] = copy_value [[ARGSARRAY4:%[0-9]+]] + // CHECK-DAG: [[ARGSARRAY4]] = begin_borrow [[ARGSARRAY:%[0-9]+]] + // CHECK-DAG: ([[ARGSARRAY]], {{%.*}}) = destructure_tuple [[ARRAYINITRES:%[0-9]+]] + // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARRAYSIZE:%[0-9]+]]) + // CHECK-DAG: [[ARRAYINIT]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF + // CHECK-DAG: [[ARRAYSIZE]] = integer_literal $Builtin.Word, 0 +} + +// CHECK-LABEL: @${{.*}}testEscapingOfPercentsyy +func testEscapingOfPercents() { + _osLogTestHelper("Process failed after 99% completion") + // CHECK-DAG: builtin "globalStringTablePointer"([[STRING:%[0-9]+]] : $String) + // CHECK-DAG: [[STRING]] = begin_borrow [[STRING2:%[0-9]+]] + // CHECK-DAG: [[STRING2]] = copy_value [[STRING3:%[0-9]+]] + // CHECK-DAG: [[STRING3]] = begin_borrow [[STRING4:%[0-9]+]] + // CHECK-DAG: [[STRING4]] = apply [[STRING_INIT:%[0-9]+]]([[LIT:%[0-9]+]], + // CHECK-DAG: [[STRING_INIT]] = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC + // CHECK-DAG: [[LIT]] = string_literal utf8 "Process failed after 99%% completion" +} + +// CHECK-LABEL: @${{.*}}testDoublePercentsyy +func testDoublePercents() { + _osLogTestHelper("Double percents: %%") + // CHECK-DAG: builtin "globalStringTablePointer"([[STRING:%[0-9]+]] : $String) + // CHECK-DAG: [[STRING]] = begin_borrow [[STRING2:%[0-9]+]] + // CHECK-DAG: [[STRING2]] = copy_value [[STRING3:%[0-9]+]] + // CHECK-DAG: [[STRING3]] = begin_borrow [[STRING4:%[0-9]+]] + // CHECK-DAG: [[STRING4]] = apply [[STRING_INIT:%[0-9]+]]([[LIT:%[0-9]+]], + // CHECK-DAG: [[STRING_INIT]] = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC + // CHECK-DAG: [[LIT]] = string_literal utf8 "Double percents: %%%%" +} + +// CHECK-LABEL: @${{.*}}testSmallFormatStringsyy +func testSmallFormatStrings() { + _osLogTestHelper("a") + // CHECK-DAG: builtin "globalStringTablePointer"([[STRING:%[0-9]+]] : $String) + // CHECK-DAG: [[STRING]] = begin_borrow [[STRING2:%[0-9]+]] + // CHECK-DAG: [[STRING2]] = copy_value [[STRING3:%[0-9]+]] + // CHECK-DAG: [[STRING3]] = begin_borrow [[STRING4:%[0-9]+]] + // CHECK-DAG: [[STRING4]] = apply [[STRING_INIT:%[0-9]+]]([[LIT:%[0-9]+]], + // CHECK-DAG: [[STRING_INIT]] = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC + // CHECK-DAG: [[LIT]] = string_literal utf8 "a" +} + +/// A stress test that checks whether the optimizer handle messages with more +/// than 48 interpolated expressions. Interpolated expressions beyond this +/// limit must be ignored. +// CHECK-LABEL: @${{.*}}testMessageWithTooManyArgumentsyy +func testMessageWithTooManyArguments() { + _osLogTestHelper( + """ + \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \ + \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \ + \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \ + \(1) \(1) \(1) \(1) \(1) \(48) \(49) + """) + + // Check if there is a call to _os_log_impl with a literal format string. + + // CHECK-DAG: builtin "globalStringTablePointer"([[STRING:%[0-9]+]] : $String) + // CHECK-DAG: [[STRING]] = begin_borrow [[STRING2:%[0-9]+]] + // CHECK-DAG: [[STRING2]] = copy_value [[STRING3:%[0-9]+]] + // CHECK-DAG: [[STRING3]] = begin_borrow [[STRING4:%[0-9]+]] + // CHECK-DAG: [[STRING4]] = apply [[STRING_INIT:%[0-9]+]]([[LIT:%[0-9]+]], + // CHECK-DAG: [[STRING_INIT]] = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC + // CHECK-DAG: [[LIT]] = string_literal utf8 "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld " + + // Check if the size of the argument buffer is a constant. + + // CHECK-DAG: [[ALLOCATE:%[0-9]+]] = function_ref @$sSp8allocate8capacitySpyxGSi_tFZ + // CHECK-DAG: apply [[ALLOCATE]]([[BUFFERSIZE:%[0-9]+]], {{%.*}}) + // CHECK-DAG: [[BUFFERSIZE]] = struct $Int ([[BUFFERSIZELIT:%[0-9]+]] + // CHECK-64-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int64, 482 + // CHECK-32-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int32, 290 + + // Check whether the header bytes: premable and argument count are constants. + + // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s15OSLogTestHelper9serialize_2atys5UInt8V_SpyAEGztF + // CHECK-DAG: apply [[SERIALIZE]]([[PREAMBLE:%[0-9]+]], {{%.*}}) + // CHECK-DAG: [[PREAMBLE]] = struct $UInt8 ([[PREAMBLELIT:%[0-9]+]] : $Builtin.Int8) + // CHECK-DAG: [[PREAMBLELIT]] = integer_literal $Builtin.Int8, 0 + + // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s15OSLogTestHelper9serialize_2atys5UInt8V_SpyAEGztF + // CHECK-DAG: apply [[SERIALIZE]]([[ARGCOUNT:%[0-9]+]], {{%.*}}) + // CHECK-DAG: [[ARGCOUNT]] = struct $UInt8 ([[ARGCOUNTLIT:%[0-9]+]] : $Builtin.Int8) + // CHECK-DAG: [[ARGCOUNTLIT]] = integer_literal $Builtin.Int8, 48 + + // Check whether argument array is folded. + + // CHECK-DAG: [[FOREACH:%[0-9]+]] = function_ref @$sSTsE7forEachyyy7ElementQzKXEKF + // CHECK-DAG: try_apply [[FOREACH]], inout Array) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) + // CHECK-DAG: store_borrow [[ARGSARRAY2:%[0-9]+]] to [[ARGSARRAYADDR]] + // CHECK-DAG: [[ARGSARRAY2]] = begin_borrow [[ARGSARRAY3:%[0-9]+]] + // CHECK-DAG: [[ARGSARRAY3]] = copy_value [[ARGSARRAY4:%[0-9]+]] + // CHECK-DAG: [[ARGSARRAY4]] = begin_borrow [[ARGSARRAY:%[0-9]+]] + // CHECK-DAG: ([[ARGSARRAY]], {{%.*}}) = destructure_tuple [[ARRAYINITRES:%[0-9]+]] + // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARRAYSIZE:%[0-9]+]]) + // CHECK-DAG: [[ARRAYINIT]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF + // CHECK-DAG: [[ARRAYSIZE]] = integer_literal $Builtin.Word, 144 +} + +// CHECK-LABEL: @${{.*}}testInt32Interpolationyy +func testInt32Interpolation() { + _osLogTestHelper("32-bit integer value: \(Int32.min)") + + // Check if there is a call to _os_log_impl with a literal format string. + + // CHECK-DAG: builtin "globalStringTablePointer"([[STRING:%[0-9]+]] : $String) + // CHECK-DAG: [[STRING]] = begin_borrow [[STRING2:%[0-9]+]] + // CHECK-DAG: [[STRING2]] = copy_value [[STRING3:%[0-9]+]] + // CHECK-DAG: [[STRING3]] = begin_borrow [[STRING4:%[0-9]+]] + // CHECK-DAG: [[STRING4]] = apply [[STRING_INIT:%[0-9]+]]([[LIT:%[0-9]+]], + // CHECK-DAG: [[STRING_INIT]] = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC + // CHECK-DAG: [[LIT]] = string_literal utf8 "32-bit integer value: %d" + + // Check if the size of the argument buffer is a constant. + + // CHECK-DAG: [[ALLOCATE:%[0-9]+]] = function_ref @$sSp8allocate8capacitySpyxGSi_tFZ + // CHECK-DAG: apply [[ALLOCATE]]([[BUFFERSIZE:%[0-9]+]], {{%.*}}) + // CHECK-DAG: [[BUFFERSIZE]] = struct $Int ([[BUFFERSIZELIT:%[0-9]+]] + // CHECK-64-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int64, 8 + // CHECK-32-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int32, 8 + + // Check whether the header bytes: premable and argument count are constants. + + // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s15OSLogTestHelper9serialize_2atys5UInt8V_SpyAEGztF + // CHECK-DAG: apply [[SERIALIZE]]([[PREAMBLE:%[0-9]+]], {{%.*}}) + // CHECK-DAG: [[PREAMBLE]] = struct $UInt8 ([[PREAMBLELIT:%[0-9]+]] : $Builtin.Int8) + // CHECK-DAG: [[PREAMBLELIT]] = integer_literal $Builtin.Int8, 0 + + // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s15OSLogTestHelper9serialize_2atys5UInt8V_SpyAEGztF + // CHECK-DAG: apply [[SERIALIZE]]([[ARGCOUNT:%[0-9]+]], {{%.*}}) + // CHECK-DAG: [[ARGCOUNT]] = struct $UInt8 ([[ARGCOUNTLIT:%[0-9]+]] : $Builtin.Int8) + // CHECK-DAG: [[ARGCOUNTLIT]] = integer_literal $Builtin.Int8, 1 +} + +// CHECK-LABEL: @${{.*}}testDynamicStringArgumentsyy +func testDynamicStringArguments() { + let concatString = "hello" + " - " + "world" + let interpolatedString = "\(31) trillion digits of pi are known so far" + + _osLogTestHelper( + """ + concat: \(concatString, privacy: .public) \ + interpolated: \(interpolatedString, privacy: .private) + """) + + // Check if there is a call to _os_log_impl with a literal format string. + // CHECK-DAG is used here as it is easier to perform the checks backwards + // from uses to the definitions. + + // CHECK-DAG: builtin "globalStringTablePointer"([[STRING:%[0-9]+]] : $String) + // CHECK-DAG: [[STRING]] = begin_borrow [[STRING2:%[0-9]+]] + // CHECK-DAG: [[STRING2]] = copy_value [[STRING3:%[0-9]+]] + // CHECK-DAG: [[STRING3]] = begin_borrow [[STRING4:%[0-9]+]] + // CHECK-DAG: [[STRING4]] = apply [[STRING_INIT:%[0-9]+]]([[LIT:%[0-9]+]], + // CHECK-DAG: [[STRING_INIT]] = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC + // CHECK-DAG: [[LIT]] = string_literal utf8 "concat: %{public}s interpolated: %{private}s" + + // Check if the size of the argument buffer is a constant. + + // CHECK-DAG: [[ALLOCATE:%[0-9]+]] = function_ref @$sSp8allocate8capacitySpyxGSi_tFZ + // CHECK-DAG: apply [[ALLOCATE]]([[BUFFERSIZE:%[0-9]+]], {{%.*}}) + // CHECK-DAG: [[BUFFERSIZE]] = struct $Int ([[BUFFERSIZELIT:%[0-9]+]] + // CHECK-64-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int64, 22 + // CHECK-32-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int32, 14 + + // Check whether the header bytes: premable and argument count are constants. + + // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s15OSLogTestHelper9serialize_2atys5UInt8V_SpyAEGztF + // CHECK-DAG: apply [[SERIALIZE]]([[PREAMBLE:%[0-9]+]], {{%.*}}) + // CHECK-DAG: [[PREAMBLE]] = struct $UInt8 ([[PREAMBLELIT:%[0-9]+]] : $Builtin.Int8) + // CHECK-DAG: [[PREAMBLELIT]] = integer_literal $Builtin.Int8, 3 + + // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s15OSLogTestHelper9serialize_2atys5UInt8V_SpyAEGztF + // CHECK-DAG: apply [[SERIALIZE]]([[ARGCOUNT:%[0-9]+]], {{%.*}}) + // CHECK-DAG: [[ARGCOUNT]] = struct $UInt8 ([[ARGCOUNTLIT:%[0-9]+]] : $Builtin.Int8) + // CHECK-DAG: [[ARGCOUNTLIT]] = integer_literal $Builtin.Int8, 2 + + // Check whether argument array is folded. We need not check the contents of + // the array which is checked by a different test suite. + + // CHECK-DAG: [[FOREACH:%[0-9]+]] = function_ref @$sSTsE7forEachyyy7ElementQzKXEKF + // CHECK-DAG: try_apply [[FOREACH]], inout Array) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) + // CHECK-DAG: store_borrow [[ARGSARRAY2:%[0-9]+]] to [[ARGSARRAYADDR]] + // CHECK-DAG: [[ARGSARRAY2]] = begin_borrow [[ARGSARRAY3:%[0-9]+]] + // CHECK-DAG: [[ARGSARRAY3]] = copy_value [[ARGSARRAY4:%[0-9]+]] + // CHECK-DAG: [[ARGSARRAY4]] = begin_borrow [[ARGSARRAY:%[0-9]+]] + // CHECK-DAG: ([[ARGSARRAY]], {{%.*}}) = destructure_tuple [[ARRAYINITRES:%[0-9]+]] + // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARRAYSIZE:%[0-9]+]]) + // CHECK-DAG: [[ARRAYINIT]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF + // CHECK-DAG: [[ARRAYSIZE]] = integer_literal $Builtin.Word, 6 +} + +// CHECK-LABEL: @${{.*}}testNSObjectInterpolationyy +func testNSObjectInterpolation() { + let nsArray: NSArray = [0, 1, 2] + let nsDictionary: NSDictionary = [1 : ""] + _osLogTestHelper( + """ + NSArray: \(nsArray, privacy: .public) \ + NSDictionary: \(nsDictionary, privacy: .private) + """) + // Check if there is a call to _os_log_impl with a literal format string. + // CHECK-DAG is used here as it is easier to perform the checks backwards + // from uses to the definitions. + + // CHECK-DAG: builtin "globalStringTablePointer"([[STRING:%[0-9]+]] : $String) + // CHECK-DAG: [[STRING]] = begin_borrow [[STRING2:%[0-9]+]] + // CHECK-DAG: [[STRING2]] = copy_value [[STRING3:%[0-9]+]] + // CHECK-DAG: [[STRING3]] = begin_borrow [[STRING4:%[0-9]+]] + // CHECK-DAG: [[STRING4]] = apply [[STRING_INIT:%[0-9]+]]([[LIT:%[0-9]+]], + // CHECK-DAG: [[STRING_INIT]] = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC + // CHECK-DAG: [[LIT]] = string_literal utf8 "NSArray: %{public}@ NSDictionary: %{private}@" + + // Check if the size of the argument buffer is a constant. + + // CHECK-DAG: [[ALLOCATE:%[0-9]+]] = function_ref @$sSp8allocate8capacitySpyxGSi_tFZ + // CHECK-DAG: apply [[ALLOCATE]]([[BUFFERSIZE:%[0-9]+]], {{%.*}}) + // CHECK-DAG: [[BUFFERSIZE]] = struct $Int ([[BUFFERSIZELIT:%[0-9]+]] + // CHECK-64-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int64, 22 + // CHECK-32-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int32, 14 + + // Check whether the header bytes: premable and argument count are constants. + + // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s15OSLogTestHelper9serialize_2atys5UInt8V_SpyAEGztF + // CHECK-DAG: apply [[SERIALIZE]]([[PREAMBLE:%[0-9]+]], {{%.*}}) + // CHECK-DAG: [[PREAMBLE]] = struct $UInt8 ([[PREAMBLELIT:%[0-9]+]] : $Builtin.Int8) + // CHECK-DAG: [[PREAMBLELIT]] = integer_literal $Builtin.Int8, 3 + + // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s15OSLogTestHelper9serialize_2atys5UInt8V_SpyAEGztF + // CHECK-DAG: apply [[SERIALIZE]]([[ARGCOUNT:%[0-9]+]], {{%.*}}) + // CHECK-DAG: [[ARGCOUNT]] = struct $UInt8 ([[ARGCOUNTLIT:%[0-9]+]] : $Builtin.Int8) + // CHECK-DAG: [[ARGCOUNTLIT]] = integer_literal $Builtin.Int8, 2 + + // Check whether argument array is folded. We need not check the contents of + // the array which is checked by a different test suite. + + // CHECK-DAG: [[FOREACH:%[0-9]+]] = function_ref @$sSTsE7forEachyyy7ElementQzKXEKF + // CHECK-DAG: try_apply [[FOREACH]], inout Array) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) + // CHECK-DAG: store_borrow [[ARGSARRAY2:%[0-9]+]] to [[ARGSARRAYADDR]] + // CHECK-DAG: [[ARGSARRAY2]] = begin_borrow [[ARGSARRAY3:%[0-9]+]] + // CHECK-DAG: [[ARGSARRAY3]] = copy_value [[ARGSARRAY4:%[0-9]+]] + // CHECK-DAG: [[ARGSARRAY4]] = begin_borrow [[ARGSARRAY:%[0-9]+]] + // CHECK-DAG: ([[ARGSARRAY]], {{%.*}}) = destructure_tuple [[ARRAYINITRES:%[0-9]+]] + // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARRAYSIZE:%[0-9]+]]) + // CHECK-DAG: [[ARRAYINIT]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF + // CHECK-DAG: [[ARRAYSIZE]] = integer_literal $Builtin.Word, 6 +} + +// CHECK-LABEL: @${{.*}}testDoubleInterpolationyy +func testDoubleInterpolation() { + let twoPi = 2 * 3.14 + _osLogTestHelper("Tau = \(twoPi)") + // Check if there is a call to _os_log_impl with a literal format string. + // CHECK-DAG is used here as it is easier to perform the checks backwards + // from uses to the definitions. + + // CHECK-DAG: builtin "globalStringTablePointer"([[STRING:%[0-9]+]] : $String) + // CHECK-DAG: [[STRING]] = begin_borrow [[STRING2:%[0-9]+]] + // CHECK-DAG: [[STRING2]] = copy_value [[STRING3:%[0-9]+]] + // CHECK-DAG: [[STRING3]] = begin_borrow [[STRING4:%[0-9]+]] + // CHECK-DAG: [[STRING4]] = apply [[STRING_INIT:%[0-9]+]]([[LIT:%[0-9]+]], + // CHECK-DAG: [[STRING_INIT]] = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC + // CHECK-DAG: [[LIT]] = string_literal utf8 "Tau = %f" + + // Check if the size of the argument buffer is a constant. + + // CHECK-DAG: [[ALLOCATE:%[0-9]+]] = function_ref @$sSp8allocate8capacitySpyxGSi_tFZ + // CHECK-DAG: apply [[ALLOCATE]]([[BUFFERSIZE:%[0-9]+]], {{%.*}}) + // CHECK-DAG: [[BUFFERSIZE]] = struct $Int ([[BUFFERSIZELIT:%[0-9]+]] + // CHECK-64-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int64, 12 + // CHECK-32-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int32, 12 + + // Check whether the header bytes: premable and argument count are constants. + + // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s15OSLogTestHelper9serialize_2atys5UInt8V_SpyAEGztF + // CHECK-DAG: apply [[SERIALIZE]]([[PREAMBLE:%[0-9]+]], {{%.*}}) + // CHECK-DAG: [[PREAMBLE]] = struct $UInt8 ([[PREAMBLELIT:%[0-9]+]] : $Builtin.Int8) + // CHECK-DAG: [[PREAMBLELIT]] = integer_literal $Builtin.Int8, 0 + + // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s15OSLogTestHelper9serialize_2atys5UInt8V_SpyAEGztF + // CHECK-DAG: apply [[SERIALIZE]]([[ARGCOUNT:%[0-9]+]], {{%.*}}) + // CHECK-DAG: [[ARGCOUNT]] = struct $UInt8 ([[ARGCOUNTLIT:%[0-9]+]] : $Builtin.Int8) + // CHECK-DAG: [[ARGCOUNTLIT]] = integer_literal $Builtin.Int8, 1 + + // Check whether argument array is folded. The contents of the array is + // not checked here, but is checked by a different test suite. + + // CHECK-DAG: [[FOREACH:%[0-9]+]] = function_ref @$sSTsE7forEachyyy7ElementQzKXEKF + // CHECK-DAG: try_apply [[FOREACH]], inout Array) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) + // CHECK-DAG: store_borrow [[ARGSARRAY2:%[0-9]+]] to [[ARGSARRAYADDR]] + // CHECK-DAG: [[ARGSARRAY2]] = begin_borrow [[ARGSARRAY3:%[0-9]+]] + // CHECK-DAG: [[ARGSARRAY3]] = copy_value [[ARGSARRAY4:%[0-9]+]] + // CHECK-DAG: [[ARGSARRAY4]] = begin_borrow [[ARGSARRAY:%[0-9]+]] + // CHECK-DAG: ([[ARGSARRAY]], {{%.*}}) = destructure_tuple [[ARRAYINITRES:%[0-9]+]] + // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARRAYSIZE:%[0-9]+]]) + // CHECK-DAG: [[ARRAYINIT]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF + // CHECK-DAG: [[ARRAYSIZE]] = integer_literal $Builtin.Word, 3 +} + +// CHECK-LABEL: @${{.*}}testDeadCodeElimination6number8num32bit6stringySi_s5Int32VSStF +func testDeadCodeElimination( + number: Int, + num32bit: Int32, + string: String +) { + _osLogTestHelper("A message with no data") + _osLogTestHelper("smallstring") + _osLogTestHelper( + """ + A message with many interpolations \(number), \(num32bit), \(string), \ + and a suffix + """) + _osLogTestHelper( + """ + \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \ + \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \ + \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \ + \(1) \(1) \(1) \(1) \(1) \(48) \(49) + """) + let concatString = string + ":" + String(number) + _osLogTestHelper("\(concatString)") + // CHECK-NOT: OSLogMessage + // CHECK-NOT: OSLogInterpolation + // CHECK-LABEL: end sil function '${{.*}}testDeadCodeElimination6number8num32bit6stringySi_s5Int32VSStF +} + +protocol Proto { + var property: String { get set } +} + +// Test capturing of address-only types in autoclosures. + +// CHECK-LABEL: @${{.*}}testInterpolationOfExistentials1pyAA5Proto_p_tF +func testInterpolationOfExistentials(p: Proto) { + _osLogTestHelper("A protocol's property \(p.property)") +} + +// CHECK-LABEL: @${{.*}}testInterpolationOfGenerics1pyx_tAA5ProtoRzlF +func testInterpolationOfGenerics(p: T) { + _osLogTestHelper("A generic argument's property \(p.property)") +} + diff --git a/test/SILOptimizer/OSLogPrototypeCompileDiagnostics.swift b/test/SILOptimizer/OSLogPrototypeCompileDiagnostics.swift deleted file mode 100644 index 6634c8403776a..0000000000000 --- a/test/SILOptimizer/OSLogPrototypeCompileDiagnostics.swift +++ /dev/null @@ -1,134 +0,0 @@ -// RUN: %target-swift-frontend -swift-version 5 -emit-sil -primary-file %s -o /dev/null -verify -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos - -// Tests for the diagnostics produced by the OSLogOptimization pass that -// performs compile-time analysis and optimization of the new os log prototype -// APIs. The tests here check whether bad user inputs are diagnosed correctly. -// The tests here model the possible invalid inputs to the os log methods. -// TODO: diagnostics will be improved. globalStringTablePointer builtin error -// must be suppressed. - -import OSLogPrototype - -if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) { - - // The following tests check the diagnostics for when the APIs are not invoked - // with constants needed for generating a static format string. - - func testDynamicLogMessage(h: Logger, message: OSLogMessage) { - // FIXME: log APIs must always be passed a string interpolation literal. - // Diagnose this. - h.log(level: .debug, message) - // expected-error @-1 {{globalStringTablePointer builtin must used only on string literals}} - } - - func testNonconstantFormatOption(h: Logger, formatOpt: OSLogIntegerFormatting) { - h.log(level: .debug, "Minimum integer value: \(Int.min, format: formatOpt)") - // expected-error @-1 {{interpolation arguments like format and privacy options must be constants}} - // expected-error @-2 {{globalStringTablePointer builtin must used only on string literals}} - } - - func testNonconstantPrivacyOption(h: Logger, privacyOpt: OSLogPrivacy) { - h.log(level: .debug, "Minimum integer value: \(Int.min, privacy: privacyOpt)") - // expected-error @-1 {{interpolation arguments like format and privacy options must be constants}} - // expected-error @-2 {{globalStringTablePointer builtin must used only on string literals}} - } - - func testNoninlinedOSLogMessage(h: Logger) { - let logMessage: OSLogMessage = "Minimum integer value: \(Int.min)" - // expected-error @-1 {{OSLogMessage instance must not be explicitly created and must be deletable}} - h.log(level: .debug, logMessage) - } - - func testNoninlinedOSLogMessageComplex(h: Logger, b: Bool) { - let logMessage: OSLogMessage = "Maximum integer value: \(Int.max)" - // expected-error @-1 {{OSLogMessage instance must not be explicitly created and must be deletable}} - if !b { - return - } - h.log(level: .debug, logMessage) - // expected-error @-1 {{globalStringTablePointer builtin must used only on string literals}} - } - - func testNoninlinedFormatOptions(h: Logger) { - let formatOption: OSLogIntegerFormatting = .hex(includePrefix: true) - h.debug("Minimum integer value: \(Int.min, format: formatOption)") - // expected-error @-1 {{interpolation arguments like format and privacy options must be constants}} - // expected-error @-2 {{globalStringTablePointer builtin must used only on string literals}} - } - - func testNoninlinedFormatOptionsComplex(h: Logger, b: Bool) { - let formatOption: OSLogIntegerFormatting = .hex(includePrefix: true) - if !b { - return - } - h.debug("Minimum integer value: \(Int.min, format: formatOption)") - // expected-error @-1 {{interpolation arguments like format and privacy options must be constants}} - // expected-error @-2 {{globalStringTablePointer builtin must used only on string literals}} - } -} - -internal enum Color { - case red - case blue -} - -if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) { - - // Invoking the log calls in unreachable code should not crash the compiler. - func testUnreachableLogCall(h: Logger, c: Color) { - let arg = 10 - switch c { - case .red: - return - case .blue: - return - default: // expected-warning {{default will never be executed}} - h.debug("Unreachable log call") - h.info("Unreachable log call with argument \(arg)") - h.log( - """ - Unreachable log call with argument and formatting \ - \(arg, align: .right(columns: 10)) - """) - } - } - - // Passing InOut values to the logger should not crash the compiler. - func foo(_ logger: Logger, _ mutableValue: inout String) { - logger.log("FMFLabelledLocation: initialized with coder \(mutableValue)") - // expected-error@-1 {{escaping closure captures 'inout' parameter 'mutableValue'}} - // expected-note@-3 {{parameter 'mutableValue' is declared 'inout'}} - // expected-note@-3 {{captured here}} - } -} - -// This is an extension used only for testing a diagnostic that doesn't arise -// normally but may be triggered by changes to the library. -extension OSLogInterpolation { - @_transparent - mutating func appendInterpolation(_ c: Color) { - switch c { - case .red: - appendInterpolation(1) - case .blue: - appendInterpolation(0) - } - } -} - -if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) { - - func testUnreachableLogCallComplex(h: Logger, c: Color) { - switch c { - case .red: - return - case .blue: - return - default: // expected-warning {{default will never be executed}} - h.info("Some call \(c)") - // expected-warning@-1 {{os log call will never be executed and may have undiagnosed errors}} - // expected-error@-2 {{globalStringTablePointer builtin must used only on string literals}} - } - } -} diff --git a/test/SILOptimizer/OSLogPrototypeCompileTest.swift b/test/SILOptimizer/OSLogPrototypeCompileTest.swift deleted file mode 100644 index f7774fb0848f0..0000000000000 --- a/test/SILOptimizer/OSLogPrototypeCompileTest.swift +++ /dev/null @@ -1,620 +0,0 @@ -// RUN: %target-swift-frontend -swift-version 5 -emit-sil -primary-file %s -Xllvm -sil-print-after=OSLogOptimization -o /dev/null 2>&1 | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize -// RUN: %target-swift-frontend -enable-ownership-stripping-after-serialization -swift-version 5 -emit-sil -primary-file %s -Xllvm -sil-print-after=OSLogOptimization -o /dev/null 2>&1 | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize -// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos - -// Tests for the OSLogOptimization pass that performs compile-time analysis -// and optimization of the new os log prototype APIs. The tests here check -// whether specific compile-time constants such as the format string, -// the size of the byte buffer etc. are literals after the mandatory pipeline. - -import OSLogPrototype -import Foundation - -if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) { - - // CHECK-LABEL: @${{.*}}testSimpleInterpolationL_ - func testSimpleInterpolation(h: Logger) { - h.log(level: .debug, "Minimum integer value: \(Int.min)") - - // Check if there is a call to _os_log_impl with a literal format string. - // CHECK-DAG is used here as it is easier to perform the checks backwards - // from uses to the definitions. - - // CHECK-DAG: builtin "globalStringTablePointer"([[STRING:%[0-9]+]] : $String) - // We need to wade through some borrows and copy values here. - // CHECK-DAG: [[STRING]] = begin_borrow [[STRING2:%[0-9]+]] - // CHECK-DAG: [[STRING2]] = copy_value [[STRING3:%[0-9]+]] - // CHECK-DAG: [[STRING3]] = begin_borrow [[STRING4:%[0-9]+]] - // CHECK-DAG: [[STRING4]] = apply [[STRING_INIT:%[0-9]+]]([[LIT:%[0-9]+]], - // CHECK-DAG: [[STRING_INIT]] = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC - // CHECK-DAG: [[LIT]] = string_literal utf8 "Minimum integer value: %ld" - - // Check if the size of the argument buffer is a constant. - - // CHECK-DAG: [[ALLOCATE:%[0-9]+]] = function_ref @$sSp8allocate8capacitySpyxGSi_tFZ - // CHECK-DAG: apply [[ALLOCATE]]([[BUFFERSIZE:%[0-9]+]], {{%.*}}) - // CHECK-DAG: [[BUFFERSIZE]] = struct $Int ([[BUFFERSIZELIT:%[0-9]+]] - // CHECK-64-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int64, 12 - // CHECK-32-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int32, 8 - - // Check whether the header bytes: premable and argument count are constants. - - // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s14OSLogPrototype9serialize_2atys5UInt8V_SpyAEGztF - // CHECK-DAG: apply [[SERIALIZE]]([[PREAMBLE:%[0-9]+]], {{%.*}}) - // CHECK-DAG: [[PREAMBLE]] = struct $UInt8 ([[PREAMBLELIT:%[0-9]+]] : $Builtin.Int8) - // CHECK-DAG: [[PREAMBLELIT]] = integer_literal $Builtin.Int8, 0 - - // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s14OSLogPrototype9serialize_2atys5UInt8V_SpyAEGztF - // CHECK-DAG: apply [[SERIALIZE]]([[ARGCOUNT:%[0-9]+]], {{%.*}}) - // CHECK-DAG: [[ARGCOUNT]] = struct $UInt8 ([[ARGCOUNTLIT:%[0-9]+]] : $Builtin.Int8) - // CHECK-DAG: [[ARGCOUNTLIT]] = integer_literal $Builtin.Int8, 1 - - // Check whether argument array is folded. We need not check the contents of - // the array which is checked by a different test suite. - - // CHECK-DAG: [[FOREACH:%[0-9]+]] = function_ref @$sSTsE7forEachyyy7ElementQzKXEKF - // CHECK-DAG: try_apply [[FOREACH]], inout Array) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) - // CHECK-DAG: store_borrow [[ARGSARRAY2:%[0-9]+]] to [[ARGSARRAYADDR]] - // We need to wade through some borrows and copy values here. - // CHECK-DAG: [[ARGSARRAY2]] = begin_borrow [[ARGSARRAY3:%[0-9]+]] - // CHECK-DAG: [[ARGSARRAY3]] = copy_value [[ARGSARRAY4:%[0-9]+]] - // CHECK-DAG: [[ARGSARRAY4]] = begin_borrow [[ARGSARRAY:%[0-9]+]] - // CHECK-DAG: ([[ARGSARRAY]], {{%.*}}) = destructure_tuple [[ARRAYINITRES:%[0-9]+]] - // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARRAYSIZE:%[0-9]+]]) - // CHECK-DAG: [[ARRAYINIT]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF - // CHECK-DAG: [[ARRAYSIZE]] = integer_literal $Builtin.Word, 3 - } - - // CHECK-LABEL: @${{.*}}testInterpolationWithFormatOptionsL_ - func testInterpolationWithFormatOptions(h: Logger) { - h.log(level: .info, "Maximum unsigned integer value: \(UInt.max, format: .hex)") - - // Check if there is a call to _os_log_impl with a literal format string. - - // CHECK-DAG: builtin "globalStringTablePointer"([[STRING:%[0-9]+]] : $String) - // CHECK-DAG: [[STRING]] = begin_borrow [[STRING2:%[0-9]+]] - // CHECK-DAG: [[STRING2]] = copy_value [[STRING3:%[0-9]+]] - // CHECK-DAG: [[STRING3]] = begin_borrow [[STRING4:%[0-9]+]] - // CHECK-DAG: [[STRING4]] = apply [[STRING_INIT:%[0-9]+]]([[LIT:%[0-9]+]], - // CHECK-DAG: [[STRING_INIT]] = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC - // CHECK-DAG: [[LIT]] = string_literal utf8 "Maximum unsigned integer value: %lx" - - // Check if the size of the argument buffer is a constant. - - // CHECK-DAG: [[ALLOCATE:%[0-9]+]] = function_ref @$sSp8allocate8capacitySpyxGSi_tFZ - // CHECK-DAG: apply [[ALLOCATE]]([[BUFFERSIZE:%[0-9]+]], {{%.*}}) - // CHECK-DAG: [[BUFFERSIZE]] = struct $Int ([[BUFFERSIZELIT:%[0-9]+]] - // CHECK-64-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int64, 12 - // CHECK-32-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int32, 8 - - // Check whether the header bytes: premable and argument count are constants. - - // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s14OSLogPrototype9serialize_2atys5UInt8V_SpyAEGztF - // CHECK-DAG: apply [[SERIALIZE]]([[PREAMBLE:%[0-9]+]], {{%.*}}) - // CHECK-DAG: [[PREAMBLE]] = struct $UInt8 ([[PREAMBLELIT:%[0-9]+]] : $Builtin.Int8) - // CHECK-DAG: [[PREAMBLELIT]] = integer_literal $Builtin.Int8, 0 - - // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s14OSLogPrototype9serialize_2atys5UInt8V_SpyAEGztF - // CHECK-DAG: apply [[SERIALIZE]]([[ARGCOUNT:%[0-9]+]], {{%.*}}) - // CHECK-DAG: [[ARGCOUNT]] = struct $UInt8 ([[ARGCOUNTLIT:%[0-9]+]] : $Builtin.Int8) - // CHECK-DAG: [[ARGCOUNTLIT]] = integer_literal $Builtin.Int8, 1 - - // Check whether argument array is folded. We need not check the contents of - // the array which is checked by a different test suite. - - // CHECK-DAG: [[FOREACH:%[0-9]+]] = function_ref @$sSTsE7forEachyyy7ElementQzKXEKF - // CHECK-DAG: try_apply [[FOREACH]], inout Array) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) - // CHECK-DAG: store_borrow [[ARGSARRAY2:%[0-9]+]] to [[ARGSARRAYADDR]] - // CHECK-DAG: [[ARGSARRAY2]] = begin_borrow [[ARGSARRAY3:%[0-9]+]] - // CHECK-DAG: [[ARGSARRAY3]] = copy_value [[ARGSARRAY4:%[0-9]+]] - // CHECK-DAG: [[ARGSARRAY4]] = begin_borrow [[ARGSARRAY:%[0-9]+]] - // CHECK-DAG: ([[ARGSARRAY]], {{%.*}}) = destructure_tuple [[ARRAYINITRES:%[0-9]+]] - // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARRAYSIZE:%[0-9]+]]) - // CHECK-DAG: [[ARRAYINIT]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF - // CHECK-DAG: [[ARRAYSIZE]] = integer_literal $Builtin.Word, 3 - } - - // CHECK-LABEL: @${{.*}}testInterpolationWithFormatOptionsAndPrivacyL_ - func testInterpolationWithFormatOptionsAndPrivacy(h: Logger) { - let privateID: UInt = 0x79abcdef - h.log( - level: .error, - "Private Identifier: \(privateID, format: .hex, privacy: .private)") - - // Check if there is a call to _os_log_impl with a literal format string. - - // CHECK-DAG: builtin "globalStringTablePointer"([[STRING:%[0-9]+]] : $String) - // CHECK-DAG: [[STRING]] = begin_borrow [[STRING2:%[0-9]+]] - // CHECK-DAG: [[STRING2]] = copy_value [[STRING3:%[0-9]+]] - // CHECK-DAG: [[STRING3]] = begin_borrow [[STRING4:%[0-9]+]] - // CHECK-DAG: [[STRING4]] = apply [[STRING_INIT:%[0-9]+]]([[LIT:%[0-9]+]], - // CHECK-DAG: [[STRING_INIT]] = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC - // CHECK-DAG: [[LIT]] = string_literal utf8 "Private Identifier: %{private}lx" - - // Check if the size of the argument buffer is a constant. - - // CHECK-DAG: [[ALLOCATE:%[0-9]+]] = function_ref @$sSp8allocate8capacitySpyxGSi_tFZ - // CHECK-DAG: apply [[ALLOCATE]]([[BUFFERSIZE:%[0-9]+]], {{%.*}}) - // CHECK-DAG: [[BUFFERSIZE]] = struct $Int ([[BUFFERSIZELIT:%[0-9]+]] - // CHECK-64-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int64, 12 - // CHECK-32-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int32, 8 - - // Check whether the header bytes: premable and argument count are constants. - - // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s14OSLogPrototype9serialize_2atys5UInt8V_SpyAEGztF - // CHECK-DAG: apply [[SERIALIZE]]([[PREAMBLE:%[0-9]+]], {{%.*}}) - // CHECK-DAG: [[PREAMBLE]] = struct $UInt8 ([[PREAMBLELIT:%[0-9]+]] : $Builtin.Int8) - // CHECK-DAG: [[PREAMBLELIT]] = integer_literal $Builtin.Int8, 1 - - // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s14OSLogPrototype9serialize_2atys5UInt8V_SpyAEGztF - // CHECK-DAG: apply [[SERIALIZE]]([[ARGCOUNT:%[0-9]+]], {{%.*}}) - // CHECK-DAG: [[ARGCOUNT]] = struct $UInt8 ([[ARGCOUNTLIT:%[0-9]+]] : $Builtin.Int8) - // CHECK-DAG: [[ARGCOUNTLIT]] = integer_literal $Builtin.Int8, 1 - - // Check whether argument array is folded. We need not check the contents of - // the array which is checked by a different test suite. - - // CHECK-DAG: [[FOREACH:%[0-9]+]] = function_ref @$sSTsE7forEachyyy7ElementQzKXEKF - // CHECK-DAG: try_apply [[FOREACH]], inout Array) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) - // CHECK-DAG: store_borrow [[ARGSARRAY2:%[0-9]+]] to [[ARGSARRAYADDR]] - // CHECK-DAG: [[ARGSARRAY2]] = begin_borrow [[ARGSARRAY3:%[0-9]+]] - // CHECK-DAG: [[ARGSARRAY3]] = copy_value [[ARGSARRAY4:%[0-9]+]] - // CHECK-DAG: [[ARGSARRAY4]] = begin_borrow [[ARGSARRAY:%[0-9]+]] - // CHECK-DAG: ([[ARGSARRAY]], {{%.*}}) = destructure_tuple [[ARRAYINITRES:%[0-9]+]] - // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARRAYSIZE:%[0-9]+]]) - // CHECK-DAG: [[ARRAYINIT]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF - // CHECK-DAG: [[ARRAYSIZE]] = integer_literal $Builtin.Word, 3 - } - - // CHECK-LABEL: @${{.*}}testInterpolationWithMultipleArgumentsL_ - func testInterpolationWithMultipleArguments(h: Logger) { - let privateID = 0x79abcdef - let filePermissions: UInt = 0o777 - let pid = 122225 - h.log( - level: .error, - """ - Access prevented: process \(pid, privacy: .public) initiated by \ - user: \(privateID, privacy: .private) attempted resetting \ - permissions to \(filePermissions, format: .octal) - """) - - // Check if there is a call to _os_log_impl with a literal format string. - - // CHECK-DAG: builtin "globalStringTablePointer"([[STRING:%[0-9]+]] : $String) - // CHECK-DAG: [[STRING]] = begin_borrow [[STRING2:%[0-9]+]] - // CHECK-DAG: [[STRING2]] = copy_value [[STRING3:%[0-9]+]] - // CHECK-DAG: [[STRING3]] = begin_borrow [[STRING4:%[0-9]+]] - // CHECK-DAG: [[STRING4]] = apply [[STRING_INIT:%[0-9]+]]([[LIT:%[0-9]+]], - // CHECK-DAG: [[STRING_INIT]] = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC - // CHECK-DAG: [[LIT]] = string_literal utf8 "Access prevented: process %{public}ld initiated by user: %{private}ld attempted resetting permissions to %lo" - - // Check if the size of the argument buffer is a constant. - - // CHECK-DAG: [[ALLOCATE:%[0-9]+]] = function_ref @$sSp8allocate8capacitySpyxGSi_tFZ - // CHECK-DAG: apply [[ALLOCATE]]([[BUFFERSIZE:%[0-9]+]], {{%.*}}) - // CHECK-DAG: [[BUFFERSIZE]] = struct $Int ([[BUFFERSIZELIT:%[0-9]+]] - // CHECK-64-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int64, 32 - // CHECK-32-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int32, 20 - - // Check whether the header bytes: premable and argument count are constants. - - // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s14OSLogPrototype9serialize_2atys5UInt8V_SpyAEGztF - // CHECK-DAG: apply [[SERIALIZE]]([[PREAMBLE:%[0-9]+]], {{%.*}}) - // CHECK-DAG: [[PREAMBLE]] = struct $UInt8 ([[PREAMBLELIT:%[0-9]+]] : $Builtin.Int8) - // CHECK-DAG: [[PREAMBLELIT]] = integer_literal $Builtin.Int8, 1 - - // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s14OSLogPrototype9serialize_2atys5UInt8V_SpyAEGztF - // CHECK-DAG: apply [[SERIALIZE]]([[ARGCOUNT:%[0-9]+]], {{%.*}}) - // CHECK-DAG: [[ARGCOUNT]] = struct $UInt8 ([[ARGCOUNTLIT:%[0-9]+]] : $Builtin.Int8) - // CHECK-DAG: [[ARGCOUNTLIT]] = integer_literal $Builtin.Int8, 3 - - // Check whether argument array is folded. We need not check the contents of - // the array which is checked by a different test suite. - - // CHECK-DAG: [[FOREACH:%[0-9]+]] = function_ref @$sSTsE7forEachyyy7ElementQzKXEKF - // CHECK-DAG: try_apply [[FOREACH]], inout Array) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) - // CHECK-DAG: store_borrow [[ARGSARRAY2:%[0-9]+]] to [[ARGSARRAYADDR]] - // CHECK-DAG: [[ARGSARRAY2]] = begin_borrow [[ARGSARRAY3:%[0-9]+]] - // CHECK-DAG: [[ARGSARRAY3]] = copy_value [[ARGSARRAY4:%[0-9]+]] - // CHECK-DAG: [[ARGSARRAY4]] = begin_borrow [[ARGSARRAY:%[0-9]+]] - // CHECK-DAG: ([[ARGSARRAY]], {{%.*}}) = destructure_tuple [[ARRAYINITRES:%[0-9]+]] - // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARRAYSIZE:%[0-9]+]]) - // CHECK-DAG: [[ARRAYINIT]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF - // CHECK-DAG: [[ARRAYSIZE]] = integer_literal $Builtin.Word, 9 - } - - // CHECK-LABEL: @${{.*}}testLogMessageWithoutDataL_ - func testLogMessageWithoutData(h: Logger) { - // FIXME: here `ExpressibleByStringLiteral` conformance of OSLogMessage - // is used. In this case, the constant evaluation begins from the apply of - // the "string.makeUTF8: initializer. The constant evaluator ends up using - // the backward mode to identify the string_literal inst passed to the - // initializer. Eliminate reliance on this backward mode by starting from - // the string_literal inst, instead of initialization instruction. - h.log("A message with no data") - - // Check if there is a call to _os_log_impl with a literal format string. - - // CHECK-DAG: builtin "globalStringTablePointer"([[STRING:%[0-9]+]] : $String) - // CHECK-DAG: [[STRING]] = begin_borrow [[STRING2:%[0-9]+]] - // CHECK-DAG: [[STRING2]] = copy_value [[STRING3:%[0-9]+]] - // CHECK-DAG: [[STRING3]] = begin_borrow [[STRING4:%[0-9]+]] - // CHECK-DAG: [[STRING4]] = apply [[STRING_INIT:%[0-9]+]]([[LIT:%[0-9]+]], - // CHECK-DAG: [[STRING_INIT]] = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC - // CHECK-DAG: [[LIT]] = string_literal utf8 "A message with no data" - - // Check if the size of the argument buffer is a constant. - - // CHECK-DAG: [[ALLOCATE:%[0-9]+]] = function_ref @$sSp8allocate8capacitySpyxGSi_tFZ - // CHECK-DAG: apply [[ALLOCATE]]([[BUFFERSIZE:%[0-9]+]], {{%.*}}) - // CHECK-DAG: [[BUFFERSIZE]] = struct $Int ([[BUFFERSIZELIT:%[0-9]+]] - // CHECK-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int{{[0-9]+}}, 2 - - // Check whether the header bytes: premable and argument count are constants. - - // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s14OSLogPrototype9serialize_2atys5UInt8V_SpyAEGztF - // CHECK-DAG: apply [[SERIALIZE]]([[PREAMBLE:%[0-9]+]], {{%.*}}) - // CHECK-DAG: [[PREAMBLE]] = struct $UInt8 ([[PREAMBLELIT:%[0-9]+]] : $Builtin.Int8) - // CHECK-DAG: [[PREAMBLELIT]] = integer_literal $Builtin.Int8, 0 - - // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s14OSLogPrototype9serialize_2atys5UInt8V_SpyAEGztF - // CHECK-DAG: apply [[SERIALIZE]]([[ARGCOUNT:%[0-9]+]], {{%.*}}) - // CHECK-DAG: [[ARGCOUNT]] = struct $UInt8 ([[ARGCOUNTLIT:%[0-9]+]] : $Builtin.Int8) - // CHECK-DAG: [[ARGCOUNTLIT]] = integer_literal $Builtin.Int8, 0 - - // Check whether argument array is folded. - - // CHECK-DAG: [[FOREACH:%[0-9]+]] = function_ref @$sSTsE7forEachyyy7ElementQzKXEKF - // CHECK-DAG: try_apply [[FOREACH]], inout Array) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) - // CHECK-DAG: store_borrow [[ARGSARRAY2:%[0-9]+]] to [[ARGSARRAYADDR]] - // CHECK-DAG: [[ARGSARRAY2]] = begin_borrow [[ARGSARRAY3:%[0-9]+]] - // CHECK-DAG: [[ARGSARRAY3]] = copy_value [[ARGSARRAY4:%[0-9]+]] - // CHECK-DAG: [[ARGSARRAY4]] = begin_borrow [[ARGSARRAY:%[0-9]+]] - // CHECK-DAG: ([[ARGSARRAY]], {{%.*}}) = destructure_tuple [[ARRAYINITRES:%[0-9]+]] - // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARRAYSIZE:%[0-9]+]]) - // CHECK-DAG: [[ARRAYINIT]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF - // CHECK-DAG: [[ARRAYSIZE]] = integer_literal $Builtin.Word, 0 - } - - // CHECK-LABEL: @${{.*}}testEscapingOfPercentsL_ - func testEscapingOfPercents(h: Logger) { - h.log("Process failed after 99% completion") - // CHECK-DAG: builtin "globalStringTablePointer"([[STRING:%[0-9]+]] : $String) - // CHECK-DAG: [[STRING]] = begin_borrow [[STRING2:%[0-9]+]] - // CHECK-DAG: [[STRING2]] = copy_value [[STRING3:%[0-9]+]] - // CHECK-DAG: [[STRING3]] = begin_borrow [[STRING4:%[0-9]+]] - // CHECK-DAG: [[STRING4]] = apply [[STRING_INIT:%[0-9]+]]([[LIT:%[0-9]+]], - // CHECK-DAG: [[STRING_INIT]] = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC - // CHECK-DAG: [[LIT]] = string_literal utf8 "Process failed after 99%% completion" - } - - // CHECK-LABEL: @${{.*}}testDoublePercentsL_ - func testDoublePercents(h: Logger) { - h.log("Double percents: %%") - // CHECK-DAG: builtin "globalStringTablePointer"([[STRING:%[0-9]+]] : $String) - // CHECK-DAG: [[STRING]] = begin_borrow [[STRING2:%[0-9]+]] - // CHECK-DAG: [[STRING2]] = copy_value [[STRING3:%[0-9]+]] - // CHECK-DAG: [[STRING3]] = begin_borrow [[STRING4:%[0-9]+]] - // CHECK-DAG: [[STRING4]] = apply [[STRING_INIT:%[0-9]+]]([[LIT:%[0-9]+]], - // CHECK-DAG: [[STRING_INIT]] = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC - // CHECK-DAG: [[LIT]] = string_literal utf8 "Double percents: %%%%" - } - - // CHECK-LABEL: @${{.*}}testSmallFormatStringsL_ - func testSmallFormatStrings(h: Logger) { - h.log("a") - // CHECK-DAG: builtin "globalStringTablePointer"([[STRING:%[0-9]+]] : $String) - // CHECK-DAG: [[STRING]] = begin_borrow [[STRING2:%[0-9]+]] - // CHECK-DAG: [[STRING2]] = copy_value [[STRING3:%[0-9]+]] - // CHECK-DAG: [[STRING3]] = begin_borrow [[STRING4:%[0-9]+]] - // CHECK-DAG: [[STRING4]] = apply [[STRING_INIT:%[0-9]+]]([[LIT:%[0-9]+]], - // CHECK-DAG: [[STRING_INIT]] = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC - // CHECK-DAG: [[LIT]] = string_literal utf8 "a" - } - - /// A stress test that checks whether the optimizer handle messages with more - /// than 48 interpolated expressions. Interpolated expressions beyond this - /// limit must be ignored. - // CHECK-LABEL: @${{.*}}testMessageWithTooManyArgumentsL_ - func testMessageWithTooManyArguments(h: Logger) { - h.log( - level: .error, - """ - \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \ - \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \ - \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \ - \(1) \(1) \(1) \(1) \(1) \(48) \(49) - """) - - // Check if there is a call to _os_log_impl with a literal format string. - - // CHECK-DAG: builtin "globalStringTablePointer"([[STRING:%[0-9]+]] : $String) - // CHECK-DAG: [[STRING]] = begin_borrow [[STRING2:%[0-9]+]] - // CHECK-DAG: [[STRING2]] = copy_value [[STRING3:%[0-9]+]] - // CHECK-DAG: [[STRING3]] = begin_borrow [[STRING4:%[0-9]+]] - // CHECK-DAG: [[STRING4]] = apply [[STRING_INIT:%[0-9]+]]([[LIT:%[0-9]+]], - // CHECK-DAG: [[STRING_INIT]] = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC - // CHECK-DAG: [[LIT]] = string_literal utf8 "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld " - - // Check if the size of the argument buffer is a constant. - - // CHECK-DAG: [[ALLOCATE:%[0-9]+]] = function_ref @$sSp8allocate8capacitySpyxGSi_tFZ - // CHECK-DAG: apply [[ALLOCATE]]([[BUFFERSIZE:%[0-9]+]], {{%.*}}) - // CHECK-DAG: [[BUFFERSIZE]] = struct $Int ([[BUFFERSIZELIT:%[0-9]+]] - // CHECK-64-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int64, 482 - // CHECK-32-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int32, 290 - - // Check whether the header bytes: premable and argument count are constants. - - // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s14OSLogPrototype9serialize_2atys5UInt8V_SpyAEGztF - // CHECK-DAG: apply [[SERIALIZE]]([[PREAMBLE:%[0-9]+]], {{%.*}}) - // CHECK-DAG: [[PREAMBLE]] = struct $UInt8 ([[PREAMBLELIT:%[0-9]+]] : $Builtin.Int8) - // CHECK-DAG: [[PREAMBLELIT]] = integer_literal $Builtin.Int8, 0 - - // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s14OSLogPrototype9serialize_2atys5UInt8V_SpyAEGztF - // CHECK-DAG: apply [[SERIALIZE]]([[ARGCOUNT:%[0-9]+]], {{%.*}}) - // CHECK-DAG: [[ARGCOUNT]] = struct $UInt8 ([[ARGCOUNTLIT:%[0-9]+]] : $Builtin.Int8) - // CHECK-DAG: [[ARGCOUNTLIT]] = integer_literal $Builtin.Int8, 48 - - // Check whether argument array is folded. - - // CHECK-DAG: [[FOREACH:%[0-9]+]] = function_ref @$sSTsE7forEachyyy7ElementQzKXEKF - // CHECK-DAG: try_apply [[FOREACH]], inout Array) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) - // CHECK-DAG: store_borrow [[ARGSARRAY2:%[0-9]+]] to [[ARGSARRAYADDR]] - // CHECK-DAG: [[ARGSARRAY2]] = begin_borrow [[ARGSARRAY3:%[0-9]+]] - // CHECK-DAG: [[ARGSARRAY3]] = copy_value [[ARGSARRAY4:%[0-9]+]] - // CHECK-DAG: [[ARGSARRAY4]] = begin_borrow [[ARGSARRAY:%[0-9]+]] - // CHECK-DAG: ([[ARGSARRAY]], {{%.*}}) = destructure_tuple [[ARRAYINITRES:%[0-9]+]] - // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARRAYSIZE:%[0-9]+]]) - // CHECK-DAG: [[ARRAYINIT]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF - // CHECK-DAG: [[ARRAYSIZE]] = integer_literal $Builtin.Word, 144 - } - - // CHECK-LABEL: @${{.*}}testInt32InterpolationL_ - func testInt32Interpolation(h: Logger) { - h.log("32-bit integer value: \(Int32.min)") - - // Check if there is a call to _os_log_impl with a literal format string. - - // CHECK-DAG: builtin "globalStringTablePointer"([[STRING:%[0-9]+]] : $String) - // CHECK-DAG: [[STRING]] = begin_borrow [[STRING2:%[0-9]+]] - // CHECK-DAG: [[STRING2]] = copy_value [[STRING3:%[0-9]+]] - // CHECK-DAG: [[STRING3]] = begin_borrow [[STRING4:%[0-9]+]] - // CHECK-DAG: [[STRING4]] = apply [[STRING_INIT:%[0-9]+]]([[LIT:%[0-9]+]], - // CHECK-DAG: [[STRING_INIT]] = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC - // CHECK-DAG: [[LIT]] = string_literal utf8 "32-bit integer value: %d" - - // Check if the size of the argument buffer is a constant. - - // CHECK-DAG: [[ALLOCATE:%[0-9]+]] = function_ref @$sSp8allocate8capacitySpyxGSi_tFZ - // CHECK-DAG: apply [[ALLOCATE]]([[BUFFERSIZE:%[0-9]+]], {{%.*}}) - // CHECK-DAG: [[BUFFERSIZE]] = struct $Int ([[BUFFERSIZELIT:%[0-9]+]] - // CHECK-64-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int64, 8 - // CHECK-32-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int32, 8 - - // Check whether the header bytes: premable and argument count are constants. - - // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s14OSLogPrototype9serialize_2atys5UInt8V_SpyAEGztF - // CHECK-DAG: apply [[SERIALIZE]]([[PREAMBLE:%[0-9]+]], {{%.*}}) - // CHECK-DAG: [[PREAMBLE]] = struct $UInt8 ([[PREAMBLELIT:%[0-9]+]] : $Builtin.Int8) - // CHECK-DAG: [[PREAMBLELIT]] = integer_literal $Builtin.Int8, 0 - - // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s14OSLogPrototype9serialize_2atys5UInt8V_SpyAEGztF - // CHECK-DAG: apply [[SERIALIZE]]([[ARGCOUNT:%[0-9]+]], {{%.*}}) - // CHECK-DAG: [[ARGCOUNT]] = struct $UInt8 ([[ARGCOUNTLIT:%[0-9]+]] : $Builtin.Int8) - // CHECK-DAG: [[ARGCOUNTLIT]] = integer_literal $Builtin.Int8, 1 - } - - // CHECK-LABEL: @${{.*}}testDynamicStringArgumentsL_ - func testDynamicStringArguments(h: Logger) { - let concatString = "hello" + " - " + "world" - let interpolatedString = "\(31) trillion digits of pi are known so far" - - h.log(""" - concat: \(concatString, privacy: .public) \ - interpolated: \(interpolatedString, privacy: .private) - """) - - // Check if there is a call to _os_log_impl with a literal format string. - // CHECK-DAG is used here as it is easier to perform the checks backwards - // from uses to the definitions. - - // CHECK-DAG: builtin "globalStringTablePointer"([[STRING:%[0-9]+]] : $String) - // CHECK-DAG: [[STRING]] = begin_borrow [[STRING2:%[0-9]+]] - // CHECK-DAG: [[STRING2]] = copy_value [[STRING3:%[0-9]+]] - // CHECK-DAG: [[STRING3]] = begin_borrow [[STRING4:%[0-9]+]] - // CHECK-DAG: [[STRING4]] = apply [[STRING_INIT:%[0-9]+]]([[LIT:%[0-9]+]], - // CHECK-DAG: [[STRING_INIT]] = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC - // CHECK-DAG: [[LIT]] = string_literal utf8 "concat: %{public}s interpolated: %{private}s" - - // Check if the size of the argument buffer is a constant. - - // CHECK-DAG: [[ALLOCATE:%[0-9]+]] = function_ref @$sSp8allocate8capacitySpyxGSi_tFZ - // CHECK-DAG: apply [[ALLOCATE]]([[BUFFERSIZE:%[0-9]+]], {{%.*}}) - // CHECK-DAG: [[BUFFERSIZE]] = struct $Int ([[BUFFERSIZELIT:%[0-9]+]] - // CHECK-64-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int64, 22 - // CHECK-32-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int32, 14 - - // Check whether the header bytes: premable and argument count are constants. - - // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s14OSLogPrototype9serialize_2atys5UInt8V_SpyAEGztF - // CHECK-DAG: apply [[SERIALIZE]]([[PREAMBLE:%[0-9]+]], {{%.*}}) - // CHECK-DAG: [[PREAMBLE]] = struct $UInt8 ([[PREAMBLELIT:%[0-9]+]] : $Builtin.Int8) - // CHECK-DAG: [[PREAMBLELIT]] = integer_literal $Builtin.Int8, 3 - - // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s14OSLogPrototype9serialize_2atys5UInt8V_SpyAEGztF - // CHECK-DAG: apply [[SERIALIZE]]([[ARGCOUNT:%[0-9]+]], {{%.*}}) - // CHECK-DAG: [[ARGCOUNT]] = struct $UInt8 ([[ARGCOUNTLIT:%[0-9]+]] : $Builtin.Int8) - // CHECK-DAG: [[ARGCOUNTLIT]] = integer_literal $Builtin.Int8, 2 - - // Check whether argument array is folded. We need not check the contents of - // the array which is checked by a different test suite. - - // CHECK-DAG: [[FOREACH:%[0-9]+]] = function_ref @$sSTsE7forEachyyy7ElementQzKXEKF - // CHECK-DAG: try_apply [[FOREACH]], inout Array) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) - // CHECK-DAG: store_borrow [[ARGSARRAY2:%[0-9]+]] to [[ARGSARRAYADDR]] - // CHECK-DAG: [[ARGSARRAY2]] = begin_borrow [[ARGSARRAY3:%[0-9]+]] - // CHECK-DAG: [[ARGSARRAY3]] = copy_value [[ARGSARRAY4:%[0-9]+]] - // CHECK-DAG: [[ARGSARRAY4]] = begin_borrow [[ARGSARRAY:%[0-9]+]] - // CHECK-DAG: ([[ARGSARRAY]], {{%.*}}) = destructure_tuple [[ARRAYINITRES:%[0-9]+]] - // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARRAYSIZE:%[0-9]+]]) - // CHECK-DAG: [[ARRAYINIT]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF - // CHECK-DAG: [[ARRAYSIZE]] = integer_literal $Builtin.Word, 6 - } - - // CHECK-LABEL: @${{.*}}testNSObjectInterpolationL_ - func testNSObjectInterpolation(h: Logger) { - let nsArray: NSArray = [0, 1, 2] - let nsDictionary: NSDictionary = [1 : ""] - h.log(""" - NSArray: \(nsArray, privacy: .public) \ - NSDictionary: \(nsDictionary, privacy: .private) - """) - // Check if there is a call to _os_log_impl with a literal format string. - // CHECK-DAG is used here as it is easier to perform the checks backwards - // from uses to the definitions. - - // CHECK-DAG: builtin "globalStringTablePointer"([[STRING:%[0-9]+]] : $String) - // CHECK-DAG: [[STRING]] = begin_borrow [[STRING2:%[0-9]+]] - // CHECK-DAG: [[STRING2]] = copy_value [[STRING3:%[0-9]+]] - // CHECK-DAG: [[STRING3]] = begin_borrow [[STRING4:%[0-9]+]] - // CHECK-DAG: [[STRING4]] = apply [[STRING_INIT:%[0-9]+]]([[LIT:%[0-9]+]], - // CHECK-DAG: [[STRING_INIT]] = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC - // CHECK-DAG: [[LIT]] = string_literal utf8 "NSArray: %{public}@ NSDictionary: %{private}@" - - // Check if the size of the argument buffer is a constant. - - // CHECK-DAG: [[ALLOCATE:%[0-9]+]] = function_ref @$sSp8allocate8capacitySpyxGSi_tFZ - // CHECK-DAG: apply [[ALLOCATE]]([[BUFFERSIZE:%[0-9]+]], {{%.*}}) - // CHECK-DAG: [[BUFFERSIZE]] = struct $Int ([[BUFFERSIZELIT:%[0-9]+]] - // CHECK-64-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int64, 22 - // CHECK-32-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int32, 14 - - // Check whether the header bytes: premable and argument count are constants. - - // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s14OSLogPrototype9serialize_2atys5UInt8V_SpyAEGztF - // CHECK-DAG: apply [[SERIALIZE]]([[PREAMBLE:%[0-9]+]], {{%.*}}) - // CHECK-DAG: [[PREAMBLE]] = struct $UInt8 ([[PREAMBLELIT:%[0-9]+]] : $Builtin.Int8) - // CHECK-DAG: [[PREAMBLELIT]] = integer_literal $Builtin.Int8, 3 - - // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s14OSLogPrototype9serialize_2atys5UInt8V_SpyAEGztF - // CHECK-DAG: apply [[SERIALIZE]]([[ARGCOUNT:%[0-9]+]], {{%.*}}) - // CHECK-DAG: [[ARGCOUNT]] = struct $UInt8 ([[ARGCOUNTLIT:%[0-9]+]] : $Builtin.Int8) - // CHECK-DAG: [[ARGCOUNTLIT]] = integer_literal $Builtin.Int8, 2 - - // Check whether argument array is folded. We need not check the contents of - // the array which is checked by a different test suite. - - // CHECK-DAG: [[FOREACH:%[0-9]+]] = function_ref @$sSTsE7forEachyyy7ElementQzKXEKF - // CHECK-DAG: try_apply [[FOREACH]], inout Array) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) - // CHECK-DAG: store_borrow [[ARGSARRAY2:%[0-9]+]] to [[ARGSARRAYADDR]] - // CHECK-DAG: [[ARGSARRAY2]] = begin_borrow [[ARGSARRAY3:%[0-9]+]] - // CHECK-DAG: [[ARGSARRAY3]] = copy_value [[ARGSARRAY4:%[0-9]+]] - // CHECK-DAG: [[ARGSARRAY4]] = begin_borrow [[ARGSARRAY:%[0-9]+]] - // CHECK-DAG: ([[ARGSARRAY]], {{%.*}}) = destructure_tuple [[ARRAYINITRES:%[0-9]+]] - // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARRAYSIZE:%[0-9]+]]) - // CHECK-DAG: [[ARRAYINIT]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF - // CHECK-DAG: [[ARRAYSIZE]] = integer_literal $Builtin.Word, 6 - } - - // CHECK-LABEL: @${{.*}}testDoubleInterpolationL_ - func testDoubleInterpolation(h: Logger) { - let twoPi = 2 * 3.14 - h.log("Tau = \(twoPi)") - // Check if there is a call to _os_log_impl with a literal format string. - // CHECK-DAG is used here as it is easier to perform the checks backwards - // from uses to the definitions. - - // CHECK-DAG: builtin "globalStringTablePointer"([[STRING:%[0-9]+]] : $String) - // CHECK-DAG: [[STRING]] = begin_borrow [[STRING2:%[0-9]+]] - // CHECK-DAG: [[STRING2]] = copy_value [[STRING3:%[0-9]+]] - // CHECK-DAG: [[STRING3]] = begin_borrow [[STRING4:%[0-9]+]] - // CHECK-DAG: [[STRING4]] = apply [[STRING_INIT:%[0-9]+]]([[LIT:%[0-9]+]], - // CHECK-DAG: [[STRING_INIT]] = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC - // CHECK-DAG: [[LIT]] = string_literal utf8 "Tau = %f" - - // Check if the size of the argument buffer is a constant. - - // CHECK-DAG: [[ALLOCATE:%[0-9]+]] = function_ref @$sSp8allocate8capacitySpyxGSi_tFZ - // CHECK-DAG: apply [[ALLOCATE]]([[BUFFERSIZE:%[0-9]+]], {{%.*}}) - // CHECK-DAG: [[BUFFERSIZE]] = struct $Int ([[BUFFERSIZELIT:%[0-9]+]] - // CHECK-64-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int64, 12 - // CHECK-32-DAG: [[BUFFERSIZELIT]] = integer_literal $Builtin.Int32, 12 - - // Check whether the header bytes: premable and argument count are constants. - - // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s14OSLogPrototype9serialize_2atys5UInt8V_SpyAEGztF - // CHECK-DAG: apply [[SERIALIZE]]([[PREAMBLE:%[0-9]+]], {{%.*}}) - // CHECK-DAG: [[PREAMBLE]] = struct $UInt8 ([[PREAMBLELIT:%[0-9]+]] : $Builtin.Int8) - // CHECK-DAG: [[PREAMBLELIT]] = integer_literal $Builtin.Int8, 0 - - // CHECK-DAG: [[SERIALIZE:%[0-9]+]] = function_ref @$s14OSLogPrototype9serialize_2atys5UInt8V_SpyAEGztF - // CHECK-DAG: apply [[SERIALIZE]]([[ARGCOUNT:%[0-9]+]], {{%.*}}) - // CHECK-DAG: [[ARGCOUNT]] = struct $UInt8 ([[ARGCOUNTLIT:%[0-9]+]] : $Builtin.Int8) - // CHECK-DAG: [[ARGCOUNTLIT]] = integer_literal $Builtin.Int8, 1 - - // Check whether argument array is folded. The contents of the array is - // not checked here, but is checked by a different test suite. - - // CHECK-DAG: [[FOREACH:%[0-9]+]] = function_ref @$sSTsE7forEachyyy7ElementQzKXEKF - // CHECK-DAG: try_apply [[FOREACH]], inout Array) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) - // CHECK-DAG: store_borrow [[ARGSARRAY2:%[0-9]+]] to [[ARGSARRAYADDR]] - // CHECK-DAG: [[ARGSARRAY2]] = begin_borrow [[ARGSARRAY3:%[0-9]+]] - // CHECK-DAG: [[ARGSARRAY3]] = copy_value [[ARGSARRAY4:%[0-9]+]] - // CHECK-DAG: [[ARGSARRAY4]] = begin_borrow [[ARGSARRAY:%[0-9]+]] - // CHECK-DAG: ([[ARGSARRAY]], {{%.*}}) = destructure_tuple [[ARRAYINITRES:%[0-9]+]] - // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARRAYSIZE:%[0-9]+]]) - // CHECK-DAG: [[ARRAYINIT]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF - // CHECK-DAG: [[ARRAYSIZE]] = integer_literal $Builtin.Word, 3 - } - - // CHECK-LABEL: @${{.*}}testDeadCodeEliminationL_ - func testDeadCodeElimination( - h: Logger, - number: Int, - num32bit: Int32, - string: String - ) { - h.log("A message with no data") - h.log("smallstring") - h.log( - level: .error, - """ - A message with many interpolations \(number), \(num32bit), \(string), \ - and a suffix - """) - h.log( - level: .info, - """ - \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \ - \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \ - \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \ - \(1) \(1) \(1) \(1) \(1) \(48) \(49) - """) - let concatString = string + ":" + String(number) - h.log("\(concatString)") - // CHECK-NOT: OSLogMessage - // CHECK-NOT: OSLogInterpolation - // CHECK-LABEL: end sil function '${{.*}}testDeadCodeEliminationL_ - } -} - -protocol Proto { - var property: String { get set } -} - -// Test capturing of address-only types in autoclosures. - -if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) { - // CHECK-LABEL: @${{.*}}testInterpolationOfExistentialsL_ - func testInterpolationOfExistentials(h: Logger, p: Proto) { - h.debug("A protocol's property \(p.property)") - } - - // CHECK-LABEL: @${{.*}}testInterpolationOfGenericsL_ - func testInterpolationOfGenerics(h: Logger, p: T) { - h.debug("A generic argument's property \(p.property)") - } -} - diff --git a/test/SourceKit/CodeComplete/complete_sort_order.swift b/test/SourceKit/CodeComplete/complete_sort_order.swift index ed83a81d64022..cbfce85c35c13 100644 --- a/test/SourceKit/CodeComplete/complete_sort_order.swift +++ b/test/SourceKit/CodeComplete/complete_sort_order.swift @@ -9,23 +9,31 @@ func test() { // XFAIL: broken_std_regex // RUN: %sourcekitd-test -req=complete -req-opts=hidelowpriority=0 -pos=7:1 %s -- %s > %t.orig -// RUN: %FileCheck -check-prefix=NAME %s < %t.orig -// Make sure the order is as below, foo(Int) should come before foo(String). +// RUN: %sourcekitd-test -req=complete -req-opts=hidelowpriority=0,sort.byname=0 -pos=7:1 %s -- %s > %t.orig.off +// RUN: %FileCheck -check-prefix=NAME_SORTED %s < %t.orig +// RUN: %FileCheck -check-prefix=NAME_UNSORTED %s < %t.orig.off +// RUN: not diff -u %t.orig %t.orig.off -// NAME: key.description: "#column" -// NAME: key.description: "foo(a: Int)" -// NAME-NOT: key.description -// NAME: key.description: "foo(a: String)" -// NAME-NOT: key.description -// NAME: key.description: "foo(b: Int)" -// NAME: key.description: "test()" -// NAME: key.description: "x" +// Make sure the order is as below, foo(Int) should come before foo(String). +// NAME_SORTED: key.description: "#column" +// NAME_SORTED: key.description: "foo(a: Int)" +// NAME_SORTED-NOT: key.description +// NAME_SORTED: key.description: "foo(a: String)" +// NAME_SORTED-NOT: key.description +// NAME_SORTED: key.description: "foo(b: Int)" +// NAME_SORTED: key.description: "test()" +// NAME_SORTED: key.description: "x" + +// NAME_UNSORTED-DAG: key.description: "x" +// NAME_UNSORTED-DAG: key.description: "foo(a: String)" +// NAME_UNSORTED-DAG: key.description: "foo(a: Int)" +// NAME_UNSORTED-DAG: key.description: "foo(b: Int)" // RUN: %sourcekitd-test -req=complete.open -pos=7:1 -req-opts=hidelowpriority=0,hideunderscores=0 %s -- %s > %t.default // RUN: %sourcekitd-test -req=complete.open -pos=7:1 -req-opts=sort.byname=0,hidelowpriority=0,hideunderscores=0 %s -- %s > %t.on // RUN: %sourcekitd-test -req=complete.open -pos=7:1 -req-opts=sort.byname=1,hidelowpriority=0,hideunderscores=0 %s -- %s > %t.off // RUN: %FileCheck -check-prefix=CONTEXT %s < %t.default -// RUN: %FileCheck -check-prefix=NAME %s < %t.off +// RUN: %FileCheck -check-prefix=NAME_SORTED %s < %t.off // FIXME: rdar://problem/20109989 non-deterministic sort order // RUN-disabled: diff %t.on %t.default // RUN: %FileCheck -check-prefix=CONTEXT %s < %t.on diff --git a/test/SourceKit/Sema/educational_note_diags.swift b/test/SourceKit/Sema/educational_note_diags.swift index b0f859292cb79..c54206148ba21 100644 --- a/test/SourceKit/Sema/educational_note_diags.swift +++ b/test/SourceKit/Sema/educational_note_diags.swift @@ -1,13 +1,8 @@ extension (Int, Int) {} -// RUN: %sourcekitd-test -req=sema %s -- -Xfrontend -enable-educational-notes -Xfrontend -diagnostic-documentation-path -Xfrontend /educational/notes/path/prefix %s | %FileCheck %s -check-prefix=DESCRIPTIVE +// RUN: %sourcekitd-test -req=sema %s -- -Xfrontend -print-educational-notes -Xfrontend -diagnostic-documentation-path -Xfrontend /educational/notes/path/prefix %s | %FileCheck %s -check-prefix=DESCRIPTIVE // DESCRIPTIVE: key.description: "non-nominal type // DESCRIPTIVE: key.educational_note_paths: [ // DESCRIPTIVE-NEXT: "{{[/\\]+}}educational{{[/\\]+}}notes{{[/\\]+}}path{{[/\\]+}}prefix{{[/\\]+}}nominal-types.md" // DESCRIPTIVE-NEXT: ] - -// RUN: %sourcekitd-test -req=sema %s -- %s | %FileCheck %s -check-prefix=DESCRIPTIVE-DISABLED - -// DESCRIPTIVE-DISABLED: key.description: "non-nominal type -// DESCRIPTIVE-DISABLED-NOT: key.educational_note_paths diff --git a/test/decl/var/property_wrappers.swift b/test/decl/var/property_wrappers.swift index 035591439f5b5..852c49e6d5302 100644 --- a/test/decl/var/property_wrappers.swift +++ b/test/decl/var/property_wrappers.swift @@ -1877,7 +1877,7 @@ open class OpenPropertyWrapperWithPublicInit { public init(wrappedValue: String) { // Okay self.wrappedValue = wrappedValue } - + open var wrappedValue: String = "Hello, world" } @@ -1895,3 +1895,28 @@ func sr_11654_generic_func(_ argument: T?) -> T? { let sr_11654_c = SR_11654_C() _ = sr_11654_generic_func(sr_11654_c.property) // Okay + +// rdar://problem/59471019 - property wrapper initializer requires empty parens +// for default init +@propertyWrapper +struct DefaultableIntWrapper { + var wrappedValue: Int + + init() { + self.wrappedValue = 0 + } +} + +struct TestDefaultableIntWrapper { + @DefaultableIntWrapper var x + @DefaultableIntWrapper() var y + @DefaultableIntWrapper var z: Int + + mutating func test() { + x = y + y = z + } +} + + + diff --git a/test/diagnostics/educational-notes.swift b/test/diagnostics/educational-notes.swift index 560f7f12a185e..2d5ecfaeeeba2 100644 --- a/test/diagnostics/educational-notes.swift +++ b/test/diagnostics/educational-notes.swift @@ -1,6 +1,6 @@ -// RUN: not %target-swift-frontend -color-diagnostics -enable-educational-notes -diagnostic-documentation-path %S/test-docs/ -typecheck %s 2>&1 | %FileCheck %s --match-full-lines --strict-whitespace -// RUN: not %target-swift-frontend -no-color-diagnostics -enable-educational-notes -diagnostic-documentation-path %S/test-docs/ -typecheck %s 2>&1 | %FileCheck %s --match-full-lines --strict-whitespace --check-prefix=NO-COLOR -// RUN: not %target-swift-frontend -enable-experimental-diagnostic-formatting -enable-educational-notes -diagnostic-documentation-path %S/test-docs/ -typecheck %s 2>&1 | %FileCheck %s --check-prefix=CHECK-DESCRIPTIVE +// RUN: not %target-swift-frontend -color-diagnostics -print-educational-notes -diagnostic-documentation-path %S/test-docs/ -typecheck %s 2>&1 | %FileCheck %s --match-full-lines --strict-whitespace +// RUN: not %target-swift-frontend -no-color-diagnostics -print-educational-notes -diagnostic-documentation-path %S/test-docs/ -typecheck %s 2>&1 | %FileCheck %s --match-full-lines --strict-whitespace --check-prefix=NO-COLOR +// RUN: not %target-swift-frontend -enable-experimental-diagnostic-formatting -print-educational-notes -diagnostic-documentation-path %S/test-docs/ -typecheck %s 2>&1 | %FileCheck %s --check-prefix=CHECK-DESCRIPTIVE // A diagnostic with no educational notes let x = 1 + diff --git a/test/stdlib/OSLogPrototypeExecTest.swift b/test/stdlib/OSLogExecutionTest.swift similarity index 72% rename from test/stdlib/OSLogPrototypeExecTest.swift rename to test/stdlib/OSLogExecutionTest.swift index 237113113dcac..3d6bd4fb06748 100644 --- a/test/stdlib/OSLogPrototypeExecTest.swift +++ b/test/stdlib/OSLogExecutionTest.swift @@ -1,227 +1,28 @@ // RUN: %empty-directory(%t) -// RUN: %target-build-swift %s -swift-version 5 -DPTR_SIZE_%target-ptrsize -o %t/OSLogPrototypeExecTest -// RUN: %target-run %t/OSLogPrototypeExecTest +// RUN: %target-build-swift %s -swift-version 5 -DPTR_SIZE_%target-ptrsize -o %t/OSLogExecutionTest +// RUN: %target-run %t/OSLogExecutionTest // -// RUN: %target-build-swift %s -O -swift-version 5 -DPTR_SIZE_%target-ptrsize -o %t/OSLogPrototypeExecTest -// RUN: %target-run %t/OSLogPrototypeExecTest +// RUN: %target-build-swift %s -O -swift-version 5 -DPTR_SIZE_%target-ptrsize -o %t/OSLogExecutionTest +// RUN: %target-run %t/OSLogExecutionTest // REQUIRES: executable_test +// // REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos -// Run-time tests for testing the new OS log APIs that accept string -// interpolations. The new APIs are still prototypes and must be used only in -// tests. +// Run-time tests for testing the correctness of the optimizations that optimize the +// construction of the format string and the byte buffer from a string interpolation. +// The tests here are run with -Onone (which includes only mandatory optimizations) +// and also with full optimizations -O. -import OSLogPrototype +import OSLogTestHelper import StdlibUnittest import Foundation defer { runAllTests() } -internal var OSLogTestSuite = TestSuite("OSLogTest") - -if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) { - - // Following tests check whether valid log calls execute without - // compile-time and run-time errors. - - func logMessages(_ h: Logger) { - // Test logging of simple messages. - h.log("A message with no data") - - // Test logging at specific levels. - h.debug("Minimum integer value: \(Int.min)") - h.info("Maximum unsigned integer value: \(UInt.max, format: .hex)") - - let privateID: UInt = 0x79abcdef - h.error("Private Identifier: \(privateID, format: .hex, privacy: .private)") - let addr: UInt = 0x7afebabe - h.fault("Invalid address: 0x\(addr, format: .hex, privacy: .public)") - - // Test logging with multiple arguments. - let filePermissions: UInt = 0o777 - let pid = 122225 - h.error( - """ - Access prevented: process \(pid) initiated by \ - user: \(privateID, privacy: .private) attempted resetting \ - permissions to \(filePermissions, format: .octal) - """) - } - - OSLogTestSuite.test("log with default logger") { - let h = Logger() - logMessages(h) - } - - OSLogTestSuite.test("log with custom logger") { - let h = - Logger(subsystem: "com.swift.test", category: "OSLogAPIPrototypeTest") - logMessages(h) - } - - OSLogTestSuite.test("escaping of percents") { - let h = Logger() - h.log("a = c % d") - h.log("Process failed after 99% completion") - h.log("Double percents: %%") - } - - // A stress test that checks whether the log APIs handle messages with more - // than 48 interpolated expressions. Interpolated expressions beyond this - // limit must be ignored. - OSLogTestSuite.test("messages with too many arguments") { - let h = Logger() - h.log( - level: .error, - """ - \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \ - \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \ - \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \ - \(1) \(1) \(1) \(1) \(1) \(48) \(49) - """) // The number 49 should not appear in the logged message. - } - - OSLogTestSuite.test("escape characters") { - let h = Logger() - h.log("\"Imagination is more important than knowledge\" - Einstein") - h.log("\'Imagination is more important than knowledge\' - Einstein") - h.log("Imagination is more important than knowledge \n - Einstein") - h.log("Imagination is more important than knowledge - \\Einstein") - h.log("The log message will be truncated here.\0 You won't see this") - } - - OSLogTestSuite.test("unicode characters") { - let h = Logger() - h.log("dollar sign: \u{24}") - h.log("black heart: \u{2665}") - h.log("sparkling heart: \u{1F496}") - } - - OSLogTestSuite.test("raw strings") { - let h = Logger() - let x = 10 - - h.log(#"There is no \(interpolated) value in this string"#) - h.log(#"This is not escaped \n"#) - h.log(##"'\b' is a printf escape character but not in Swift"##) - h.log(##"The interpolated value is \##(x)"##) - h.log(#"Sparkling heart should appear in the next line. \#n \#u{1F496}"#) - } - - OSLogTestSuite.test("integer types") { - let h = Logger() - h.log("Smallest 32-bit integer value: \(Int32.min)") - } - - OSLogTestSuite.test("dynamic strings") { - let h = Logger() - - let smallString = "a" - h.log("A small string: \(smallString, privacy: .public)") - - let largeString = "This is a large String" - h.log("\(largeString, privacy: .public)") - - let concatString = "hello" + " - " + "world" - h.log("A dynamic string: \(concatString, privacy: .public)") - - let interpolatedString = "\(31) trillion digits of pi are known so far" - h.log("\(interpolatedString)") - } - - OSLogTestSuite.test("NSObject") { - let h = Logger() - - let smallNSString: NSString = "a" - h.log("A small string: \(smallNSString, privacy: .public)") - - let largeNSString: NSString = "This is a large String" - h.log("\(largeNSString, privacy: .public)") - - let nsArray: NSArray = [0, 1, 2] - h.log("NS Array: \(nsArray, privacy: .public)") - - let nsDictionary: NSDictionary = [1 : ""] - h.log("NS Dictionary: \(nsDictionary, privacy: .public)") - } - - OSLogTestSuite.test("integer formatting") { - let h = Logger() - - let unsignedOctal: UInt = 0o171 - // format specifier "0o%lo" output: "0o171" - h.log("\(unsignedOctal, format: .octal(includePrefix: true))") - - // format specifier: "%lX" output: "DEADBEEF" - let unsignedValue: UInt = 0xdeadbeef - h.log("\(unsignedValue, format: .hex(uppercase: true))") - - // format specifier: "%+ld" output: "+20" - h.log("\(20, format: .decimal(explicitPositiveSign: true))") - - // format specifier: "+%lu" output: "+2" - h.log("\(UInt(2), format: .decimal(explicitPositiveSign: true))") - - // format specifier: "%.10ld" output: "0000000010" - h.log("\(10, format: .decimal(minDigits: 10))") - - // format specifier: "%10ld" output: " 10" - h.log("\(10, align: .right(columns: 10))") - - // format specifier: "%-5ld" output: "10 " - h.log("\(10, align: .left(columns: 5))") - } - - func logWithDynamicPrecisionAndAlignment( - _ h: Logger, - _ value: Int, - columns: Int, - minDigits: Int - ) { - h.log( - """ - dynamic precision/alignment: \ - \(value, - format: .decimal(minDigits: minDigits), - align: .right(columns: columns)) - """) - } - - OSLogTestSuite.test("dynamic precision and alignment") { - let h = Logger() - // Format specifier: "%*.*ld", expected output: " 0019" - logWithDynamicPrecisionAndAlignment(h, 19, columns: 10, minDigits: 4) - // Prints three stars in a diagonal. - for i in 0..<3 { - h.log("\("*", align: .right(columns: 10 - i))") - } - } - - OSLogTestSuite.test("string formatting") { - let h = Logger() - let smallString = "a" - h.log("\(smallString, align: .right(columns: 10), privacy: .public)") - } - - OSLogTestSuite.test("Floats and Doubles") { - let h = Logger() - let x = 1.2 + 0.5 - let pi: Double = 3.141593 - let floatPi: Float = 3.141593 - h.log("A double value: \(x, privacy: .private)") - h.log("pi as double: \(pi), pi as float: \(floatPi)") - } -} - -// The following tests check the correctness of the format string and the -// byte buffer constructed by the APIs from a string interpolation. -// These tests do not perform logging and do not require the os_log ABIs to -// be available. - internal var InterpolationTestSuite = TestSuite("OSLogInterpolationTest") internal let bitsPerByte = 8 -/// A struct that exposes methods for checking whether a given byte buffer +/// A struct that provides methods for checking whether a given byte buffer /// conforms to the format expected by the os_log ABI. This struct acts as /// a specification of the byte buffer format. internal struct OSLogBufferChecker { @@ -459,9 +260,9 @@ internal struct OSLogBufferChecker { } InterpolationTestSuite.test("integer literal") { - _checkFormatStringAndBuffer( + _osLogTestHelper( "An integer literal \(10)", - with: { (formatString, buffer) in + assertion: { (formatString, buffer) in expectEqual( "An integer literal %ld", formatString) @@ -479,9 +280,9 @@ InterpolationTestSuite.test("integer literal") { } InterpolationTestSuite.test("integer with formatting") { - _checkFormatStringAndBuffer( + _osLogTestHelper( "Minimum integer value: \(UInt.max, format: .hex)", - with: { (formatString, buffer) in + assertion: { (formatString, buffer) in expectEqual( "Minimum integer value: %lx", formatString) @@ -503,9 +304,9 @@ InterpolationTestSuite.test("integer with formatting") { InterpolationTestSuite.test("integer with privacy and formatting") { let addr: UInt = 0x7afebabe - _checkFormatStringAndBuffer( + _osLogTestHelper( "Access to invalid address: \(addr, format: .hex, privacy: .private)", - with: { (formatString, buffer) in + assertion: { (formatString, buffer) in expectEqual( "Access to invalid address: %{private}lx", formatString) @@ -530,13 +331,13 @@ InterpolationTestSuite.test("test multiple arguments") { let pid = 122225 let privateID = 0x79abcdef - _checkFormatStringAndBuffer( + _osLogTestHelper( """ Access prevented: process \(pid, privacy: .public) initiated by \ user: \(privateID, privacy: .private) attempted resetting \ permissions to \(filePerms, format: .octal) """, - with: { (formatString, buffer) in + assertion: { (formatString, buffer) in expectEqual( """ Access prevented: process %{public}ld initiated by \ @@ -576,14 +377,14 @@ InterpolationTestSuite.test("test multiple arguments") { InterpolationTestSuite.test("interpolation of too many arguments") { // The following string interpolation has 49 interpolated values. Only 48 // of these must be present in the generated format string and byte buffer. - _checkFormatStringAndBuffer( + _osLogTestHelper( """ \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \ \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \ \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \(1) \ \(1) \(1) \(1) \(1) \(1) \(1) \(1) """, - with: { (formatString, buffer) in + assertion: { (formatString, buffer) in expectEqual( String( repeating: "%ld ", @@ -609,9 +410,9 @@ InterpolationTestSuite.test("interpolation of too many arguments") { } InterpolationTestSuite.test("string interpolations with percents") { - _checkFormatStringAndBuffer( + _osLogTestHelper( "a = (c % d)%%", - with: { (formatString, buffer) in + assertion: { (formatString, buffer) in expectEqual("a = (c %% d)%%%%", formatString) @@ -624,7 +425,7 @@ InterpolationTestSuite.test("string interpolations with percents") { } InterpolationTestSuite.test("integer types") { - _checkFormatStringAndBuffer("Int32 max: \(Int32.max)") { + _osLogTestHelper("Int32 max: \(Int32.max)") { (formatString, buffer) in expectEqual("Int32 max: %d", formatString) @@ -646,7 +447,7 @@ InterpolationTestSuite.test("integer types") { InterpolationTestSuite.test("string arguments") { let small = "a" let large = "this is a large string" - _checkFormatStringAndBuffer( + _osLogTestHelper( "small: \(small, privacy: .public) large: \(large)") { (formatString, buffer) in expectEqual("small: %{public}s large: %s", formatString) @@ -676,7 +477,7 @@ InterpolationTestSuite.test("dynamic strings") { let concatString = "hello" + " - " + "world" let interpolatedString = "\(31) trillion digits of pi are known so far" - _checkFormatStringAndBuffer( + _osLogTestHelper( """ concat: \(concatString, privacy: .public) \ interpolated: \(interpolatedString, privacy: .private) @@ -708,7 +509,7 @@ InterpolationTestSuite.test("NSObject") { let nsArray: NSArray = [0, 1, 2] let nsDictionary: NSDictionary = [1 : ""] - _checkFormatStringAndBuffer( + _osLogTestHelper( """ NSArray: \(nsArray, privacy: .public) \ NSDictionary: \(nsDictionary) @@ -748,7 +549,7 @@ InterpolationTestSuite.test("Interpolation of complex expressions") { class TestClass: NSObject { func testFunction() { // The following call should not crash. - _checkFormatStringAndBuffer("A complex expression \(toString(self))") { + _osLogTestHelper("A complex expression \(toString(self))") { (formatString, _) in expectEqual("A complex expression %s", formatString) } @@ -760,7 +561,7 @@ InterpolationTestSuite.test("Interpolation of complex expressions") { InterpolationTestSuite.test("Include prefix formatting option") { let unsignedValue: UInt = 0o171 - _checkFormatStringAndBuffer( + _osLogTestHelper( "Octal with prefix: \(unsignedValue, format: .octal(includePrefix: true))") { (formatString, buffer) in expectEqual("Octal with prefix: 0o%lo", formatString) @@ -769,7 +570,7 @@ InterpolationTestSuite.test("Include prefix formatting option") { InterpolationTestSuite.test("Hex with uppercase formatting option") { let unsignedValue: UInt = 0xcafebabe - _checkFormatStringAndBuffer( + _osLogTestHelper( "Hex with uppercase: \(unsignedValue, format: .hex(uppercase: true))") { (formatString, buffer) in expectEqual("Hex with uppercase: %lX", formatString) @@ -778,7 +579,7 @@ InterpolationTestSuite.test("Hex with uppercase formatting option") { InterpolationTestSuite.test("Integer with explicit positive sign") { let posValue = Int.max - _checkFormatStringAndBuffer( + _osLogTestHelper( "\(posValue, format: .decimal(explicitPositiveSign: true))") { (formatString, buffer) in expectEqual("%+ld", formatString) @@ -787,7 +588,7 @@ InterpolationTestSuite.test("Integer with explicit positive sign") { InterpolationTestSuite.test("Unsigned integer with explicit positive sign") { let posValue = UInt.max - _checkFormatStringAndBuffer( + _osLogTestHelper( "\(posValue, format: .decimal(explicitPositiveSign: true))") { (formatString, buffer) in expectEqual("+%lu", formatString) @@ -796,7 +597,7 @@ InterpolationTestSuite.test("Unsigned integer with explicit positive sign") { InterpolationTestSuite.test("Integer formatting with precision") { let intValue = 1200 - _checkFormatStringAndBuffer( + _osLogTestHelper( "\(intValue, format: .decimal(minDigits: 10))") { (formatString, buffer) in expectEqual("%.*ld", formatString) @@ -824,7 +625,7 @@ InterpolationTestSuite.test("Integer formatting with precision") { InterpolationTestSuite.test("Integer formatting with alignment") { let intValue = 10 - _checkFormatStringAndBuffer( + _osLogTestHelper( """ \(intValue, align: .right(columns: 10)) \ \(intValue, align: .left(columns: 5), privacy: .private) @@ -836,7 +637,7 @@ InterpolationTestSuite.test("Integer formatting with alignment") { InterpolationTestSuite.test("Integer formatting with precision and alignment") { let intValue = 1200 - _checkFormatStringAndBuffer( + _osLogTestHelper( "\(intValue, format: .decimal(minDigits: 10), align: .left(columns: 7))") { (formatString, buffer) in expectEqual("%-*.*ld", formatString) @@ -870,7 +671,7 @@ InterpolationTestSuite.test("Integer formatting with precision and alignment") { InterpolationTestSuite.test("String with alignment") { let smallString = "a" + "b" let concatString = "hello" + " - " + "world" - _checkFormatStringAndBuffer( + _osLogTestHelper( """ \(smallString, align: .right(columns: 10)) \ \(concatString, align: .left(columns: 7), privacy: .public) @@ -884,7 +685,7 @@ InterpolationTestSuite.test("Floats and Doubles") { let x = 1.2 + 0.5 let pi: Double = 3.141593 let floatPi: Float = 3.141593 - _checkFormatStringAndBuffer( + _osLogTestHelper( """ A double value: \(x, privacy: .private) \ pi as double: \(pi), pi as float: \(floatPi) diff --git a/test/stdlib/StaticString.swift b/test/stdlib/StaticString.swift index 30aba3e413d0b..f41dcfb765d9b 100644 --- a/test/stdlib/StaticString.swift +++ b/test/stdlib/StaticString.swift @@ -8,6 +8,7 @@ var StaticStringTestSuite = TestSuite("StaticString") StaticStringTestSuite.test("PointerRepresentation/ASCII/Empty") { let str = StaticString() + expectEqual(0x00, str.utf8Start[0]) expectEqual(0, str.utf8CodeUnitCount) expectTrue(str.hasPointerRepresentation) expectTrue(str.isASCII) @@ -26,6 +27,7 @@ StaticStringTestSuite.test("PointerRepresentation/ASCII") { expectEqual(0x61, str.utf8Start[0]) expectEqual(0x62, str.utf8Start[1]) expectEqual(0x63, str.utf8Start[2]) + expectEqual(0x00, str.utf8Start[3]) expectEqual(3, str.utf8CodeUnitCount) expectTrue(str.hasPointerRepresentation) expectTrue(str.isASCII) @@ -50,6 +52,7 @@ StaticStringTestSuite.test("PointerRepresentation/NonASCII") { expectEqual(0xb1, str.utf8Start[3]) expectEqual(0xd0, str.utf8Start[4]) expectEqual(0xb2, str.utf8Start[5]) + expectEqual(0x00, str.utf8Start[6]) expectEqual(6, str.utf8CodeUnitCount) expectTrue(str.hasPointerRepresentation) expectFalse(str.isASCII) diff --git a/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp b/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp index 0947f35d276ee..0195df09afc0b 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp @@ -182,7 +182,8 @@ void SwiftLangSupport::codeComplete( SKConsumer.setCompletionKind(kind); bool hasRequiredType = info.completionContext->typeContextKind == TypeContextKind::Required; - CodeCompletionContext::sortCompletionResults(Results); + if (CCOpts.sortByName) + CodeCompletionContext::sortCompletionResults(Results); // FIXME: this adhoc filtering should be configurable like it is in the // codeCompleteOpen path. for (auto *Result : Results) { diff --git a/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp b/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp index 163a6aaf480b3..748a4d4e072b8 100644 --- a/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp +++ b/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp @@ -593,6 +593,8 @@ static int handleTestInvocation(TestOptions Opts, TestOptions &InitOpts) { sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestCodeComplete); sourcekitd_request_dictionary_set_int64(Req, KeyOffset, ByteOffset); sourcekitd_request_dictionary_set_string(Req, KeyName, SemaName.c_str()); + // Default to sort by name. + Opts.RequestOptions.insert(Opts.RequestOptions.begin(), "sort.byname=1"); addCodeCompleteOptions(Req, Opts); break; diff --git a/unittests/AST/ArithmeticEvaluator.cpp b/unittests/AST/ArithmeticEvaluator.cpp index ed85576e07c57..f1b15d107ddc6 100644 --- a/unittests/AST/ArithmeticEvaluator.cpp +++ b/unittests/AST/ArithmeticEvaluator.cpp @@ -81,6 +81,12 @@ void simple_display(llvm::raw_ostream &out, ArithmeticExpr *expr) { } } +/// Helper to short-circuit errors to NaN. +template +static double evalOrNaN(Evaluator &evaluator, const Request &request) { + return evaluateOrDefault(evaluator, request, NAN); +} + /// Rule to evaluate the value of the expression. template struct EvaluationRule @@ -89,8 +95,9 @@ struct EvaluationRule using SimpleRequest ::SimpleRequest; - llvm::Expected - evaluate(Evaluator &evaluator, ArithmeticExpr *expr) const { + static bool brokeCycle; + + double evaluate(Evaluator &evaluator, ArithmeticExpr *expr) const { switch (expr->kind) { case ArithmeticExpr::Kind::Literal: return static_cast(expr)->value; @@ -99,19 +106,23 @@ struct EvaluationRule auto binary = static_cast(expr); // Evaluate the left- and right-hand sides. - auto lhsValue = evaluator(Derived{binary->lhs}); - if (!lhsValue) + auto lhsValue = evalOrNaN(evaluator, Derived{binary->lhs}); + if (std::isnan(lhsValue)) { + brokeCycle = true; return lhsValue; - auto rhsValue = evaluator(Derived{binary->rhs}); - if (!rhsValue) + } + auto rhsValue = evalOrNaN(evaluator, Derived{binary->rhs}); + if (std::isnan(rhsValue)) { + brokeCycle = true; return rhsValue; + } switch (binary->operatorKind) { case Binary::OperatorKind::Sum: - return *lhsValue + *rhsValue; + return lhsValue + rhsValue; case Binary::OperatorKind::Product: - return *lhsValue * *rhsValue; + return lhsValue * rhsValue; } } } @@ -120,6 +131,9 @@ struct EvaluationRule SourceLoc getNearestLoc() const { return SourceLoc(); } }; +template +bool EvaluationRule::brokeCycle = false; + struct InternallyCachedEvaluationRule : EvaluationRule { @@ -192,12 +206,6 @@ static AbstractRequestFunction *arithmeticRequestFunctions[] = { #undef SWIFT_REQUEST }; -/// Helper to short-circuit errors to NaN. -template -static double evalOrNaN(Evaluator &evaluator, const Request &request) { - return evaluateOrDefault(evaluator, request, NAN); -} - TEST(ArithmeticEvaluator, Simple) { // (3.14159 + 2.71828) * 42 @@ -342,15 +350,42 @@ TEST(ArithmeticEvaluator, Cycle) { arithmeticRequestFunctions); // Evaluate when there is a cycle. - bool cycleDetected = false; - auto result = evaluator(UncachedEvaluationRule(sum)); - if (auto err = result.takeError()) { - llvm::handleAllErrors(std::move(err), - [&](const CyclicalRequestError &E) { - cycleDetected = true; - }); - } - EXPECT_TRUE(cycleDetected); + UncachedEvaluationRule::brokeCycle = false; + EXPECT_TRUE(std::isnan(evalOrNaN(evaluator, + UncachedEvaluationRule(product)))); + EXPECT_TRUE(UncachedEvaluationRule::brokeCycle); + + // Cycle-breaking result is cached. + EXPECT_TRUE(std::isnan(evalOrNaN(evaluator, + UncachedEvaluationRule(product)))); + UncachedEvaluationRule::brokeCycle = false; + EXPECT_FALSE(UncachedEvaluationRule::brokeCycle); + + // Evaluate when there is a cycle. + evaluator.clearCache(); + InternallyCachedEvaluationRule::brokeCycle = false; + EXPECT_TRUE(std::isnan(evalOrNaN(evaluator, + InternallyCachedEvaluationRule(product)))); + EXPECT_TRUE(InternallyCachedEvaluationRule::brokeCycle); + + // Cycle-breaking result is cached. + InternallyCachedEvaluationRule::brokeCycle = false; + EXPECT_TRUE(std::isnan(evalOrNaN(evaluator, + InternallyCachedEvaluationRule(product)))); + EXPECT_FALSE(InternallyCachedEvaluationRule::brokeCycle); + + // Evaluate when there is a cycle. + evaluator.clearCache(); + ExternallyCachedEvaluationRule::brokeCycle = false; + EXPECT_TRUE(std::isnan(evalOrNaN(evaluator, + ExternallyCachedEvaluationRule(product)))); + EXPECT_TRUE(ExternallyCachedEvaluationRule::brokeCycle); + + // Cycle-breaking result is cached. + ExternallyCachedEvaluationRule::brokeCycle = false; + EXPECT_TRUE(std::isnan(evalOrNaN(evaluator, + ExternallyCachedEvaluationRule(product)))); + EXPECT_FALSE(ExternallyCachedEvaluationRule::brokeCycle); // Dependency printing. std::string productDependencies; diff --git a/unittests/Reflection/RemoteMirrorInterop/test.m b/unittests/Reflection/RemoteMirrorInterop/test.m index 356c2c3529525..e625e9c829831 100644 --- a/unittests/Reflection/RemoteMirrorInterop/test.m +++ b/unittests/Reflection/RemoteMirrorInterop/test.m @@ -136,6 +136,13 @@ int main(int argc, char **argv) { printf("Kind:%u Size:%u Alignment:%u Stride:%u NumFields:%u\n", TypeInfo.Kind, TypeInfo.Size, TypeInfo.Alignment, TypeInfo.Stride, TypeInfo.NumFields); + char *Name = swift_reflection_interop_copyDemangledNameForTypeRef(Context, Type); + if (Name) { + printf("Demangled name: %s\n", Name); + free(Name); + } else { + printf("Could not get name.\n"); + } } else { printf("Unknown typeref!\n"); } diff --git a/unittests/Reflection/RemoteMirrorInterop/test.py b/unittests/Reflection/RemoteMirrorInterop/test.py index 57061bab0bb4c..a18ca81c6ef63 100755 --- a/unittests/Reflection/RemoteMirrorInterop/test.py +++ b/unittests/Reflection/RemoteMirrorInterop/test.py @@ -16,13 +16,21 @@ if len(args) == 0: print >> sys.stderr, "Usage:", sys.argv[0], "swift-build-dirs..." print >> sys.stderr, ("Note: pass paths to the swift-macosx-x86_64" - " directories.") + " directories, or /usr to test the OS.") sys.exit(1) absoluteArgs = [os.path.abspath(arg) for arg in args] swiftcs = [os.path.join(arg, 'bin', 'swiftc') for arg in absoluteArgs] -swiftlibs = [os.path.join(arg, 'lib', 'swift', 'macosx') - for arg in absoluteArgs] + + +def libPath(path): + libPath = os.path.join(path, 'lib', 'swift', 'macosx') + if not os.path.isdir(libPath): + libPath = os.path.join(path, 'lib', 'swift') + return libPath + + +swiftlibs = [libPath(arg) for arg in absoluteArgs] mirrorlibs = [os.path.join(lib, 'libswiftRemoteMirror.dylib') for lib in swiftlibs] diff --git a/utils/build-script-impl b/utils/build-script-impl index 3656788aa540c..dec9202a7f8ab 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -1895,6 +1895,17 @@ for host in "${ALL_HOSTS[@]}"; do -DLLDB_TEST_USER_ARGS="${DOTEST_ARGS}" ) + if [[ $(is_cross_tools_host ${host}) ]] ; then + cmake_options=( + "${cmake_options[@]}" + -DLLVM_TABLEGEN=$(build_directory "${LOCAL_HOST}" llvm)/bin/llvm-tblgen + -DCLANG_TABLEGEN=$(build_directory "${LOCAL_HOST}" llvm)/bin/clang-tblgen + -DLLDB_TABLEGEN=$(build_directory "${LOCAL_HOST}" lldb)/bin/lldb-tblgen + -DLLDB_TABLEGEN_EXE=$(build_directory "${LOCAL_HOST}" lldb)/bin/lldb-tblgen + -DLLVM_NATIVE_BUILD=$(build_directory "${LOCAL_HOST}" llvm) + ) + fi + if [[ "$(uname -s)" == "Darwin" && "$(true_false ${LLDB_USE_SYSTEM_DEBUGSERVER})" == "TRUE" ]]; then cmake_options+=( -DLLDB_USE_SYSTEM_DEBUGSERVER:BOOL="${LLDB_USE_SYSTEM_DEBUGSERVER}" diff --git a/utils/update_checkout/__init__.py b/utils/update_checkout/__init__.py index 7d293923c962d..99cc1c7c3d1d1 100644 --- a/utils/update_checkout/__init__.py +++ b/utils/update_checkout/__init__.py @@ -1,4 +1,4 @@ -from update_checkout import main +from .update_checkout import main __all__ = ["main"] diff --git a/utils/update_checkout/update_checkout/__init__.py b/utils/update_checkout/update_checkout/__init__.py index 7d293923c962d..99cc1c7c3d1d1 100644 --- a/utils/update_checkout/update_checkout/__init__.py +++ b/utils/update_checkout/update_checkout/__init__.py @@ -1,4 +1,4 @@ -from update_checkout import main +from .update_checkout import main __all__ = ["main"] diff --git a/validation-test/Reflection/existentials.swift b/validation-test/Reflection/existentials.swift index e9955a0eb05da..02b41e9c89370 100644 --- a/validation-test/Reflection/existentials.swift +++ b/validation-test/Reflection/existentials.swift @@ -69,6 +69,7 @@ reflect(any: mc) // CHECK-64: Type info: // CHECK-64: (reference kind=strong refcounting=native) // CHECK-64: Mangled name: $s12existentials7MyClassCyS2iG +// CHECK-64: Demangled name: existentials.MyClass // CHECK-32: Reflecting an existential. // CHECK-32: Instance pointer in child address space: 0x{{[0-9a-fA-F]+}} @@ -79,6 +80,7 @@ reflect(any: mc) // CHECK-32: Type info: // CHECK-32: (reference kind=strong refcounting=native) // CHECK-32: Mangled name: $s12existentials7MyClassCyS2iG +// CHECK-32: Demangled name: existentials.MyClass // This value fits in the 3-word buffer in the container. var smallStruct = MyStruct(x: 1, y: 2, z: 3) @@ -107,6 +109,7 @@ reflect(any: smallStruct) // CHECK-64-NEXT: (field name=_value offset=0 // CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0 bitwise_takable=1))))) // CHECK-64-NEXT: Mangled name: $s12existentials8MyStructVyS3iG +// CHECK-64-NEXT: Demangled name: existentials.MyStruct // CHECK-32: Reflecting an existential. // CHECK-32: Instance pointer in child address space: 0x{{[0-9a-fA-F]+}} @@ -131,6 +134,7 @@ reflect(any: smallStruct) // CHECK-32-NEXT: (field name=_value offset=0 // CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0 bitwise_takable=1))))) // CHECK-32-NEXT: Mangled name: $s12existentials8MyStructVyS3iG +// CHECK-32-NEXT: Demangled name: existentials.MyStruct // This value will be copied into a heap buffer, with a // pointer to it in the existential. @@ -198,6 +202,7 @@ reflect(any: largeStruct) // CHECK-64-NEXT: (field name=_value offset=0 // CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0 bitwise_takable=1))))))) // CHECK-64-NEXT: Mangled name: $s12existentials8MyStructVySi_S2itSi_S2itSi_S2itG +// CHECK-64-NEXT: Demangled name: existentials.MyStruct<(Swift.Int, Swift.Int, Swift.Int), (Swift.Int, Swift.Int, Swift.Int), (Swift.Int, Swift.Int, Swift.Int)> // CHECK-32: Reflecting an existential. // CHECK-32: Instance pointer in child address space: 0x{{[0-9a-fA-F]+}} @@ -260,11 +265,14 @@ reflect(any: largeStruct) // CHECK-32-NEXT: (field name=_value offset=0 // CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0 bitwise_takable=1))))))) // CHECK-32-NEXT: Mangled name: $s12existentials8MyStructVySi_S2itSi_S2itSi_S2itG +// CHECK-32-NEXT: Demangled name: existentials.MyStruct<(Swift.Int, Swift.Int, Swift.Int), (Swift.Int, Swift.Int, Swift.Int), (Swift.Int, Swift.Int, Swift.Int)> // Function type: reflect(any: {largeStruct}) // CHECK-64: Mangled name: $s12existentials8MyStructVySi_S2itSi_S2itSi_S2itGyc +// CHECK-64: Demangled name: () -> existentials.MyStruct<(Swift.Int, Swift.Int, Swift.Int), (Swift.Int, Swift.Int, Swift.Int), (Swift.Int, Swift.Int, Swift.Int)> // CHECK-32: Mangled name: $s12existentials8MyStructVySi_S2itSi_S2itSi_S2itGyc +// CHECK-32: Demangled name: () -> existentials.MyStruct<(Swift.Int, Swift.Int, Swift.Int), (Swift.Int, Swift.Int, Swift.Int), (Swift.Int, Swift.Int, Swift.Int)> // Protocol composition: protocol P {} @@ -273,13 +281,17 @@ protocol Composition : P, Q {} struct S : Composition {} func getComposition() -> P & Q { return S() } reflect(any: getComposition()) -// CHECK-64: Mangled name: $s12existentials1P_AA1Qp -// CHECK-32: Mangled name: $s12existentials1P_AA1Qp +// CHECK-64: Mangled name: $s12existentials1PP_AA1QPp +// CHECK-64: Demangled name: existentials.P & existentials.Q +// CHECK-32: Mangled name: $s12existentials1PP_AA1QPp +// CHECK-32: Demangled name: existentials.P & existentials.Q // Metatype: reflect(any: Int.self) // CHECK-64: Mangled name: $sSim +// CHECK-64: Demangled name: Swift.Int.Type // CHECK-32: Mangled name: $sSim +// CHECK-32: Demangled name: Swift.Int.Type protocol WithType { associatedtype T @@ -332,6 +344,7 @@ reflect(any: he) // CHECK-64-NEXT: (field name=wtable offset=40 // CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=1 bitwise_takable=1))))) // CHECK-64-NEXT: Mangled name: $s12existentials8HasErrorV +// CHECK-64-NEXT: Demangled name: existentials.HasError // CHECK-32: Reflecting an existential. // CHECK-32: Instance pointer in child address space: 0x{{[0-9a-fA-F]+}} @@ -367,6 +380,7 @@ reflect(any: he) // CHECK-32-NEXT: (field name=wtable offset=20 // CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=1 bitwise_takable=1))))) // CHECK-32-NEXT: Mangled name: $s12existentials8HasErrorV +// CHECK-32-NEXT: Demangled name: existentials.HasError reflect(error: MyError()) @@ -382,6 +396,7 @@ reflect(error: MyError()) // CHECK-64-NEXT: (field name=_value offset=0 // CHECK-64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0 bitwise_takable=1))))) // CHECK-64-NEXT: Mangled name: $s12existentials7MyErrorV +// CHECK-64-NEXT: Demangled name: existentials.MyError // CHECK-32: Reflecting an error existential. // CHECK-32: Instance pointer in child address space: 0x{{[0-9a-fA-F]+}} @@ -395,5 +410,6 @@ reflect(error: MyError()) // CHECK-32-NEXT: (field name=_value offset=0 // CHECK-32-NEXT: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=0 bitwise_takable=1))))) // CHECK-32-NEXT: Mangled name: $s12existentials7MyErrorV +// CHECK-32-NEXT: Demangled name: existentials.MyError doneReflecting() diff --git a/validation-test/Reflection/existentials_objc.swift b/validation-test/Reflection/existentials_objc.swift index c805ca8365d0d..986883847f1b5 100644 --- a/validation-test/Reflection/existentials_objc.swift +++ b/validation-test/Reflection/existentials_objc.swift @@ -17,6 +17,8 @@ import Foundation import SwiftReflectionTest +class MyClass {} + if #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) { // Imported class wrapped in AnyObject @@ -33,6 +35,17 @@ if #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) { // CHECK: Type info: // CHECK: $sSo9NSCopying_Xl reflect(any: { () -> NSCopying in NSString("abc") }()) + + // Generic types involving ObjC and CF types. + // CHECK: Type info: + // CHECK: Mangled name: $s17existentials_objc7MyClassCySo8NSStringCG + // CHECK: Demangled name: existentials_objc.MyClass<__C.NSString> + reflect(any: MyClass()) + + // CHECK: Type info: + // CHECK: Mangled name: $s17existentials_objc7MyClassCySo11CFStringRefaG + // CHECK: Demangled name: existentials_objc.MyClass<__C.CFStringRef> + reflect(any: MyClass()) } else { // The Swift 5.0 libraries don't support this test. class SkipTheTest {}